]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap_r/tpool.c
Emulate mkstemp() using mktemp() if mkstemp() is not found by configure
[openldap] / libraries / libldap_r / tpool.c
index af0c4f739d63069105f6118fd9cc70fe59f8bef9..6d014d70ff0dc58ca36ca61c490df9c00c762582 100644 (file)
@@ -12,8 +12,8 @@
 #include "portable.h"
 
 #include <stdio.h>
-#include <stdarg.h>
 
+#include <ac/stdarg.h>
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/time.h>
@@ -44,6 +44,7 @@ struct ldap_int_thread_pool_s {
        long ltp_pending_count;
        long ltp_active_count;
        long ltp_open_count;
+       long ltp_starting;
 };
 
 typedef struct ldap_int_thread_ctx_s {
@@ -60,7 +61,9 @@ static void *ldap_int_thread_pool_wrapper(
 
 static void *ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem );
 static void *ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem );
+#if 0
 static void *ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem );
+#endif
 
 int
 ldap_int_thread_pool_startup ( void )
@@ -84,12 +87,11 @@ ldap_int_thread_pool_shutdown ( void )
 int
 ldap_pvt_thread_pool_init (
        ldap_pvt_thread_pool_t *tpool,
-       int max_concurrency,
+       int max_threads,
        int max_pending )
 {
-       int rc;
        ldap_pvt_thread_pool_t pool;
-       ldap_pvt_thread_t thr;
+       int rc;
 
        *tpool = NULL;
        pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
@@ -97,18 +99,37 @@ ldap_pvt_thread_pool_init (
 
        if (pool == NULL) return(-1);
 
-       ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
-       ldap_pvt_thread_cond_init(&pool->ltp_cond);
+       rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
+       if (rc != 0)
+               return(rc);
+       rc = ldap_pvt_thread_cond_init(&pool->ltp_cond);
+       if (rc != 0)
+               return(rc);
        pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
-       pool->ltp_max_count = max_concurrency;
+       pool->ltp_max_count = max_threads;
        pool->ltp_max_pending = max_pending;
        ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
        ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool);
        ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
 
-       /* start up one thread, just so there is one */
+#if 0
+       /* THIS WILL NOT WORK on some systems.  If the process
+        * forks after starting a thread, there is no guarantee
+        * that the thread will survive the fork.  For example,
+        * slapd forks in order to daemonize, and does so after
+        * calling ldap_pvt_thread_pool_init.  On some systems,
+        * this initial thread does not run in the child process,
+        * but ltp_open_count == 1, so two things happen: 
+        * 1) the first client connection fails, and 2) when
+        * slapd is kill'ed, it never terminates since it waits
+        * for all worker threads to exit. */
+
+       /* start up one thread, just so there is one. no need to
+        * lock the mutex right now, since no threads are running.
+        */
        pool->ltp_open_count++;
 
+       ldap_pvt_thread_t thr;
        rc = ldap_pvt_thread_create( &thr, 1,
                (void *) ldap_int_thread_pool_wrapper, pool );
 
@@ -122,6 +143,7 @@ ldap_pvt_thread_pool_init (
                free(pool);
                return(-1);
        }
+#endif
 
        *tpool = pool;
        return(0);
@@ -172,6 +194,7 @@ ldap_pvt_thread_pool_submit (
                        || pool->ltp_open_count < pool->ltp_max_count))
        {
                pool->ltp_open_count++;
+               pool->ltp_starting++;
                need_thread = 1;
        }
        ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
@@ -179,15 +202,17 @@ ldap_pvt_thread_pool_submit (
        if (need_thread) {
                int rc = ldap_pvt_thread_create( &thr, 1,
                        (void *)ldap_int_thread_pool_wrapper, pool );
-               if (rc != 0) {
+               ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+               if (rc == 0) {
+                       pool->ltp_starting--;
+               } else {
                        /* couldn't create thread.  back out of
                         * ltp_open_count and check for even worse things.
                         */
-                       ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
                        pool->ltp_open_count--;
+                       pool->ltp_starting--;
                        if (pool->ltp_open_count == 0) {
-                               /* no open threads at all?!?  this will never happen
-                                * because we always leave at least one thread open.
+                               /* no open threads at all?!?
                                 */
                                if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) {
                                        /* no open threads, context not handled, so
@@ -200,18 +225,37 @@ ldap_pvt_thread_pool_submit (
                                        return(-1);
                                }
                        }
-                       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
                        /* there is another open thread, so this
                         * context will be handled eventually.
                         * continue on and signal that the context
                         * is waiting.
                         */
                }
+               ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
        }
 
        return(0);
 }
 
+int
+ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads )
+{
+       struct ldap_int_thread_pool_s *pool;
+
+       if (tpool == NULL)
+               return(-1);
+
+       pool = *tpool;
+
+       if (pool == NULL)
+               return(-1);
+
+       ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
+       pool->ltp_max_count = max_threads;
+       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
+       return(0);
+}
+
 int
 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool )
 {
@@ -257,7 +301,6 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
                ? LDAP_INT_THREAD_POOL_FINISHING
                : LDAP_INT_THREAD_POOL_STOPPING;
        waiting = pool->ltp_open_count;
-       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
        /* broadcast could be used here, but only after
         * it is fixed in the NT thread implementation
@@ -265,6 +308,7 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
        while (--waiting >= 0) {
                ldap_pvt_thread_cond_signal(&pool->ltp_cond);
        }
+       ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
 
        do {
                ldap_pvt_thread_yield();
@@ -273,8 +317,8 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
                ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
        } while (waiting > 0);
 
-       while (ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist(
-               &pool->ltp_pending_list, NULL))
+       while ((ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist(
+               &pool->ltp_pending_list, NULL)) != NULL)
        {
                free(ctx);
        }
@@ -302,10 +346,24 @@ ldap_int_thread_pool_wrapper (
                if (ctx == NULL) {
                        if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING)
                                break;
+                       if (pool->ltp_max_count > 0
+                               && pool->ltp_open_count > pool->ltp_max_count)
+                       {
+                               /* too many threads running (can happen if the
+                                * maximum threads value is set during ongoing
+                                * operation using ldap_pvt_thread_pool_maxthreads)
+                                * so let this thread die.
+                                */
+                               break;
+                       }
+
                        /* we could check an idle timer here, and let the
                         * thread die if it has been inactive for a while.
                         * only die if there are other open threads (i.e.,
-                        * always have at least one thread open).
+                        * always have at least one thread open).  the check
+                        * should be like this:
+                        *   if (pool->ltp_open_count > 1 && pool->ltp_starting == 0)
+                        *       check timer, leave thread (break;)
                         */
 
                        if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
@@ -377,7 +435,7 @@ ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem )
        }
        return(NULL);
 }
-
+#if 0
 static void *
 ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem )
 {
@@ -392,5 +450,5 @@ ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem )
 
        return(NULL);
 }
-
+#endif
 #endif /* LDAP_HAVE_THREAD_POOL */