+
+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 */