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.
17 #include <ac/stdlib.h>
18 #include <ac/string.h>
22 #include "ldap_pvt_thread.h"
24 #ifndef LDAP_THREAD_HAVE_TPOOL
26 enum ldap_int_thread_pool_state {
27 LDAP_INT_THREAD_POOL_RUNNING,
28 LDAP_INT_THREAD_POOL_FINISHING,
29 LDAP_INT_THREAD_POOL_STOPPING
32 typedef struct ldap_int_thread_list_element_s {
33 struct ldap_int_thread_list_element_s *next;
34 } ldap_int_thread_list_element_t, *ldap_int_thread_list_t;
36 struct ldap_int_thread_pool_s {
37 struct ldap_int_thread_pool_s *ltp_next;
38 ldap_pvt_thread_mutex_t ltp_mutex;
39 ldap_pvt_thread_cond_t ltp_cond;
40 ldap_int_thread_list_t ltp_pending_list;
44 long ltp_pending_count;
45 long ltp_active_count;
49 typedef struct ldap_int_thread_ctx_s {
50 struct ldap_int_thread_ctx_s *ltc_next;
51 void *(*ltc_start_routine)( void *);
53 } ldap_int_thread_ctx_t;
55 static ldap_int_thread_list_t ldap_int_thread_pool_list = NULL;
56 static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
58 static void *ldap_int_thread_pool_wrapper(
59 struct ldap_int_thread_pool_s *pool );
61 static void *ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem );
62 static void *ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem );
63 static void *ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem );
66 ldap_int_thread_pool_startup ( void )
68 return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
72 ldap_int_thread_pool_shutdown ( void )
74 while (ldap_int_thread_pool_list != NULL) {
75 struct ldap_int_thread_pool_s *pool =
76 (struct ldap_int_thread_pool_s *) ldap_int_thread_pool_list;
78 ldap_pvt_thread_pool_destroy( &pool, 0);
80 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
85 ldap_pvt_thread_pool_init (
86 ldap_pvt_thread_pool_t *tpool,
91 ldap_pvt_thread_pool_t pool;
92 ldap_pvt_thread_t thr;
95 pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
96 sizeof(struct ldap_int_thread_pool_s));
98 if (pool == NULL) return(-1);
100 ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
101 ldap_pvt_thread_cond_init(&pool->ltp_cond);
102 pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
103 pool->ltp_max_count = max_concurrency;
104 pool->ltp_max_pending = max_pending;
105 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
106 ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool);
107 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
109 /* start up one thread, just so there is one */
110 pool->ltp_open_count++;
112 rc = ldap_pvt_thread_create( &thr, 1,
113 (void *) ldap_int_thread_pool_wrapper, pool );
116 /* couldn't start one? then don't start any */
117 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
118 ldap_int_thread_delist(&ldap_int_thread_pool_list, pool);
119 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
120 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
121 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
131 ldap_pvt_thread_pool_submit (
132 ldap_pvt_thread_pool_t *tpool,
133 void *(*start_routine)( void * ), void *arg )
135 struct ldap_int_thread_pool_s *pool;
136 ldap_int_thread_ctx_t *ctx;
138 ldap_pvt_thread_t thr;
148 ctx = (ldap_int_thread_ctx_t *) LDAP_CALLOC(1,
149 sizeof(ldap_int_thread_ctx_t));
151 if (ctx == NULL) return(-1);
153 ctx->ltc_start_routine = start_routine;
156 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
157 if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING
158 || (pool->ltp_max_pending > 0
159 && pool->ltp_pending_count >= pool->ltp_max_pending))
161 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
165 pool->ltp_pending_count++;
166 ldap_int_thread_enlist(&pool->ltp_pending_list, ctx);
167 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
168 if ((pool->ltp_open_count <= 0
169 || pool->ltp_pending_count > 1
170 || pool->ltp_open_count == pool->ltp_active_count)
171 && (pool->ltp_max_count <= 0
172 || pool->ltp_open_count < pool->ltp_max_count))
174 pool->ltp_open_count++;
177 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
180 int rc = ldap_pvt_thread_create( &thr, 1,
181 (void *)ldap_int_thread_pool_wrapper, pool );
183 /* couldn't create thread. back out of
184 * ltp_open_count and check for even worse things.
186 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
187 pool->ltp_open_count--;
188 if (pool->ltp_open_count == 0) {
189 /* no open threads at all?!? this will never happen
190 * because we always leave at least one thread open.
192 if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) {
193 /* no open threads, context not handled, so
194 * back out of ltp_pending_count, free the context,
197 pool->ltp_pending_count++;
198 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
203 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
204 /* there is another open thread, so this
205 * context will be handled eventually.
206 * continue on and signal that the context
216 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool )
218 struct ldap_int_thread_pool_s *pool;
229 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
230 count = pool->ltp_pending_count + pool->ltp_active_count;
231 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
236 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
238 struct ldap_int_thread_pool_s *pool;
240 ldap_int_thread_ctx_t *ctx;
247 if (pool == NULL) return(-1);
249 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
250 pool = ldap_int_thread_delist(&ldap_int_thread_pool_list, pool);
251 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
253 if (pool == NULL) return(-1);
255 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
256 pool->ltp_state = run_pending
257 ? LDAP_INT_THREAD_POOL_FINISHING
258 : LDAP_INT_THREAD_POOL_STOPPING;
259 waiting = pool->ltp_open_count;
260 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
262 /* broadcast could be used here, but only after
263 * it is fixed in the NT thread implementation
265 while (--waiting >= 0) {
266 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
270 ldap_pvt_thread_yield();
271 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
272 waiting = pool->ltp_open_count;
273 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
274 } while (waiting > 0);
276 while (ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist(
277 &pool->ltp_pending_list, NULL))
282 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
283 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
289 ldap_int_thread_pool_wrapper (
290 struct ldap_int_thread_pool_s *pool )
292 ldap_int_thread_ctx_t *ctx;
297 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
299 while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) {
301 ctx = ldap_int_thread_delist(&pool->ltp_pending_list, NULL);
303 if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING)
305 /* we could check an idle timer here, and let the
306 * thread die if it has been inactive for a while.
307 * only die if there are other open threads (i.e.,
308 * always have at least one thread open).
311 if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
312 ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
317 pool->ltp_pending_count--;
318 pool->ltp_active_count++;
319 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
321 (ctx->ltc_start_routine)(ctx->ltc_arg);
323 ldap_pvt_thread_yield();
325 /* if we use an idle timer, here's
326 * a good place to update it
329 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
330 pool->ltp_active_count--;
333 pool->ltp_open_count--;
334 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
336 ldap_pvt_thread_exit(NULL);
341 ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem )
343 ldap_int_thread_list_element_t *prev;
345 if (elem == NULL) return(NULL);
347 ((ldap_int_thread_list_element_t *)elem)->next = NULL;
353 for (prev = *list ; prev->next != NULL; prev = prev->next) ;
359 ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem )
361 ldap_int_thread_list_element_t *prev;
363 if (*list == NULL) return(NULL);
365 if (elem == NULL) elem = *list;
368 *list = ((ldap_int_thread_list_element_t *)elem)->next;
372 for (prev = *list ; prev->next != NULL; prev = prev->next) {
373 if (prev->next == elem) {
374 prev->next = ((ldap_int_thread_list_element_t *)elem)->next;
382 ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem )
384 ldap_int_thread_list_element_t *prev;
386 if (elem == NULL || *list == NULL) return(NULL);
388 for (prev = *list ; prev != NULL; prev = prev->next) {
396 #endif /* LDAP_HAVE_THREAD_POOL */