commit d00d7dab5a31c9967e14971493e9650621e5d656 Author: David Goulet dgoulet@ev0ke.net Date: Tue Jun 18 22:14:24 2013 -0400
Add registry lock API and connection's refcount
Signed-off-by: David Goulet dgoulet@ev0ke.net --- src/common/Makefile.am | 2 +- src/common/connection.c | 47 ++++++++++++++++++++++++++++++++++++++ src/common/connection.h | 14 ++++++++++++ src/common/macros.h | 18 ++++++++++++++- src/common/ref.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 6714617..8d8e074 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -5,4 +5,4 @@ AM_CFLAGS = -fno-strict-aliasing noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = log.c log.h config-file.c config-file.h utils.c utils.h \ compat.c compat.h socks5.c socks5.h \ - connection.c connection.h ht.h + connection.c connection.h ht.h ref.h diff --git a/src/common/connection.c b/src/common/connection.c index 8ee60b9..ba1890a 100644 --- a/src/common/connection.c +++ b/src/common/connection.c @@ -22,6 +22,20 @@ #include "connection.h" #include "macros.h"
+/* Connection registry mutex. */ +static TSOCKS_INIT_MUTEX(connection_registry_mutex); + +/* + * Release connection using the given refcount located inside the connection + * object. This is ONLY called from the connection put reference. After this + * call, the connection object associated with that refcount object is freed. + */ +static void release_conn(struct ref *ref) +{ + struct connection *conn = container_of(ref, struct connection, refcount); + connection_destroy(conn); +} + /* * Return 0 if the two connections are equal else 1. */ @@ -68,6 +82,22 @@ HT_GENERATE(connection_registry, connection, node, conn_hash_fct, conn_equal_fct, 0.5, malloc, realloc, free);
/* + * Acquire connection registry mutex. + */ +void connection_registry_lock(void) +{ + tsocks_mutex_lock(&connection_registry_mutex); +} + +/* + * Release connection registry mutex. + */ +void connection_registry_unlock(void) +{ + tsocks_mutex_unlock(&connection_registry_mutex); +} + +/* * Initialize connection registry. */ void connection_registry_init(void) @@ -221,3 +251,20 @@ void connection_destroy(struct connection *conn)
free(conn); } + +/* + * Get a reference of the given connection object. + */ +void connection_get_ref(struct connection *c) +{ + ref_get(&c->refcount); +} + +/* + * Put back a reference of the given connection object. If the refcount drops + * to 0, the release connection function is called which frees the object. + */ +void connection_put_ref(struct connection *c) +{ + ref_put(&c->refcount, release_conn); +} diff --git a/src/common/connection.h b/src/common/connection.h index 058a1f6..d1163a9 100644 --- a/src/common/connection.h +++ b/src/common/connection.h @@ -24,6 +24,8 @@
#include "defaults.h" #include "ht.h" +#include "macros.h" +#include "ref.h"
enum connection_domain { CONNECTION_DOMAIN_INET = 1, @@ -52,6 +54,13 @@ struct connection { /* Remote destination that passes through Tor. */ struct connection_addr dest_addr;
+ /* + * Object refcount needed to access this object outside the registry lock. + * This is always initialized to 1 so only the destroy process can bring + * the refcount to 0 so to delete it. + */ + struct ref refcount; + /* Hash table node. */ HT_ENTRY(connection) node; }; @@ -67,5 +76,10 @@ void connection_remove(struct connection *conn); void connection_insert(struct connection *conn);
void connection_registry_init(void); +void connection_registry_lock(void); +void connection_registry_unlock(void); + +void connection_get_ref(struct connection *c); +void connection_put_ref(struct connection *c);
#endif /* TORSOCKS_CONNECTION_H */ diff --git a/src/common/macros.h b/src/common/macros.h index 5702b2e..1e98fd6 100644 --- a/src/common/macros.h +++ b/src/common/macros.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 - David Goulet dgoulet@ev0ke.net + * Copyright (c) 2009 - Mathieu Desnoyers mathieu.desnoyers@efficios.com + * 2013 - David Goulet dgoulet@ev0ke.net * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License, version 2 only, as @@ -18,6 +19,21 @@ #ifndef TORSOCKS_MACROS_H #define TORSOCKS_MACROS_H
+#include <stddef.h> /* for offsetof */ + +/* + * container_of - Get the address of an object containing a field. + * + * @ptr: pointer to the field. + * @type: type of the object. + * @member: name of the field within the object. + */ +#define container_of(ptr, type, member) \ + ({ \ + const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \ + (type *)((char *)__ptr - offsetof(type, member)); \ + }) + /* Memory allocation zeroed. */ #define zmalloc(x) calloc(1, x)
diff --git a/src/common/ref.h b/src/common/ref.h new file mode 100644 index 0000000..e1ae6d9 --- /dev/null +++ b/src/common/ref.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 - David Goulet dgoulet@ev0ke.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TORSOCKS_REF_H +#define TORSOCKS_REF_H + +struct ref { + long count; +}; + +#if (defined(__linux__) || defined(__FreeBSD__) || defined(__darwin__)) + +/* + * Get a reference by incrementing the refcount. + */ +static inline void ref_get(struct ref *r) +{ + (void) __sync_add_and_fetch(&r->count, 1); +} + +/* + * Put a reference back by decrementing the refcount. + * + * The release function MUST use container_of to get back the object pointer in + * which the ref structure is located. + */ +static inline void ref_put(struct ref *r, + void (*release)(struct ref *)) +{ + long ret; + + assert(release); + ret = __sync_sub_and_fetch(&r->count, 1); + assert(ret >= 0); + if (ret == 0) { + release(r); + } +} + +#else +#error "OS not supported" +#endif /* __linux__, __FreeBSD__, __darwin__ */ + +#endif /* TORSOCKS_REF_H */
tor-commits@lists.torproject.org