home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap_r / tpool.c < prev   
C/C++ Source or Header  |  2000-09-15  |  12KB  |  455 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap_r/tpool.c,v 1.1.2.7 2000/09/15 01:07:43 bcollins Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, Redwood City, California, USA
  4.  * All rights reserved.
  5.  *
  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.
  10.  */
  11.  
  12. #include "portable.h"
  13.  
  14. #include <stdio.h>
  15. #include <stdarg.h>
  16.  
  17. #include <ac/stdlib.h>
  18. #include <ac/string.h>
  19. #include <ac/time.h>
  20.  
  21. #include "ldap-int.h"
  22. #include "ldap_pvt_thread.h"
  23.  
  24. #ifndef LDAP_THREAD_HAVE_TPOOL
  25.  
  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
  30. };
  31.  
  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;
  35.  
  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;
  41.     long ltp_state;
  42.     long ltp_max_count;
  43.     long ltp_max_pending;
  44.     long ltp_pending_count;
  45.     long ltp_active_count;
  46.     long ltp_open_count;
  47.     long ltp_starting;
  48. };
  49.  
  50. typedef struct ldap_int_thread_ctx_s {
  51.     struct ldap_int_thread_ctx_s *ltc_next;
  52.     void *(*ltc_start_routine)( void *);
  53.     void *ltc_arg;
  54. } ldap_int_thread_ctx_t;
  55.  
  56. static ldap_int_thread_list_t ldap_int_thread_pool_list = NULL;
  57. static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
  58.  
  59. static void *ldap_int_thread_pool_wrapper(
  60.     struct ldap_int_thread_pool_s *pool );
  61.  
  62. static void *ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem );
  63. static void *ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem );
  64. #if 0
  65. static void *ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem );
  66. #endif
  67.  
  68. int
  69. ldap_int_thread_pool_startup ( void )
  70. {
  71.     return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
  72. }
  73.  
  74. int
  75. ldap_int_thread_pool_shutdown ( void )
  76. {
  77.     while (ldap_int_thread_pool_list != NULL) {
  78.         struct ldap_int_thread_pool_s *pool =
  79.             (struct ldap_int_thread_pool_s *) ldap_int_thread_pool_list;
  80.  
  81.         ldap_pvt_thread_pool_destroy( &pool, 0);
  82.     }
  83.     ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
  84.     return(0);
  85. }
  86.  
  87. int
  88. ldap_pvt_thread_pool_init (
  89.     ldap_pvt_thread_pool_t *tpool,
  90.     int max_threads,
  91.     int max_pending )
  92. {
  93.     ldap_pvt_thread_pool_t pool;
  94.     int rc;
  95.  
  96.     *tpool = NULL;
  97.     pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
  98.         sizeof(struct ldap_int_thread_pool_s));
  99.  
  100.     if (pool == NULL) return(-1);
  101.  
  102.     rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
  103.     if (rc != 0)
  104.         return(rc);
  105.     rc = ldap_pvt_thread_cond_init(&pool->ltp_cond);
  106.     if (rc != 0)
  107.         return(rc);
  108.     pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING;
  109.     pool->ltp_max_count = max_threads;
  110.     pool->ltp_max_pending = max_pending;
  111.     ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
  112.     ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool);
  113.     ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
  114.  
  115. #if 0
  116.     /* THIS WILL NOT WORK on some systems.  If the process
  117.      * forks after starting a thread, there is no guarantee
  118.      * that the thread will survive the fork.  For example,
  119.      * slapd forks in order to daemonize, and does so after
  120.      * calling ldap_pvt_thread_pool_init.  On some systems,
  121.      * this initial thread does not run in the child process,
  122.      * but ltp_open_count == 1, so two things happen: 
  123.      * 1) the first client connection fails, and 2) when
  124.      * slapd is kill'ed, it never terminates since it waits
  125.      * for all worker threads to exit. */
  126.  
  127.     /* start up one thread, just so there is one. no need to
  128.      * lock the mutex right now, since no threads are running.
  129.      */
  130.     pool->ltp_open_count++;
  131.  
  132.     ldap_pvt_thread_t thr;
  133.     rc = ldap_pvt_thread_create( &thr, 1,
  134.         (void *) ldap_int_thread_pool_wrapper, pool );
  135.  
  136.     if( rc != 0) {
  137.         /* couldn't start one?  then don't start any */
  138.         ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
  139.         ldap_int_thread_delist(&ldap_int_thread_pool_list, pool);
  140.         ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
  141.         ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
  142.         ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
  143.         free(pool);
  144.         return(-1);
  145.     }
  146. #endif
  147.  
  148.     *tpool = pool;
  149.     return(0);
  150. }
  151.  
  152. int
  153. ldap_pvt_thread_pool_submit (
  154.     ldap_pvt_thread_pool_t *tpool,
  155.     void *(*start_routine)( void * ), void *arg )
  156. {
  157.     struct ldap_int_thread_pool_s *pool;
  158.     ldap_int_thread_ctx_t *ctx;
  159.     int need_thread = 0;
  160.     ldap_pvt_thread_t thr;
  161.  
  162.     if (tpool == NULL)
  163.         return(-1);
  164.  
  165.     pool = *tpool;
  166.  
  167.     if (pool == NULL)
  168.         return(-1);
  169.  
  170.     ctx = (ldap_int_thread_ctx_t *) LDAP_CALLOC(1,
  171.         sizeof(ldap_int_thread_ctx_t));
  172.  
  173.     if (ctx == NULL) return(-1);
  174.  
  175.     ctx->ltc_start_routine = start_routine;
  176.     ctx->ltc_arg = arg;
  177.  
  178.     ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  179.     if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING
  180.         || (pool->ltp_max_pending > 0
  181.             && pool->ltp_pending_count >= pool->ltp_max_pending))
  182.     {
  183.         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  184.         free(ctx);
  185.         return(-1);
  186.     }
  187.     pool->ltp_pending_count++;
  188.     ldap_int_thread_enlist(&pool->ltp_pending_list, ctx);
  189.     ldap_pvt_thread_cond_signal(&pool->ltp_cond);
  190.     if ((pool->ltp_open_count <= 0
  191.             || pool->ltp_pending_count > 1
  192.             || pool->ltp_open_count == pool->ltp_active_count)
  193.         && (pool->ltp_max_count <= 0
  194.             || pool->ltp_open_count < pool->ltp_max_count))
  195.     {
  196.         pool->ltp_open_count++;
  197.         pool->ltp_starting++;
  198.         need_thread = 1;
  199.     }
  200.     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  201.  
  202.     if (need_thread) {
  203.         int rc = ldap_pvt_thread_create( &thr, 1,
  204.             (void *)ldap_int_thread_pool_wrapper, pool );
  205.         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  206.         if (rc == 0) {
  207.             pool->ltp_starting--;
  208.         } else {
  209.             /* couldn't create thread.  back out of
  210.              * ltp_open_count and check for even worse things.
  211.              */
  212.             pool->ltp_open_count--;
  213.             pool->ltp_starting--;
  214.             if (pool->ltp_open_count == 0) {
  215.                 /* no open threads at all?!?
  216.                  */
  217.                 if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) {
  218.                     /* no open threads, context not handled, so
  219.                      * back out of ltp_pending_count, free the context,
  220.                      * report the error.
  221.                      */
  222.                     pool->ltp_pending_count++;
  223.                     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  224.                     free(ctx);
  225.                     return(-1);
  226.                 }
  227.             }
  228.             /* there is another open thread, so this
  229.              * context will be handled eventually.
  230.              * continue on and signal that the context
  231.              * is waiting.
  232.              */
  233.         }
  234.         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  235.     }
  236.  
  237.     return(0);
  238. }
  239.  
  240. int
  241. ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads )
  242. {
  243.     struct ldap_int_thread_pool_s *pool;
  244.  
  245.     if (tpool == NULL)
  246.         return(-1);
  247.  
  248.     pool = *tpool;
  249.  
  250.     if (pool == NULL)
  251.         return(-1);
  252.  
  253.     ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  254.     pool->ltp_max_count = max_threads;
  255.     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  256.     return(0);
  257. }
  258.  
  259. int
  260. ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool )
  261. {
  262.     struct ldap_int_thread_pool_s *pool;
  263.     int count;
  264.  
  265.     if (tpool == NULL)
  266.         return(-1);
  267.  
  268.     pool = *tpool;
  269.  
  270.     if (pool == NULL)
  271.         return(0);
  272.  
  273.     ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  274.     count = pool->ltp_pending_count + pool->ltp_active_count;
  275.     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  276.     return(count);
  277. }
  278.  
  279. int
  280. ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending )
  281. {
  282.     struct ldap_int_thread_pool_s *pool;
  283.     long waiting;
  284.     ldap_int_thread_ctx_t *ctx;
  285.  
  286.     if (tpool == NULL)
  287.         return(-1);
  288.  
  289.     pool = *tpool;
  290.  
  291.     if (pool == NULL) return(-1);
  292.  
  293.     ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
  294.     pool = ldap_int_thread_delist(&ldap_int_thread_pool_list, pool);
  295.     ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
  296.  
  297.     if (pool == NULL) return(-1);
  298.  
  299.     ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  300.     pool->ltp_state = run_pending
  301.         ? LDAP_INT_THREAD_POOL_FINISHING
  302.         : LDAP_INT_THREAD_POOL_STOPPING;
  303.     waiting = pool->ltp_open_count;
  304.  
  305.     /* broadcast could be used here, but only after
  306.      * it is fixed in the NT thread implementation
  307.      */
  308.     while (--waiting >= 0) {
  309.         ldap_pvt_thread_cond_signal(&pool->ltp_cond);
  310.     }
  311.     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  312.  
  313.     do {
  314.         ldap_pvt_thread_yield();
  315.         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  316.         waiting = pool->ltp_open_count;
  317.         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  318.     } while (waiting > 0);
  319.  
  320.     while ((ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist(
  321.         &pool->ltp_pending_list, NULL)) != NULL)
  322.     {
  323.         free(ctx);
  324.     }
  325.  
  326.     ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
  327.     ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
  328.     free(pool);
  329.     return(0);
  330. }
  331.  
  332. static void *
  333. ldap_int_thread_pool_wrapper ( 
  334.     struct ldap_int_thread_pool_s *pool )
  335. {
  336.     ldap_int_thread_ctx_t *ctx;
  337.  
  338.     if (pool == NULL)
  339.         return NULL;
  340.  
  341.     ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  342.  
  343.     while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) {
  344.  
  345.         ctx = ldap_int_thread_delist(&pool->ltp_pending_list, NULL);
  346.         if (ctx == NULL) {
  347.             if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING)
  348.                 break;
  349.             if (pool->ltp_max_count > 0
  350.                 && pool->ltp_open_count > pool->ltp_max_count)
  351.             {
  352.                 /* too many threads running (can happen if the
  353.                  * maximum threads value is set during ongoing
  354.                  * operation using ldap_pvt_thread_pool_maxthreads)
  355.                  * so let this thread die.
  356.                  */
  357.                 break;
  358.             }
  359.  
  360.             /* we could check an idle timer here, and let the
  361.              * thread die if it has been inactive for a while.
  362.              * only die if there are other open threads (i.e.,
  363.              * always have at least one thread open).  the check
  364.              * should be like this:
  365.              *   if (pool->ltp_open_count > 1 && pool->ltp_starting == 0)
  366.              *       check timer, leave thread (break;)
  367.              */
  368.  
  369.             if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
  370.                 ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
  371.  
  372.             continue;
  373.         }
  374.  
  375.         pool->ltp_pending_count--;
  376.         pool->ltp_active_count++;
  377.         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  378.  
  379.         (ctx->ltc_start_routine)(ctx->ltc_arg);
  380.         free(ctx);
  381.         ldap_pvt_thread_yield();
  382.  
  383.         /* if we use an idle timer, here's
  384.          * a good place to update it
  385.          */
  386.  
  387.         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
  388.         pool->ltp_active_count--;
  389.     }
  390.  
  391.     pool->ltp_open_count--;
  392.     ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
  393.  
  394.     ldap_pvt_thread_exit(NULL);
  395.     return(NULL);
  396. }
  397.  
  398. static void *
  399. ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem )
  400. {
  401.     ldap_int_thread_list_element_t *prev;
  402.  
  403.     if (elem == NULL) return(NULL);
  404.  
  405.     ((ldap_int_thread_list_element_t *)elem)->next = NULL;
  406.     if (*list == NULL) {
  407.         *list = elem;
  408.         return(elem);
  409.     }
  410.  
  411.     for (prev = *list ; prev->next != NULL; prev = prev->next) ;
  412.     prev->next = elem;
  413.     return(elem);
  414. }
  415.  
  416. static void *
  417. ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem )
  418. {
  419.     ldap_int_thread_list_element_t *prev;
  420.  
  421.     if (*list == NULL) return(NULL);
  422.  
  423.     if (elem == NULL) elem = *list;
  424.  
  425.     if (*list == elem) {
  426.         *list = ((ldap_int_thread_list_element_t *)elem)->next;
  427.         return(elem);
  428.     }
  429.  
  430.     for (prev = *list ; prev->next != NULL; prev = prev->next) {
  431.         if (prev->next == elem) {
  432.             prev->next = ((ldap_int_thread_list_element_t *)elem)->next;
  433.             return(elem);
  434.         }
  435.     }
  436.     return(NULL);
  437. }
  438. #if 0
  439. static void *
  440. ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem )
  441. {
  442.     ldap_int_thread_list_element_t *prev;
  443.  
  444.     if (elem == NULL || *list == NULL) return(NULL);
  445.  
  446.     for (prev = *list ; prev != NULL; prev = prev->next) {
  447.         if (prev == elem)
  448.             return(elem);
  449.     }
  450.  
  451.     return(NULL);
  452. }
  453. #endif
  454. #endif /* LDAP_HAVE_THREAD_POOL */
  455.