Make talloc_stack threadsafe using TLS. Volker please
authorJeremy Allison <jra@samba.org>
Tue, 14 Apr 2009 19:23:22 +0000 (12:23 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 14 Apr 2009 19:23:22 +0000 (12:23 -0700)
check. Passes make test and basic valgrind testing.
Jeremy.

lib/util/config.mk
lib/util/smb_threads.c
lib/util/smb_threads_internal.h
lib/util/talloc_stack.c

index 7835fed911869a5aced8c922e4e0ccf25ad3da87..1b620d1464c6a0018c8fc333e9c1ef89e639b8ba 100644 (file)
@@ -27,6 +27,7 @@ LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
                become_daemon.o \
                rbtree.o \
                talloc_stack.o \
+               smb_threads.o \
                params.o)
 
 PUBLIC_HEADERS += $(addprefix $(libutilsrcdir)/, util.h \
index 84dec4d874aa021879021b232e3c8eea23570356..8e0e1cd9157d627a91f9a61f217b2f452ac2f2ad 100644 (file)
@@ -50,8 +50,19 @@ int smb_thread_set_functions(const struct smb_thread_functions *tf)
 
        global_tfp = tf;
 
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+#endif
+
        /* Here we initialize any static locks we're using. */
-       global_lock_array = (void **)SMB_MALLOC_ARRAY(void *, NUM_GLOBAL_LOCKS);
+       global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS);
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
        if (global_lock_array == NULL) {
                return ENOMEM;
        }
@@ -62,9 +73,11 @@ int smb_thread_set_functions(const struct smb_thread_functions *tf)
                        SAFE_FREE(global_lock_array);
                        return ENOMEM;
                }
-               global_tfp->create_mutex(name,
+               if (global_tfp->create_mutex(name,
                                &global_lock_array[i],
-                               __location__);
+                               __location__)) {
+                       smb_panic("smb_thread_set_functions: create mutexes failed");
+               }
                SAFE_FREE(name);
        }
 
index 3208bc27e13a371b46fb9892bac88f60e70ab8df..ad05aae9a5e2291edf05ff2d846b0d2def758cd5 100644 (file)
        } while (0)
 
 #define SMB_THREAD_SET_TLS(key, val) \
-       (global_tfp ? global_tfp->set_tls((key),(val),__location__) : 0)
+       (global_tfp ? global_tfp->set_tls((key),(val),__location__) : \
+               ((key) = (val), 0))
 
 #define SMB_THREAD_GET_TLS(key) \
-       (global_tfp ? global_tfp->get_tls((key), __location__) : NULL)
+       (global_tfp ? global_tfp->get_tls((key), __location__) : (key))
 
 #endif
index 2f3ea11377fb2ffb4c324d3e32e597bac4647f33..a9b6e033cebe416367cdbf22a5fc0b7a1f9997b0 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    Implement a stack of talloc contexts
    Copyright (C) Volker Lendecke 2007
+   Copyright (C) Jeremy Allison 2009 - made thread safe.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include "includes.h"
 
-static int talloc_stacksize;
-static int talloc_stack_arraysize;
-static TALLOC_CTX **talloc_stack;
+struct talloc_stackframe {
+       int talloc_stacksize;
+       int talloc_stack_arraysize;
+       TALLOC_CTX **talloc_stack;
+};
+
+/*
+ * In the single threaded case this is a pointer
+ * to the global talloc_stackframe. In the MT-case
+ * this is the pointer to the thread-specific key
+ * used to look up the per-thread talloc_stackframe
+ * pointer.
+ */
+
+static void *global_ts;
+
+static struct talloc_stackframe *talloc_stackframe_init(void)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+#endif
+       struct talloc_stackframe *ts =
+               (struct talloc_stackframe *)malloc(sizeof(struct talloc_stackframe));
+#if defined(PARANOID_MALLOC_CHECKER)
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
+       if (!ts) {
+               smb_panic("talloc_stackframe_init malloc failed");
+       }
+
+       ZERO_STRUCTP(ts);
+
+       if (SMB_THREAD_CREATE_TLS("talloc_stackframe", global_ts)) {
+               smb_panic("talloc_stackframe_init create_tls failed");
+       }
+
+       if (SMB_THREAD_SET_TLS(global_ts, ts)) {
+               smb_panic("talloc_stackframe_init set_tls failed");
+       }
+       return ts;
+}
 
 static int talloc_pop(TALLOC_CTX *frame)
 {
+       struct talloc_stackframe *ts =
+               (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
        int i;
 
-       for (i=talloc_stacksize-1; i>0; i--) {
-               if (frame == talloc_stack[i]) {
+       for (i=ts->talloc_stacksize-1; i>0; i--) {
+               if (frame == ts->talloc_stack[i]) {
                        break;
                }
-               talloc_free(talloc_stack[i]);
+               talloc_free(ts->talloc_stack[i]);
        }
 
-       talloc_stacksize = i;
+       ts->talloc_stacksize = i;
        return 0;
 }
 
@@ -67,22 +111,27 @@ static int talloc_pop(TALLOC_CTX *frame)
 static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
 {
        TALLOC_CTX **tmp, *top, *parent;
+       struct talloc_stackframe *ts =
+               (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
 
-       if (talloc_stack_arraysize < talloc_stacksize + 1) {
-               tmp = talloc_realloc(NULL, talloc_stack, TALLOC_CTX *,
-                                          talloc_stacksize + 1);
+       if (ts == NULL) {
+               ts = talloc_stackframe_init();
+       }
+
+       if (ts->talloc_stack_arraysize < ts->talloc_stacksize + 1) {
+               tmp = talloc_realloc(NULL, ts->talloc_stack, TALLOC_CTX *,
+                                          ts->talloc_stacksize + 1);
                if (tmp == NULL) {
                        goto fail;
                }
-               talloc_stack = tmp;
-               talloc_stack_arraysize = talloc_stacksize + 1;
+               ts->talloc_stack = tmp;
+               ts->talloc_stack_arraysize = ts->talloc_stacksize + 1;
         }
 
-       if (talloc_stacksize == 0) {
-               parent = talloc_stack;
-       }
-       else {
-               parent = talloc_stack[talloc_stacksize-1];
+       if (ts->talloc_stacksize == 0) {
+               parent = ts->talloc_stack;
+       } else {
+               parent = ts->talloc_stack[ts->talloc_stacksize-1];
        }
 
        if (poolsize) {
@@ -97,7 +146,7 @@ static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
 
        talloc_set_destructor(top, talloc_pop);
 
-       talloc_stack[talloc_stacksize++] = top;
+       ts->talloc_stack[ts->talloc_stacksize++] = top;
        return top;
 
  fail:
@@ -121,10 +170,14 @@ TALLOC_CTX *talloc_stackframe_pool(size_t poolsize)
 
 TALLOC_CTX *talloc_tos(void)
 {
-       if (talloc_stacksize == 0) {
+       struct talloc_stackframe *ts =
+               (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+       if (ts == NULL) {
                talloc_stackframe();
+               ts = (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
                DEBUG(0, ("no talloc stackframe around, leaking memory\n"));
        }
 
-       return talloc_stack[talloc_stacksize-1];
+       return ts->talloc_stack[ts->talloc_stacksize-1];
 }