]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap_r/tpool.c
tpool cleanup
[openldap] / libraries / libldap_r / tpool.c
index f64c3009e0f5b87441eb012208661080ceda825d..c682930aa6d06c8de11f9c127f9247d73c070441 100644 (file)
@@ -1,12 +1,16 @@
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, Redwood City, California, USA
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2006 The OpenLDAP Foundation.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted only
- * as authorized by the OpenLDAP Public License.  A copy of this
- * license is available at http://www.OpenLDAP.org/license.html or
- * in file LICENSE in the top-level directory of the distribution.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
  */
 
 #include "portable.h"
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/time.h>
+#include <ac/errno.h>
 
 #include "ldap-int.h"
-#include "ldap_pvt_thread.h"
-#include "queue-compat.h"
+#include "ldap_pvt_thread.h" /* Get the thread interface */
+#include "ldap_queue.h"
+#define LDAP_THREAD_POOL_IMPLEMENTATION
+#include "ldap_thr_debug.h"  /* May rename symbols defined below */
 
 #ifndef LDAP_THREAD_HAVE_TPOOL
 
-enum ldap_int_thread_pool_state {
+typedef enum ldap_int_thread_pool_state_e {
        LDAP_INT_THREAD_POOL_RUNNING,
        LDAP_INT_THREAD_POOL_FINISHING,
-       LDAP_INT_THREAD_POOL_STOPPING
-};
+       LDAP_INT_THREAD_POOL_STOPPING,
+       LDAP_INT_THREAD_POOL_PAUSING
+} ldap_int_thread_pool_state_t;
+
+typedef struct ldap_int_thread_key_s {
+       void *ltk_key;
+       void *ltk_data;
+       ldap_pvt_thread_pool_keyfree_t *ltk_free;
+} ldap_int_thread_key_t;
+
+/* Max number of thread-specific keys we store per thread.
+ * We don't expect to use many...
+ */
+#define        MAXKEYS 32
+#define        LDAP_MAXTHR     1024    /* must be a power of 2 */
+
+static ldap_pvt_thread_t tid_zero;
+
+static struct {
+       ldap_pvt_thread_t id;
+       ldap_int_thread_key_t *ctx;
+} thread_keys[LDAP_MAXTHR];
+       
 
 typedef struct ldap_int_thread_ctx_s {
        union {
-       SLIST_ENTRY(ldap_int_thread_ctx_s) l;
-       STAILQ_ENTRY(ldap_int_thread_ctx_s) q;
+       LDAP_STAILQ_ENTRY(ldap_int_thread_ctx_s) q;
+       LDAP_SLIST_ENTRY(ldap_int_thread_ctx_s) l;
+       LDAP_SLIST_ENTRY(ldap_int_thread_ctx_s) al;
        } ltc_next;
-       void *(*ltc_start_routine)( void *);
+       ldap_pvt_thread_start_t *ltc_start_routine;
        void *ltc_arg;
 } ldap_int_thread_ctx_t;
 
 struct ldap_int_thread_pool_s {
-       STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next;
+       LDAP_STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next;
        ldap_pvt_thread_mutex_t ltp_mutex;
        ldap_pvt_thread_cond_t ltp_cond;
-       STAILQ_HEAD(tcq, ldap_int_thread_ctx_s) ltp_pending_list;
-       long ltp_state;
+       ldap_pvt_thread_cond_t ltp_pcond;
+       LDAP_STAILQ_HEAD(tcq, ldap_int_thread_ctx_s) ltp_pending_list;
+       LDAP_SLIST_HEAD(tcl, ldap_int_thread_ctx_s) ltp_free_list;
+       LDAP_SLIST_HEAD(tclq, ldap_int_thread_ctx_s) ltp_active_list;
+       ldap_int_thread_pool_state_t ltp_state;
        long ltp_max_count;
        long ltp_max_pending;
        long ltp_pending_count;
@@ -53,44 +85,34 @@ struct ldap_int_thread_pool_s {
        long ltp_starting;
 };
 
-static STAILQ_HEAD(tpq, ldap_int_thread_pool_s)
+static LDAP_STAILQ_HEAD(tpq, ldap_int_thread_pool_s)
        ldap_int_thread_pool_list =
-       STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list);
-
-static SLIST_HEAD(tcl, ldap_int_thread_ctx_s)
-       ldap_int_ctx_free_list = 
-       SLIST_HEAD_INITIALIZER(ldap_int_ctx_free_list);
+       LDAP_STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list);
 
 static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
