func(_n);\
return 0;\
}\
-static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+static inline _t __fr_thread_local_set_destructor_##_n(pthread_destructor_t func, void *value)\
{\
static pthread_destructor_t *ctx;\
if (!ctx) {\
talloc_set_destructor(ctx, __fr_thread_local_destructor_##_n);\
*ctx = func;\
}\
+ _n = value\
return _n;\
}
-
-# define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
-# define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
-# define fr_thread_local_get(_n) _n
+# define fr_thread_local_set_destructor(_n, _f, _v) __fr_thread_local_set_destructor_##_n(_f, _v)
#else
# include <pthread.h>
-/** Create a thread local variable with initializers/destructors
+/** Pre-initialise resources required for a thread local destructor
+ *
+ * @note If destructors are not required, just use __Thread_local.
*
* @param _t Type of variable e.g. 'char *'. Must be a pointer type.
* @param _n Name of variable e.g. 'my_tls'.
static pthread_key_t __fr_thread_local_key_##_n;\
static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
-static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
+static void __fr_thread_local_destroy_##_n(void *value)\
{\
- __fr_thread_local_destructor_##_n(_n);\
+ __fr_thread_local_destructor_##_n(value);\
}\
static void __fr_thread_local_key_init_##_n(void)\
{\
(void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
}\
-static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+static _t __fr_thread_local_set_destructor_##_n(pthread_destructor_t func, void *value)\
{\
__fr_thread_local_destructor_##_n = func;\
if (_n) return _n; \
+ if (!value) return _n; \
(void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
- (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
+ (void) pthread_setspecific(__fr_thread_local_key_##_n, value);\
+ _n = value;\
return _n;\
}
-/** If variable is NULL, call initialization function, else return the variable value
- *
- * @param _n Name of variable e.g. 'my_tls'.
- * @param _f Destructor, called when the thread exits to clean up any data.
- */
-# define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
-
-/** Set a new variable value
- *
- * @param _n Name of variable e.g. 'my_tls'.
- * @param _f Function to call for initialization.
- */
-# define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
-
-/** Get an existing variable value
+/** Set a destructor for thread local storage to free the memory on thread exit
*
- * @note In practice this is rarely used, and a call to fr_thread_local_init
- * is used to retrieve the value of the variable.
+ * @note Pointers to thread local storage seem to become unusable as threads are
+ * destroyed. So we need to store the address of the memory to free, not
+ * the address of the thread local variable.
*
* @param _n Name of variable e.g. 'my_tls'.
+ * @param _f Destructor, called when the thread exits to clean up any data.
+ * @param _v Memory to free.
*/
-# define fr_thread_local_get(_n) _n
+# define fr_thread_local_set_destructor(_n, _f, _v) __fr_thread_local_set_destructor_##_n(_f, _v)
#endif
#endif /* _FR_THREADS_H */
*/
static void _fr_logging_free(void *arg)
{
- talloc_free(arg);
+ char *buff = talloc_get_type_abort(arg, char);
+ talloc_free(buff);
}
/** Log to thread local error buffer
char *buffer;
- buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free);
+ buffer = fr_strerror_buffer;
if (!buffer) {
- int ret;
-
buffer = talloc_zero_array(NULL, char, (FR_STRERROR_BUFSIZE * 2) + 1); /* One byte extra for status */
if (!buffer) {
fr_perror("Failed allocating memory for libradius error buffer");
return;
}
-
- ret = fr_thread_local_set(fr_strerror_buffer, buffer);
- if (ret != 0) {
- fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret));
- talloc_free(buffer);
- return;
- }
+ fr_thread_local_set_destructor(fr_strerror_buffer, _fr_logging_free, buffer);
}
/*
{
char *buffer;
- buffer = fr_thread_local_get(fr_strerror_buffer);
+ buffer = fr_strerror_buffer;
if (!buffer) return "";
switch (buffer[FR_STRERROR_BUFSIZE * 2]) {
char *buffer, *p, *end;
int ret;
- buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
+ buffer = fr_syserror_buffer;
if (!buffer) {
buffer = talloc_array(NULL, char, FR_STRERROR_BUFSIZE);
if (!buffer) {
fr_perror("Failed allocating memory for system error buffer");
return NULL;
}
-
- ret = fr_thread_local_set(fr_syserror_buffer, buffer);
- if (ret != 0) {
- fr_perror("Failed setting up TLS for system error buffer: %s", fr_syserror(ret));
- talloc_free(buffer);
- return NULL;
- }
+ fr_thread_local_set_destructor(fr_syserror_buffer, _fr_logging_free, buffer);
}
if (!num) return "No error";
void *module_thread_instance_find(void *instance)
{
module_instance_t *inst = instance;
- rbtree_t *tree = fr_thread_local_get(module_thread_inst_tree);
+ rbtree_t *tree = module_thread_inst_tree;
module_thread_instance_t find, *found;
if (!inst->module->thread_instantiate || !inst->module->thread_inst_size) return NULL;
/** Destructor for module_thread_instance_t
*
+ * @note This cannot be converted to a talloc destructor,
+ * as we need to call thread_detach *before* any of the children
+ * of the talloc ctx are freed.
*/
-static int _module_thread_instance_free(void *thread_inst_data)
+static void _module_thread_instance_free(void *to_free)
{
- module_thread_instance_t *thread_inst = talloc_parent(thread_inst_data);
+ module_thread_instance_t *thread_inst = talloc_get_type_abort(to_free, module_thread_instance_t);
if (thread_inst->inst->module->thread_detach) {
(void) thread_inst->inst->module->thread_detach(thread_inst->data);
}
- return 0;
+ talloc_free(thread_inst);
}
/** Frees the thread local instance free and any thread local instance data
*/
static void _module_thread_inst_tree_free(void *to_free)
{
- rbtree_t *thread_inst_tree = talloc_get_type_abort(to_free, rbtree_t);
+ rbtree_t *thread_inst_tree = talloc_get_type_abort(to_free , rbtree_t);
+
rbtree_free(thread_inst_tree);
}
talloc_set_name(thread_inst->data, "%s", type_name);
talloc_free(type_name);
- talloc_set_destructor(thread_inst->data, _module_thread_instance_free);
rbtree_insert(thread_inst_ctx->tree, thread_inst);
}
modules = cf_section_sub_find(root, "modules");
if (!modules) return 0;
- thread_inst_tree = fr_thread_local_init(module_thread_inst_tree, _module_thread_inst_tree_free);
+ thread_inst_tree = module_thread_inst_tree;
if (!thread_inst_tree) {
- MEM(thread_inst_tree = module_thread_inst_tree = rbtree_create(NULL, _module_thread_inst_tree_cmp,
- rbtree_node_talloc_free, 0));
+ MEM(thread_inst_tree = rbtree_create(NULL, _module_thread_inst_tree_cmp,
+ _module_thread_instance_free, 0));
+ fr_thread_local_set_destructor(module_thread_inst_tree,
+ _module_thread_inst_tree_free, thread_inst_tree);
}
ctx.el = el;
if (!rad_cond_assert(inst)) return NULL;
- buffer = fr_thread_local_init(krb5_error_buffer, _krb5_logging_free);
+ buffer = krb5_error_buffer;
if (!buffer) {
- int ret;
-
buffer = talloc_array(NULL, char, KRB5_STRERROR_BUFSIZE);
if (!buffer) {
ERROR("Failed allocating memory for krb5 error buffer");
return NULL;
}
- ret = fr_thread_local_set(krb5_error_buffer, buffer);
- if (ret != 0) {
- ERROR("Failed setting up TLS for krb5 error buffer: %s", fr_syserror(ret));
- talloc_free(buffer);
- return NULL;
- }
+ fr_thread_local_set_destructor(krb5_error_buffer, _krb5_logging_free, buffer);
}
msg = krb5_get_error_message(context, code);
* Check to see if we've got a thread state tree
* If not, create one.
*/
- thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
+ thread_tree = local_thread_state;
if (!thread_tree) {
thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
if (!thread_tree) {
RERROR("Failed allocating thread state tree");
return RLM_MODULE_FAIL;
}
-
- ret = fr_thread_local_set(local_thread_state, thread_tree);
- if (ret != 0) {
- talloc_free(thread_tree);
- return RLM_MODULE_FAIL;
- }
+ fr_thread_local_set_destructor(local_thread_state, _python_thread_tree_free, thread_tree);
}
find.inst = inst;
* Retrieve the thread specific pipe we use
* to communicate with the multiplexer.
*/
- fd_ptr = fr_thread_local_init(req_pipe, _req_pipe_unregister);
+ fd_ptr = req_pipe;
if (!fd_ptr) {
fd_ptr = talloc(NULL, int);
fd = sigtran_client_thread_register();
return RLM_MODULE_FAIL;
}
*fd_ptr = fd;
- fr_thread_local_set(req_pipe, fd_ptr);
+ fr_thread_local_set_destructor(req_pipe, _req_pipe_unregister, fd_ptr);
} else {
fd = *fd_ptr;
}