python:tests: Don’t needlessly create single‐element tuple
[Samba.git] / lib / talloc / doc / tutorial_threads.dox
blob111bbf587aaf76f345953facee8419e0ca230ecb
1 /**
2 @page libtalloc_threads Chapter 8: Using threads with talloc
4 @section Talloc and thread safety
6 The talloc library is not internally thread-safe, in that accesses
7 to variables on a talloc context are not controlled by mutexes or
8 other thread-safe primitives.
10 However, so long as talloc_disable_null_tracking() is called from
11 the main thread to disable global variable access within talloc,
12 then each thread can safely use its own top level talloc context
13 allocated off the NULL context.
15 For example:
17 @code
18 static void *thread_fn(void *arg)
20         const char *ctx_name = (const char *)arg;
21         /*
22          * Create a new top level talloc hierarchy in
23          * this thread.
24          */
25         void *top_ctx = talloc_named_const(NULL, 0, "top");
26         if (top_ctx == NULL) {
27                 return NULL;
28         }
29         sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
30         if (sub_ctx == NULL) {
31                 return NULL;
32         }
34         /*
35          * Do more processing/talloc calls on top_ctx
36          * and its children.
37          */
38         ......
40         talloc_free(top_ctx);
41         return value;
43 @endcode
45 is a perfectly safe use of talloc within a thread.
47 The problem comes when one thread wishes to move some
48 memory allocated on its local top level talloc context
49 to another thread. Care must be taken to add data access
50 exclusion to prevent memory corruption. One method would
51 be to lock a mutex before any talloc call on each thread,
52 but this would push the burden of total talloc thread-safety
53 on the poor user of the library.
55 A much easier way to transfer talloced memory between
56 threads is by the use of an intermediate, mutex locked,
57 intermediate variable.
59 An example of this is below - taken from test code inside
60 the talloc testsuite.
62 The main thread creates 1000 sub-threads, and then accepts
63 the transfer of some thread-talloc'ed memory onto its top
64 level context from each thread in turn.
66 A pthread mutex and condition variable are used to
67 synchronize the transfer via the intermediate_ptr
68 variable.
70 @code
71 /* Required sync variables. */
72 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
75 /* Intermediate talloc pointer for transfer. */
76 static void *intermediate_ptr;
78 /* Subthread. */
79 static void *thread_fn(void *arg)
81         int ret;
82         const char *ctx_name = (const char *)arg;
83         void *sub_ctx = NULL;
84         /*
85          * Do stuff that creates a new talloc hierarchy in
86          * this thread.
87          */
88         void *top_ctx = talloc_named_const(NULL, 0, "top");
89         if (top_ctx == NULL) {
90                 return NULL;
91         }
92         sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
93         if (sub_ctx == NULL) {
94                 return NULL;
95         }
97         /*
98          * Now transfer a pointer from our hierarchy
99          * onto the intermediate ptr.
100          */
101         ret = pthread_mutex_lock(&mtx);
102         if (ret != 0) {
103                 talloc_free(top_ctx);
104                 return NULL;
105         }
107         /* Wait for intermediate_ptr to be free. */
108         while (intermediate_ptr != NULL) {
109                 ret = pthread_cond_wait(&condvar, &mtx);
110                 if (ret != 0) {
111                         talloc_free(top_ctx);
112                         return NULL;
113                 }
114         }
116         /* and move our memory onto it from our toplevel hierarchy. */
117         intermediate_ptr = talloc_move(NULL, &sub_ctx);
119         /* Tell the main thread it's ready for pickup. */
120         pthread_cond_broadcast(&condvar);
121         pthread_mutex_unlock(&mtx);
123         talloc_free(top_ctx);
124         return NULL;
127 /* Main thread. */
129 #define NUM_THREADS 1000
131 static bool test_pthread_talloc_passing(void)
133         int i;
134         int ret;
135         char str_array[NUM_THREADS][20];
136         pthread_t thread_id;
137         void *mem_ctx;
139         /*
140          * Important ! Null tracking breaks threaded talloc.
141          * It *must* be turned off.
142          */
143         talloc_disable_null_tracking();
145         /* Main thread toplevel context. */
146         mem_ctx = talloc_named_const(NULL, 0, "toplevel");
147         if (mem_ctx == NULL) {
148                 return false;
149         }
151         /*
152          * Spin off NUM_THREADS threads.
153          * They will use their own toplevel contexts.
154          */
155         for (i = 0; i < NUM_THREADS; i++) {
156                 (void)snprintf(str_array[i],
157                                 20,
158                                 "thread:%d",
159                                 i);
160                 if (str_array[i] == NULL) {
161                         return false;
162                 }
163                 ret = pthread_create(&thread_id,
164                                 NULL,
165                                 thread_fn,
166                                 str_array[i]);
167                 if (ret != 0) {
168                         return false;
169                 }
170         }
172         /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */
173         for (i = 0; i < NUM_THREADS; i++) {
174                 ret = pthread_mutex_lock(&mtx);
175                 if (ret != 0) {
176                         talloc_free(mem_ctx);
177                         return false;
178                 }
180                 /* Wait for intermediate_ptr to have our data. */
181                 while (intermediate_ptr == NULL) {
182                         ret = pthread_cond_wait(&condvar, &mtx);
183                         if (ret != 0) {
184                                 talloc_free(mem_ctx);
185                                 return false;
186                         }
187                 }
189                 /* and move it onto our toplevel hierarchy. */
190                 (void)talloc_move(mem_ctx, &intermediate_ptr);
192                 /* Tell the sub-threads we're ready for another. */
193                 pthread_cond_broadcast(&condvar);
194                 pthread_mutex_unlock(&mtx);
195         }
197         /* Dump the hierarchy. */
198         talloc_report(mem_ctx, stdout);
199         talloc_free(mem_ctx);
200         return true;
202 @endcode