-static ldap_pvt_thread_mutex_t ldap_pvt_ctx_free_mutex;
 
-static void *ldap_int_thread_pool_wrapper(
-       struct ldap_int_thread_pool_s *pool );
+static void *ldap_int_thread_pool_wrapper( void *pool );
+
+static ldap_pvt_thread_t ldap_int_main_tid;
+
+static ldap_int_thread_key_t ldap_int_main_thrctx[LDAP_MAXTHR];
 
 int
 ldap_int_thread_pool_startup ( void )
 {
-       int rc = ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
-       if (rc == 0)
-               rc = ldap_pvt_thread_mutex_init(&ldap_pvt_ctx_free_mutex);
-       return rc;
+       ldap_int_main_tid = ldap_pvt_thread_self();
+
+       return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
 }
 
 int
 ldap_int_thread_pool_shutdown ( void )
 {
-       ldap_int_thread_ctx_t *ctx;
        struct ldap_int_thread_pool_s *pool;
 
-       while ((pool = STAILQ_FIRST(&ldap_int_thread_pool_list)) != NULL) {
-               STAILQ_REMOVE_HEAD(&ldap_int_thread_pool_list, ltp_next);
-               ldap_pvt_thread_pool_destroy( &pool, 0);
+       while ((pool = LDAP_STAILQ_FIRST(&ldap_int_thread_pool_list)) != NULL) {
+               (ldap_pvt_thread_pool_destroy)(&pool, 0); /* ignore thr_debug macro */
        }
-       while ((ctx = SLIST_FIRST(&ldap_int_ctx_free_list))) {
-               SLIST_REMOVE_HEAD(&ldap_int_ctx_free_list, ltc_next.l);
-               free(ctx);
-       }
-       ldap_pvt_thread_mutex_destroy(&ldap_pvt_ctx_free_mutex);
        ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
        return(0);
 }
@@ -114,17 +136,19 @@ ldap_pvt_thread_pool_init (
        if (rc != 0)
                return(rc);
        rc = ldap_pvt_thread_cond_init(&pool->ltp_cond);
+       if (rc != 0)
+               return(rc);
+       rc = ldap_pvt_thread_cond_init(&pool->ltp_pcond);
        if (rc != 0)
                return(rc);
        pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
        pool->ltp_max_count = max_threads;
        pool->ltp_max_pending = max_pending;
+       LDAP_STAILQ_INIT(&pool->ltp_pending_list);
+       LDAP_SLIST_INIT(&pool->ltp_free_list);
+       LDAP_SLIST_INIT(&pool->ltp_active_list);
        ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
-       if (STAILQ_EMPTY(&ldap_int_thread_pool_list)) {
-               STAILQ_INSERT_HEAD(&ldap_int_thread_pool_list, pool, ltp_next);
-       } else {
-               STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next);
-       }
+       LDAP_STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next);
        ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
 
 #if 0
