3 * Copyright 1998-2000 The OpenLDAP Foundation, Redwood City, California, USA
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.
16 #include <ac/stdarg.h>
17 #include <ac/stdlib.h>
18 #include <ac/string.h>
22 #include "ldap_pvt_thread.h"
23 #include "queue-compat.h"
25 #ifndef LDAP_THREAD_HAVE_TPOOL
27 enum ldap_int_thread_pool_state {
28 LDAP_INT_THREAD_POOL_RUNNING,
29 LDAP_INT_THREAD_POOL_FINISHING,
30 LDAP_INT_THREAD_POOL_STOPPING
33 typedef struct ldap_int_thread_ctx_s {
35 STAILQ_ENTRY(ldap_int_thread_ctx_s) q;
36 SLIST_ENTRY(ldap_int_thread_ctx_s) l;
38 void *(*ltc_start_routine)( void *);
40 } ldap_int_thread_ctx_t;
42 struct ldap_int_thread_pool_s {
43 STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next;
44 ldap_pvt_thread_mutex_t ltp_mutex;
45 ldap_pvt_thread_cond_t ltp_cond;
46 STAILQ_HEAD(tcq, ldap_int_thread_ctx_s) ltp_pending_list;
47 SLIST_HEAD(tcl, ldap_int_thread_ctx_s) ltp_free_list;
51 long ltp_pending_count;
52 long ltp_active_count;
57 static STAILQ_HEAD(tpq, ldap_int_thread_pool_s)
58 ldap_int_thread_pool_list =
59 STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list);
61 static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
63 static void *ldap_int_thread_pool_wrapper(
64 struct ldap_int_thread_pool_s *pool );
67 ldap_int_thread_pool_startup ( void )
69 return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
73 ldap_int_thread_pool_shutdown ( void )
75 ldap_int_thread_ctx_t *ctx;
76 struct ldap_int_thread_pool_s *pool;
78 while ((pool = STAILQ_FIRST(&ldap_int_thread_pool_list)) != NULL) {
79 STAILQ_REMOVE_HEAD(&ldap_int_thread_pool_list, ltp_next);
80 ldap_pvt_thread_pool_destroy( &pool, 0);
82 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
87 ldap_pvt_thread_pool_init (
88 ldap_pvt_thread_pool_t *tpool,
92 ldap_pvt_thread_pool_t pool;
96 pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
97 sizeof(struct ldap_int_thread_pool_s));
99 if (pool == NULL) return(-1);
101 rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
104 rc = ldap_pvt_thread_cond_init(&pool->ltp_cond);
107 pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
108 pool->ltp_max_count = max_threads;
109 pool->ltp_max_pending = max_pending;
110 STAILQ_INIT(&pool->ltp_pending_list);
111 SLIST_INIT(&pool->ltp_free_list);
112 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
113 STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next);
114 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
117 /* THIS WILL NOT WORK on some systems. If the process
118 * forks after starting a thread, there is no guarantee
119 * that the thread will survive the fork. For example,
120 * slapd forks in order to daemonize, and does so after
121 * calling ldap_pvt_thread_pool_init. On some systems,
122 * this initial thread does not run in the child process,
123 * but ltp_open_count == 1, so two things happen:
124 * 1) the first client connection fails, and 2) when
125 * slapd is kill'ed, it never terminates since it waits
126 * for all worker threads to exit. */
128 /* start up one thread, just so there is one. no need to
129 * lock the mutex right now, since no threads are running.
131 pool->ltp_open_count++;
133 ldap_pvt_thread_t thr;
134 rc = ldap_pvt_thread_create( &thr, 1,
135 (void *) ldap_int_thread_pool_wrapper, pool );
138 /* couldn't start one? then don't start any */
139 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
140 STAILQ_REMOVE(ldap_int_thread_pool_list, pool,
141 ldap_int_thread_element_s, ltp_next);
142 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
143 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
144 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
155 ldap_pvt_thread_pool_submit (
156 ldap_pvt_thread_pool_t *tpool,
157 void *(*start_routine)( void * ), void *arg )
159 struct ldap_int_thread_pool_s *pool;
160 ldap_int_thread_ctx_t *ctx;
162 ldap_pvt_thread_t thr;
172 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
173 if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING
174 || (pool->ltp_max_pending > 0
175 && pool->ltp_pending_count >= pool->ltp_max_pending))
177 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
180 ctx = SLIST_FIRST(&pool->ltp_free_list);
182 SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l);
184 ctx = (ldap_int_thread_ctx_t *) LDAP_MALLOC(
185 sizeof(ldap_int_thread_ctx_t));
187 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
192 ctx->ltc_start_routine = start_routine;
195 pool->ltp_pending_count++;
196 STAILQ_INSERT_TAIL(&pool->ltp_pending_list, ctx, ltc_next.q);
197 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
198 if ((pool->ltp_open_count <= 0
199 || pool->ltp_pending_count > 1
200 || pool->ltp_open_count == pool->ltp_active_count)
201 && (pool->ltp_max_count <= 0
202 || pool->ltp_open_count < pool->ltp_max_count))
204 pool->ltp_open_count++;
205 pool->ltp_starting++;
208 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
211 int rc = ldap_pvt_thread_create( &thr, 1,
212 (void *)ldap_int_thread_pool_wrapper, pool );
213 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
215 pool->ltp_starting--;
217 /* couldn't create thread. back out of
218 * ltp_open_count and check for even worse things.
220 pool->ltp_open_count--;
221 pool->ltp_starting--;
222 if (pool->ltp_open_count == 0) {
223 /* no open threads at all?!?
225 ldap_int_thread_ctx_t *ptr;
226 STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltc_next.q)
227 if (ptr == ctx) break;
229 /* no open threads, context not handled, so
230 * back out of ltp_pending_count, free the context,
233 STAILQ_REMOVE(&pool->ltp_pending_list, ctx,
234 ldap_int_thread_ctx_s, ltc_next.q);
235 pool->ltp_pending_count++;
236 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
241 /* there is another open thread, so this
242 * context will be handled eventually.
243 * continue on and signal that the context
247 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
254 ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads )
256 struct ldap_int_thread_pool_s *pool;
266 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
267 pool->ltp_max_count = max_threads;
268 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
273 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool )
275 struct ldap_int_thread_pool_s *pool;
286 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
287 count = pool->ltp_pending_count + pool->ltp_active_count;
288 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
293 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
295 struct ldap_int_thread_pool_s *pool, *pptr;
297 ldap_int_thread_ctx_t *ctx;
304 if (pool == NULL) return(-1);
306 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
307 STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next)
308 if (pptr == pool) break;
310 STAILQ_REMOVE(&ldap_int_thread_pool_list, pool,
311 ldap_int_thread_pool_s, ltp_next);
312 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
314 if (pool != pptr) return(-1);
316 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
317 pool->ltp_state = run_pending
318 ? LDAP_INT_THREAD_POOL_FINISHING
319 : LDAP_INT_THREAD_POOL_STOPPING;
320 waiting = pool->ltp_open_count;
322 /* broadcast could be used here, but only after
323 * it is fixed in the NT thread implementation
325 while (--waiting >= 0) {
326 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
328 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
331 ldap_pvt_thread_yield();
332 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
333 waiting = pool->ltp_open_count;
334 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
335 } while (waiting > 0);
337 while ((ctx = STAILQ_FIRST(&pool->ltp_pending_list)) != NULL)
339 STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
343 while ((ctx = SLIST_FIRST(&pool->ltp_free_list)) != NULL)
345 SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l);
349 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
350 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
356 ldap_int_thread_pool_wrapper (
357 struct ldap_int_thread_pool_s *pool )
359 ldap_int_thread_ctx_t *ctx;
364 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
366 while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) {
367 ctx = STAILQ_FIRST(&pool->ltp_pending_list);
369 STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
371 if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING)
373 if (pool->ltp_max_count > 0
374 && pool->ltp_open_count > pool->ltp_max_count)
376 /* too many threads running (can happen if the
377 * maximum threads value is set during ongoing
378 * operation using ldap_pvt_thread_pool_maxthreads)
379 * so let this thread die.
384 /* we could check an idle timer here, and let the
385 * thread die if it has been inactive for a while.
386 * only die if there are other open threads (i.e.,
387 * always have at least one thread open). the check
388 * should be like this:
389 * if (pool->ltp_open_count > 1 && pool->ltp_starting == 0)
390 * check timer, leave thread (break;)
393 if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
394 ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
399 pool->ltp_pending_count--;
400 pool->ltp_active_count++;
401 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
403 (ctx->ltc_start_routine)(ctx->ltc_arg);
404 SLIST_INSERT_HEAD(&pool->ltp_free_list, ctx, ltc_next.l);
405 ldap_pvt_thread_yield();
407 /* if we use an idle timer, here's
408 * a good place to update it
411 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
412 pool->ltp_active_count--;
415 pool->ltp_open_count--;
416 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
418 ldap_pvt_thread_exit(NULL);
421 #endif /* LDAP_HAVE_THREAD_POOL */