]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/threads.c
80a11cfa2c877b2730fe6271989fd1b9b909e342
[openldap] / libraries / libldap_r / threads.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, Redwood City, California, USA
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted only
7  * as authorized by the OpenLDAP Public License.  A copy of this
8  * license is available at http://www.OpenLDAP.org/license.html or
9  * in file LICENSE in the top-level directory of the distribution.
10  */
11
12 #include "portable.h"
13
14 #include <stdio.h>
15 #include <stdarg.h>
16
17 #include <ac/stdlib.h>
18 #include <ac/string.h>
19
20 #include "ldap_int_thread.h"
21 #include "ldap_pvt_thread.h"
22
23 enum {
24         LDAP_PVT_THREAD_POOL_RUNNING,
25         LDAP_PVT_THREAD_POOL_FINISHING,
26         LDAP_PVT_THREAD_POOL_STOPPING
27 };
28
29 typedef struct t_ldap_pvt_thread_listelement {
30         struct t_ldap_pvt_thread_listelement *next;
31 } ldap_pvt_thread_listelement, *ldap_pvt_thread_list;
32
33 struct t_ldap_pvt_thread_pool {
34         struct t_ldap_pvt_thread_pool *ltp_next;
35         ldap_pvt_thread_mutex_t ltp_mutex;
36         ldap_pvt_thread_cond_t ltp_cond;
37         ldap_pvt_thread_list ltp_pending_list;
38         long ltp_state;
39         long ltp_max_count;
40         long ltp_max_pending;
41         long ltp_pending_count;
42         long ltp_active_count;
43         long ltp_open_count;
44 };
45
46 typedef struct t_ldap_pvt_thread_ctx {
47         struct t_ldap_pvt_thread_ctx *ltc_next;
48         void *(*ltc_start_routine)( void *);
49         void *ltc_arg;
50 } ldap_pvt_thread_ctx;
51
52 ldap_pvt_thread_list ldap_pvt_thread_pool_list = NULL;
53 ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
54
55 void *ldap_pvt_thread_pool_wrapper( ldap_pvt_thread_pool_t pool );
56 void *ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem );
57 void *ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem );
58 void *ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem );
59
60
61 int
62 ldap_pvt_thread_initialize ( void )
63 {
64         int rc;
65
66         rc = ldap_int_thread_initialize();
67         if (rc == 0) {
68                 /* init the mutex that protext the list of pools
69                  */
70                 ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
71         }
72         return rc;
73 }
74
75 int
76 ldap_pvt_thread_destroy ( void )
77 {
78         while (ldap_pvt_thread_pool_list != NULL) {
79                 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
80         }
81         ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
82
83         return ldap_int_thread_destroy();
84 }
85
86 int
87 ldap_pvt_thread_get_concurrency ( void )
88 {
89 #ifdef HAVE_GETCONCURRENCY
90         return ldap_int_thread_get_concurrency();
91 #else
92         return 1;
93 #endif
94 }
95
96 int
97 ldap_pvt_thread_set_concurrency ( int concurrency )
98 {
99 #ifdef HAVE_SETCONCURRENCY
100         return ldap_int_thread_set_concurrency(concurrency);
101 #else
102         return 1;
103 #endif
104 }
105
106 int 
107 ldap_pvt_thread_create (
108         ldap_pvt_thread_t * thread, 
109         int     detach,
110         void *(*start_routine)( void * ), 
111         void *arg)
112 {
113         return ldap_int_thread_create(thread, detach, start_routine, arg);
114 }
115
116 void
117 ldap_pvt_thread_exit ( void *retval )
118 {
119         ldap_int_thread_exit(retval);
120 }
121
122 int
123 ldap_pvt_thread_join ( ldap_pvt_thread_t thread, void **status )
124 {
125         return ldap_int_thread_join(thread, status);
126 }
127
128 int
129 ldap_pvt_thread_kill ( ldap_pvt_thread_t thread, int signo )
130 {
131         return ldap_int_thread_kill(thread, signo);
132 }
133
134 int
135 ldap_pvt_thread_yield ( void )
136 {
137         return ldap_int_thread_yield();
138 }
139
140 int
141 ldap_pvt_thread_cond_init ( ldap_pvt_thread_cond_t *cond )
142 {
143         return ldap_int_thread_cond_init(cond);
144 }
145
146 int
147 ldap_pvt_thread_cond_destroy ( ldap_pvt_thread_cond_t *cond )
148 {
149         return ldap_int_thread_cond_destroy(cond);
150 }
151
152 int
153 ldap_pvt_thread_cond_signal ( ldap_pvt_thread_cond_t *cond )
154 {
155         return ldap_int_thread_cond_signal(cond);
156 }
157
158 int
159 ldap_pvt_thread_cond_broadcast ( ldap_pvt_thread_cond_t *cond )
160 {
161         return ldap_int_thread_cond_broadcast(cond);
162 }
163
164 int
165 ldap_pvt_thread_cond_wait (
166         ldap_pvt_thread_cond_t *cond, 
167         ldap_pvt_thread_mutex_t *mutex )
168 {
169         return ldap_int_thread_cond_wait(cond, mutex);
170 }
171
172 int
173 ldap_pvt_thread_mutex_init ( ldap_pvt_thread_mutex_t *mutex )
174 {
175         return ldap_int_thread_mutex_init(mutex);
176 }
177
178 int
179 ldap_pvt_thread_mutex_destroy ( ldap_pvt_thread_mutex_t *mutex )
180 {
181         return ldap_int_thread_mutex_destroy(mutex);
182 }
183
184 int
185 ldap_pvt_thread_mutex_lock ( ldap_pvt_thread_mutex_t *mutex )
186 {
187         return ldap_int_thread_mutex_lock(mutex);
188 }
189
190 int
191 ldap_pvt_thread_mutex_trylock ( ldap_pvt_thread_mutex_t *mutex )
192 {
193         return ldap_int_thread_mutex_trylock(mutex);
194 }
195
196 int
197 ldap_pvt_thread_mutex_unlock ( ldap_pvt_thread_mutex_t *mutex )
198 {
199         return ldap_int_thread_mutex_unlock(mutex);
200 }
201
202 #ifdef NO_THREADS
203
204 /* There must be a separate implementation when NO_THREADS is on.
205  * Since ldap_pvt_thread_pool_wrapper loops, there's no way to
206  * simply let the underlying (stub) thread implementation take
207  * care of things (unless there was an #ifdef that removed the
208  * "while" in ldap_pvt_thread_pool_wrapper, but why do all the
209  * extra work of init/submit/destroy when all that's needed
210  * are these stubs?)
211  */
212 int
213 ldap_pvt_thread_pool_startup ( void )
214 {
215         return(0);
216 }
217
218 int
219 ldap_pvt_thread_pool_shutdown ( void )
220 {
221         return(0);
222 }
223
224 int
225 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
226 {
227         *pool_out = NULL;
228         return(0);
229 }
230
231 int
232 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
233 {
234         (start_routine)(arg);
235         return(0);
236 }
237
238 int
239 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
240 {
241         return(0);
242 }
243
244 int
245 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
246 {
247         return(0);
248 }
249
250 #else
251
252 int
253 ldap_pvt_thread_pool_startup ( void )
254 {
255         return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
256 }
257
258 int
259 ldap_pvt_thread_pool_shutdown ( void )
260 {
261         while (ldap_pvt_thread_pool_list != NULL) {
262                 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
263         }
264         ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
265         return(0);
266 }
267
268 int
269 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
270 {
271         ldap_pvt_thread_pool_t pool;
272         ldap_pvt_thread_t thr;
273
274         *pool_out = NULL;
275         pool = (ldap_pvt_thread_pool_t)calloc(1, sizeof(struct t_ldap_pvt_thread_pool));
276         if (pool == NULL)
277                 return(-1);
278
279         ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
280         ldap_pvt_thread_cond_init(&pool->ltp_cond);
281         pool->ltp_state = LDAP_PVT_THREAD_POOL_RUNNING;
282         pool->ltp_max_count = max_concurrency;
283         pool->ltp_max_pending = max_pending;
284         ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
285         ldap_pvt_thread_enlist(&ldap_pvt_thread_pool_list, pool);
286         ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
287
288         /* start up one thread, just so there is one */
289         pool->ltp_open_count++;
290         if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
291                 /* couldn't start one?  then don't start any */
292                 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
293                 ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
294                 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
295                 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
296                 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
297                 free(pool);
298                 return(-1);
299         }
300
301         *pool_out = pool;
302         return(0);
303 }
304
305 int
306 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
307 {
308         ldap_pvt_thread_ctx *ctx;
309         int need_thread = 0;
310         ldap_pvt_thread_t thr;
311
312         if (pool == NULL)
313                 return(-1);
314
315         ctx = (ldap_pvt_thread_ctx *)calloc(1, sizeof(ldap_pvt_thread_ctx));
316         if (ctx == NULL)
317                 return(-1);
318
319         ctx->ltc_start_routine = start_routine;
320         ctx->ltc_arg = arg;
321
322         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
323         if (pool->ltp_state != LDAP_PVT_THREAD_POOL_RUNNING
324                 || (pool->ltp_max_pending > 0 && pool->ltp_pending_count >= pool->ltp_max_pending))
325         {
326                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
327                 free(ctx);
328                 return(-1);
329         }
330         pool->ltp_pending_count++;
331         ldap_pvt_thread_enlist(&pool->ltp_pending_list, ctx);
332         ldap_pvt_thread_cond_signal(&pool->ltp_cond);
333         if ((pool->ltp_open_count <= 0
334                         || pool->ltp_pending_count > 1
335                         || pool->ltp_open_count == pool->ltp_active_count)
336                 && (pool->ltp_max_count <= 0
337                         || pool->ltp_open_count < pool->ltp_max_count))
338         {
339                 pool->ltp_open_count++;
340                 need_thread = 1;
341         }
342         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
343
344         if (need_thread) {
345                 if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
346                         /* couldn't create thread.  back out of
347                          * ltp_open_count and check for even worse things.
348                          */
349                         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
350                         pool->ltp_open_count--;
351                         if (pool->ltp_open_count == 0) {
352                                 /* no open threads at all?!?  this will never happen
353                                  * because we always leave at least one thread open.
354                                  */
355                                 if (ldap_pvt_thread_delist(&pool->ltp_pending_list, ctx)) {
356                                         /* no open threads, context not handled, so
357                                          * back out of ltp_pending_count, free the context,
358                                          * report the error.
359                                          */
360                                         pool->ltp_pending_count++;
361                                         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
362                                         free(ctx);
363                                         return(-1);
364                                 }
365                         }
366                         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
367                         /* there is another open thread, so this
368                          * context will be handled eventually.
369                          * continue on and signal that the context
370                          * is waiting.
371                          */
372                 }
373         }
374
375         return(0);
376 }
377
378 int
379 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
380 {
381         int count;
382
383         if (pool == NULL)
384                 return(0);
385
386         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
387         count = pool->ltp_pending_count + pool->ltp_active_count;
388         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
389         return(count);
390 }
391
392 int
393 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
394 {
395         long waiting;
396         ldap_pvt_thread_ctx *ctx;
397
398         if (pool == NULL)
399                 return(-1);
400
401         ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
402         pool = ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
403         ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
404
405         if (pool == NULL)
406                 return(-1);
407
408         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
409         if (run_pending)
410                 pool->ltp_state = LDAP_PVT_THREAD_POOL_FINISHING;
411         else
412                 pool->ltp_state = LDAP_PVT_THREAD_POOL_STOPPING;
413         waiting = pool->ltp_open_count;
414         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
415
416         /* broadcast could be used here, but only after
417          * it is fixed in the NT thread implementation
418          */
419         while (--waiting >= 0)
420                 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
421         do {
422                 ldap_pvt_thread_yield();
423                 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
424                 waiting = pool->ltp_open_count;
425                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
426         } while (waiting > 0);
427
428         while (ctx = (ldap_pvt_thread_ctx *)ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL))
429                 free(ctx);
430
431         ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
432         ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
433         free(pool);
434         return(0);
435 }
436
437 void *
438 ldap_pvt_thread_pool_wrapper ( ldap_pvt_thread_pool_t pool )
439 {
440         ldap_pvt_thread_ctx *ctx;
441
442         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
443
444         while (pool->ltp_state != LDAP_PVT_THREAD_POOL_STOPPING) {
445
446                 ctx = ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL);
447                 if (ctx == NULL) {
448                         if (pool->ltp_state == LDAP_PVT_THREAD_POOL_FINISHING)
449                                 break;
450                         /* we could check an idle timer here, and let the
451                          * thread die if it has been inactive for a while.
452                          * only die if there are other open threads (i.e.,
453                          * always have at least one thread open).
454                          */
455                         if (pool->ltp_state == LDAP_PVT_THREAD_POOL_RUNNING)
456                                 ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
457
458                         continue;
459                 }
460
461                 pool->ltp_pending_count--;
462                 pool->ltp_active_count++;
463                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
464
465                 (ctx->ltc_start_routine)(ctx->ltc_arg);
466                 free(ctx);
467
468                 /* if we use an idle timer, here's
469                  * a good place to update it
470                  */
471
472                 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
473                 pool->ltp_active_count--;
474         }
475
476         pool->ltp_open_count--;
477         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
478
479         ldap_pvt_thread_exit(NULL);
480         return(NULL);
481 }
482
483 void *
484 ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem )
485 {
486         ldap_pvt_thread_listelement *prev;
487
488         if (elem == NULL)
489                 return(NULL);
490
491         ((ldap_pvt_thread_listelement *)elem)->next = NULL;
492         if (*list == NULL) {
493                 *list = elem;
494                 return(elem);
495         }
496
497         for (prev = *list ; prev->next != NULL; prev = prev->next) ;
498         prev->next = elem;
499         return(elem);
500 }
501
502 void *
503 ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem )
504 {
505         ldap_pvt_thread_listelement *prev;
506
507         if (*list == NULL)
508                 return(NULL);
509
510         if (elem == NULL)
511                 elem = *list;
512
513         if (*list == elem) {
514                 *list = ((ldap_pvt_thread_listelement *)elem)->next;
515                 return(elem);
516         }
517
518         for (prev = *list ; prev->next != NULL; prev = prev->next) {
519                 if (prev->next == elem) {
520                         prev->next = ((ldap_pvt_thread_listelement *)elem)->next;
521                         return(elem);
522                 }
523         }
524         return(NULL);
525 }
526
527 void *
528 ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem )
529 {
530         ldap_pvt_thread_listelement *prev;
531
532         if (elem == NULL || *list == NULL)
533                 return(NULL);
534
535         for (prev = *list ; prev != NULL; prev = prev->next) {
536                 if (prev == elem)
537                         return(elem);
538         }
539
540         return(NULL);
541 }
542
543 #endif  /* NO_THREADS */