@@ -145,18 +169,18 @@ ldap_pvt_thread_pool_init (
        pool->ltp_open_count++;
 
        ldap_pvt_thread_t thr;
-       rc = ldap_pvt_thread_create( &thr, 1,
-               (void *) ldap_int_thread_pool_wrapper, pool );
+       rc = ldap_pvt_thread_create( &thr, 1, ldap_int_thread_pool_wrapper, pool );
 
        if( rc != 0) {
                /* couldn't start one?  then don't start any */
                ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
-               STAILQ_REMOVE(ldap_int_thread_pool_list, pool, 
-                       ldap_int_thread_element_s, ltp_next);
+               LDAP_STAILQ_REMOVE(ldap_int_thread_pool_list, pool, 
+                       ldap_int_thread_pool_s, ltp_next);
                ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
+               ldap_pvt_thread_cond_destroy(&pool->ltp_pcond);
                ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
                ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
-               free(pool);
+               LDAP_FREE(pool);
                return(-1);
        }
 #endif
@@ -165,10 +189,14 @@ ldap_pvt_thread_pool_init (
        return(0);
 }
 
+#define        TID_HASH(tid, hash) do { unsigned i; \
+       unsigned char *ptr = (unsigned char *)&(tid); \
+       for (i=0, hash=0; i<sizeof(tid); i++) hash += ptr[i]; } while(0)
+
 int
 ldap_pvt_thread_pool_submit (
        ldap_pvt_thread_pool_t *tpool,
-       void *(*start_routine)( void * ), void *arg )
+       ldap_pvt_thread_start_t *start_routine, void *arg )
 {
        struct ldap_int_thread_pool_s *pool;
        ldap_int_thread_ctx_t *ctx;
@@ -184,20 +212,18 @@ ldap_pvt_thread_pool_submit (
                return(-1);
 
        ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
-       if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING
+       if ((pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING &&
+               pool->ltp_state != LDAP_INT_THREAD_POOL_PAUSING)
                || (pool->ltp_max_pending > 0
                        && pool->ltp_pending_count >= pool->ltp_max_pending))
        {
                ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
                return(-1);
        }
-       ldap_pvt_thread_mutex_lock(&ldap_pvt_ctx_free_mutex);
-       ctx = SLIST_FIRST(&ldap_int_ctx_free_list);
+       ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list);
        if (ctx) {
-               SLIST_REMOVE_HEAD(&ldap_int_ctx_free_list, ltc_next.l);
-               ldap_pvt_thread_mutex_unlock(&ldap_pvt_ctx_free_mutex);
+               LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l);
        } else {
-               ldap_pvt_thread_mutex_unlock(&ldap_pvt_ctx_free_mutex);
                ctx = (ldap_int_thread_ctx_t *) LDAP_MALLOC(
                        sizeof(ldap_int_thread_ctx_t));
                if (ctx == NULL) {
@@ -210,17 +236,15 @@ ldap_pvt_thread_pool_submit (
        ctx->ltc_arg = arg;
 
        pool->ltp_pending_count++;
-       if (STAILQ_EMPTY(&pool->ltp_pending_list)) {
-               STAILQ_INSERT_HEAD(&pool->ltp_pending_list, ctx, ltc_next.q);
-       } else {
-               STAILQ_INSERT_TAIL(&pool->ltp_pending_list, ctx, ltc_next.q);
+       LDAP_STAILQ_INSERT_TAIL(&pool->ltp_pending_list, ctx, ltc_next.q);
+       if (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) {
+               ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
+               return(0);
        }
        ldap_pvt_thread_cond_signal(&pool->ltp_cond);
-       if ((pool->ltp_open_count <= 0
-                       || pool->ltp_pending_count > 1
-                       || pool->ltp_open_count == pool->ltp_active_count)
-               && (pool->ltp_max_count <= 0
-                       || pool->ltp_open_count < pool->ltp_max_count))
+       if (pool->ltp_open_count < pool->ltp_active_count + pool->ltp_pending_count
+               && (pool->ltp_open_count < pool->ltp_max_count ||
+                       pool->ltp_max_count <= 0 ))
        {
                pool->ltp_open_count++;
                pool->ltp_starting++;
@@ -229,11 +253,25 @@ ldap_pvt_thread_pool_submit (
        ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
        if (need_thread) {
-               int rc = ldap_pvt_thread_create( &thr, 1,
-                       (void *)ldap_int_thread_pool_wrapper, pool );
+               int rc;
+
                ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+
+               rc = ldap_pvt_thread_create( &thr, 1,
+                       ldap_int_thread_pool_wrapper, pool );
                if (rc == 0) {
+                       int hash;
                        pool->ltp_starting--;
+
+                       /* assign this thread ID to a key slot; start
+                        * at the thread ID itself (mod LDAP_MAXTHR) and
+                        * look for an empty slot.
+                        */
+                       TID_HASH(thr, hash);
+                       for (rc = hash & (LDAP_MAXTHR-1);
+                               !ldap_pvt_thread_equal(thread_keys[rc].id, tid_zero);
+                               rc = (rc+1) & (LDAP_MAXTHR-1));
+                       thread_keys[rc].id = thr;
                } else {
                        /* couldn't create thread.  back out of
                         * ltp_open_count and check for even worse things.
@@ -244,18 +282,18 @@ ldap_pvt_thread_pool_submit (
                                /* no open threads at all?!?
                                 */
                                ldap_int_thread_ctx_t *ptr;
-                               STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltc_next.q)
+                               LDAP_STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltc_next.q)
                                        if (ptr == ctx) break;
                                if (ptr == ctx) {
                                        /* no open threads, context not handled, so
                                         * back out of ltp_pending_count, free the context,
                                         * report the error.
                                         */
-                                       STAILQ_REMOVE(&pool->ltp_pending_list, ctx, 
+                                       LDAP_STAILQ_REMOVE(&pool->ltp_pending_list, ctx, 
                                                ldap_int_thread_ctx_s, ltc_next.q);
                                        pool->ltp_pending_count++;
                                        ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
-                                       free(ctx);
+                                       LDAP_FREE(ctx);
                                        return(-1);
                                }
                        }
@@ -314,7 +352,6 @@ int
 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
 {
        struct ldap_int_thread_pool_s *pool, *pptr;
-       long waiting;
        ldap_int_thread_ctx_t *ctx;
 
        if (tpool == NULL)
@@ -325,10 +362,10 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
        if (pool == NULL) return(-1);
 
        ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
-       STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next)
+       LDAP_STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next)
                if (pptr == pool) break;
        if (pptr == pool)
-               STAILQ_REMOVE(&ldap_int_thread_pool_list, pool,
+               LDAP_STAILQ_REMOVE(&ldap_int_thread_pool_list, pool,
                        ldap_int_thread_pool_s, ltp_next);
        ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
 
@@ -338,50 +375,65 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
        pool->ltp_state = run_pending
                ? LDAP_INT_THREAD_POOL_FINISHING
                : LDAP_INT_THREAD_POOL_STOPPING;
-       waiting = pool->ltp_open_count;
 
-       /* broadcast could be used here, but only after
-        * it is fixed in the NT thread implementation
-        */
-       while (--waiting >= 0) {
-               ldap_pvt_thread_cond_signal(&pool->ltp_cond);
+       if ( pool->ltp_open_count ) {
+               ldap_pvt_thread_cond_broadcast(&pool->ltp_cond);
+               ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
        }
        ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
-       do {
-               ldap_pvt_thread_yield();
-               ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
-               waiting = pool->ltp_open_count;
-               ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
-       } while (waiting > 0);
+       while ((ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list)) != NULL)
+       {
+               LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
+               LDAP_FREE(ctx);
+       }
 
-       while ((ctx = STAILQ_FIRST(&pool->ltp_pending_list)) != NULL)
+       while ((ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list)) != NULL)
        {
-               STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
-               free(ctx);
+               LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l);
+               LDAP_FREE(ctx);
        }
 
+       ldap_pvt_thread_cond_destroy(&pool->ltp_pcond);
        ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
        ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
-       free(pool);
+       LDAP_FREE(pool);
        return(0);
 }
 
 static void *
 ldap_int_thread_pool_wrapper ( 
-       struct ldap_int_thread_pool_s *pool )
+       void *xpool )
 {
+       struct ldap_int_thread_pool_s *pool = xpool;
        ldap_int_thread_ctx_t *ctx;
+       ldap_int_thread_key_t ltc_key[MAXKEYS];
+       ldap_pvt_thread_t tid;
+       int i, keyslot, hash;
 
        if (pool == NULL)
                return NULL;
 
+       for ( i=0; i<MAXKEYS; i++ ) {
+               ltc_key[i].ltk_key = NULL;
+       }
+
+       tid = ldap_pvt_thread_self();
+
        ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
 
+       /* store pointer to our keys */
+       TID_HASH(tid, hash);
+       for (i = hash & (LDAP_MAXTHR-1);
+                               !ldap_pvt_thread_equal(thread_keys[i].id, tid);
+                               i = (i+1) & (LDAP_MAXTHR-1));
+       thread_keys[i].ctx = ltc_key;
+       keyslot = i;
+
        while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) {
-               ctx = STAILQ_FIRST(&pool->ltp_pending_list);
+               ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list);
                if (ctx) {
-                       STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
+                       LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q);
                } else {
                        if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING)
                                break;
@@ -403,36 +455,220 @@ ldap_int_thread_pool_wrapper (
                         * should be like this:
                         *   if (pool->ltp_open_count > 1 && pool->ltp_starting == 0)
                         *       check timer, leave thread (break;)
+                        *
+                        * Just use pthread_cond_timedwait if we want to
+                        * check idle time.
                         */
 
-                       if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
+                       if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING
+                               || pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING)
+                       {
                                ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
+                       }
 
                        continue;
                }
 
                pool->ltp_pending_count--;
+
+               LDAP_SLIST_INSERT_HEAD(&pool->ltp_active_list, ctx, ltc_next.al);
                pool->ltp_active_count++;
                ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
-               (ctx->ltc_start_routine)(ctx->ltc_arg);
-               ldap_pvt_thread_mutex_lock(&ldap_pvt_ctx_free_mutex);
-               SLIST_INSERT_HEAD(&ldap_int_ctx_free_list, ctx, ltc_next.l);
-               ldap_pvt_thread_mutex_unlock(&ldap_pvt_ctx_free_mutex);
-               ldap_pvt_thread_yield();
-
-               /* if we use an idle timer, here's
-                * a good place to update it
-                */
+               ctx->ltc_start_routine(ltc_key, ctx->ltc_arg);
 
                ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+               LDAP_SLIST_REMOVE(&pool->ltp_active_list, ctx,
+                       ldap_int_thread_ctx_s, ltc_next.al);
+               LDAP_SLIST_INSERT_HEAD(&pool->ltp_free_list, ctx, ltc_next.l);
                pool->ltp_active_count--;
+
+               if (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) {
+                       if (pool->ltp_active_count < 2) {
+                               ldap_pvt_thread_cond_signal(&pool->ltp_pcond);
+                       }
+                       ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
+               }
+       }
+
+       for ( i=0; i<MAXKEYS && ltc_key[i].ltk_key; i++ ) {
+               if (ltc_key[i].ltk_free)
+                       ltc_key[i].ltk_free(
+                               ltc_key[i].ltk_key,
+                               ltc_key[i].ltk_data );
        }
 
+       thread_keys[keyslot].ctx = NULL;
+       thread_keys[keyslot].id = tid_zero;
+
        pool->ltp_open_count--;
+
+       /* let pool_destroy know we're all done */
+       if (pool->ltp_open_count < 1)
+               ldap_pvt_thread_cond_signal(&pool->ltp_cond);
+
        ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
        ldap_pvt_thread_exit(NULL);
        return(NULL);
 }
-#endif /* LDAP_HAVE_THREAD_POOL */
+
+int
+ldap_pvt_thread_pool_pause ( 
+       ldap_pvt_thread_pool_t *tpool )
+{
+       struct ldap_int_thread_pool_s *pool;
+
+       if (tpool == NULL)
+               return(-1);
+
+       pool = *tpool;
+
+       if (pool == NULL)
+               return(0);
+
+       ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+
+       /* If someone else has already requested a pause, we have to wait */
+       while (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) {
+               pool->ltp_pending_count++;
+               pool->ltp_active_count--;
+               ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
+               pool->ltp_pending_count--;
+               pool->ltp_active_count++;
+       }
+       /* Wait for everyone else to finish */
+       pool->ltp_state = LDAP_INT_THREAD_POOL_PAUSING;
+       while (pool->ltp_active_count > 1) {
+               ldap_pvt_thread_cond_wait(&pool->ltp_pcond, &pool->ltp_mutex);
+       }
+       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
+       return(0);
+}
+
+int
+ldap_pvt_thread_pool_resume ( 
+       ldap_pvt_thread_pool_t *tpool )
+{
+       struct ldap_int_thread_pool_s *pool;
+
+       if (tpool == NULL)
+               return(-1);
+
+       pool = *tpool;
+
+       if (pool == NULL)
+               return(0);
+
+       ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+
+       pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
+       ldap_pvt_thread_cond_broadcast(&pool->ltp_cond);
+       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
+       return(0);
+}
+
+int ldap_pvt_thread_pool_getkey(
+       void *xctx,
+       void *key,
+       void **data,
+       ldap_pvt_thread_pool_keyfree_t **kfree )
+{
+       ldap_int_thread_key_t *ctx = xctx;
+       int i;
+
+       if ( !ctx || !data ) return EINVAL;
+
+       for ( i=0; i<MAXKEYS && ctx[i].ltk_key; i++ ) {
+               if ( ctx[i].ltk_key == key ) {
+                       *data = ctx[i].ltk_data;
+                       if ( kfree ) *kfree = ctx[i].ltk_free;
+                       return 0;
+               }
+       }
+       return ENOENT;
+}
+
+int ldap_pvt_thread_pool_setkey(
+       void *xctx,
+       void *key,
+       void *data,
+       ldap_pvt_thread_pool_keyfree_t *kfree )
+{
+       ldap_int_thread_key_t *ctx = xctx;
+       int i;
+
+       if ( !ctx || !key ) return EINVAL;
+
+       for ( i=0; i<MAXKEYS; i++ ) {
+               if ( !ctx[i].ltk_key || ctx[i].ltk_key == key ) {
+                       ctx[i].ltk_key = key;
+                       ctx[i].ltk_data = data;
+                       ctx[i].ltk_free = kfree;
+                       return 0;
+               }
+       }
+       return ENOMEM;
+}
+
+/* Free all elements with this key, no matter which thread they're in.
+ * May only be called while the pool is paused.
+ */
+void ldap_pvt_thread_pool_purgekey( void *key )
+{
+       int i, j;
+       ldap_int_thread_key_t *ctx;
+
+       for ( i=0; i<LDAP_MAXTHR; i++ ) {
+               if ( thread_keys[i].ctx ) {
+                       ctx = thread_keys[i].ctx;
+                       for ( j=0; j<MAXKEYS; j++ ) {
+                               if ( ctx[j].ltk_key == key ) {
+                                       if (ctx[j].ltk_free)
+                                               ctx[j].ltk_free( ctx[j].ltk_key, ctx[j].ltk_data );
+                                       ctx[j].ltk_key = NULL;
+                                       ctx[j].ltk_free = NULL;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+/*
+ * This is necessary if the caller does not have access to the
+ * thread context handle (for example, a slapd plugin calling
+ * slapi_search_internal()). No doubt it is more efficient to
+ * for the application to keep track of the thread context
+ * handles itself.
+ */
+void *ldap_pvt_thread_pool_context( )
+{
+       ldap_pvt_thread_t tid;
+       int i, hash;
+
+       tid = ldap_pvt_thread_self();
+       if ( ldap_pvt_thread_equal( tid, ldap_int_main_tid ))
+               return ldap_int_main_thrctx;
+
+       TID_HASH( tid, hash );
+       for (i = hash & (LDAP_MAXTHR-1);
+               !ldap_pvt_thread_equal(thread_keys[i].id, tid_zero) &&
+               !ldap_pvt_thread_equal(thread_keys[i].id, tid);
+               i = (i+1) & (LDAP_MAXTHR-1));
+
+       return thread_keys[i].ctx;
+}
+
+void ldap_pvt_thread_pool_context_reset( void *vctx )
+{
+       ldap_int_thread_key_t *ctx = vctx;
+       int i;
+
+       for ( i=0; i<MAXKEYS && ctx[i].ltk_key; i++) {
+               if ( ctx[i].ltk_free )
+                       ctx[i].ltk_free( ctx[i].ltk_key, ctx[i].ltk_data );
+               ctx[i].ltk_key = NULL;
+       }
+}
+#endif /* LDAP_THREAD_HAVE_TPOOL */