dougm       00/04/15 15:43:11

  Modified:    src/modules/perl modperl_interp.c modperl_interp.h
                        modperl_types.h
  Log:
  interpreter pool throttling
  
  Revision  Changes    Path
  1.4       +134 -49   modperl-2.0/src/modules/perl/modperl_interp.c
  
  Index: modperl_interp.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_interp.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- modperl_interp.c  2000/04/15 17:51:44     1.3
  +++ modperl_interp.c  2000/04/15 22:43:10     1.4
  @@ -6,15 +6,21 @@
    */
   
   modperl_interp_t *modperl_interp_new(ap_pool_t *p,
  -                                     modperl_interp_t *parent)
  +                                     modperl_interp_pool_t *mip,
  +                                     PerlInterpreter *perl)
   {
       modperl_interp_t *interp = 
           (modperl_interp_t *)ap_pcalloc(p, sizeof(*interp));
       
  -    if (parent) {
  -        interp->mip_lock = parent->mip_lock;
  +    if (mip) {
  +        interp->mip = mip;
       }
   
  +    if (perl) {
  +        interp->perl = perl_clone(perl, TRUE);
  +        MpInterpCLONED_On(interp);
  +    }
  +
       MP_TRACE_i(MP_FUNC, "0x%lx\n", (unsigned long)interp);
   
       return interp;
  @@ -31,7 +37,6 @@
           MP_TRACE_i(MP_FUNC, "*error - still in use!*\n");
       }
   
  -
       PL_perl_destruct_level = 2;
       perl_destruct(interp->perl);
       perl_free(interp->perl);
  @@ -58,8 +63,23 @@
           MP_TRACE_i(MP_FUNC, "no pool, returning parent\n");
           return mip->parent;
       }
  +
  +    MUTEX_LOCK(&mip->mip_lock);
   
  -    ap_lock(mip->mip_lock);
  +    if (mip->size == mip->in_use) {
  +        if (mip->size < mip->max) {
  +            interp = modperl_interp_new(mip->ap_pool, mip, 
  +                                        mip->parent->perl);
  +            MUTEX_UNLOCK(&mip->mip_lock);
  +            modperl_interp_pool_add(mip, interp);
  +            MP_TRACE_i(MP_FUNC, "cloned new interp\n");
  +            return interp;
  +        }
  +        while (mip->size == mip->in_use) {
  +            MP_TRACE_i(MP_FUNC, "waiting for available interpreter\n");
  +            COND_WAIT(&mip->available, &mip->mip_lock);
  +        }
  +    }
   
       head = mip->head;
   
  @@ -77,6 +97,7 @@
   #endif
               MpInterpIN_USE_On(interp);
               MpInterpPUTBACK_On(interp);
  +            mip->in_use++;
               break;
           }
           else {
  @@ -86,28 +107,19 @@
           }
       }
   
  -    ap_unlock(mip->mip_lock);
  +    MUTEX_UNLOCK(&mip->mip_lock);
   
  -    if (!interp) {
  -        /*
  -         * XXX: options
  -         * -block until one is available
  -         * -clone a new Perl
  -         * - ...
  -         */
  -    }
  -
       return interp;
   }
   
   ap_status_t modperl_interp_pool_destroy(void *data)
   {
       modperl_interp_pool_t *mip = (modperl_interp_pool_t *)data;
  +    modperl_interp_t *interp;
   
  -    while (mip->head) {
  -        modperl_interp_destroy(mip->head);
  -        mip->head->perl = NULL;
  -        mip->head = mip->head->next;
  +    while ((interp = mip->head)) {
  +        modperl_interp_pool_remove(mip, interp);
  +        modperl_interp_destroy(interp);
       }
   
       MP_TRACE_i(MP_FUNC, "parent == 0x%lx\n",
  @@ -115,54 +127,112 @@
   
       modperl_interp_destroy(mip->parent);
       mip->parent->perl = NULL;
  +
  +    MUTEX_DESTROY(&mip->mip_lock);
   
  -    ap_destroy_lock(mip->mip_lock);
  +    COND_DESTROY(&mip->available);
   
       return APR_SUCCESS;
   }
   
  +void modperl_interp_pool_add(modperl_interp_pool_t *mip,
  +                             modperl_interp_t *interp)
  +{
  +    MUTEX_LOCK(&mip->mip_lock);
  +
  +    if (mip->size == 0) {
  +        mip->head = mip->tail = interp;
  +    }
  +    else {
  +        mip->tail->next = interp;
  +        mip->tail = interp;
  +    }
  +
  +    mip->size++;
  +    MP_TRACE_i(MP_FUNC, "added 0x%lx (size=%d)\n",
  +               (unsigned long)interp, mip->size);
  +
  +    MUTEX_UNLOCK(&mip->mip_lock);
  +}
  +
  +void modperl_interp_pool_remove(modperl_interp_pool_t *mip,
  +                                modperl_interp_t *interp)
  +{
  +    MUTEX_LOCK(&mip->mip_lock);
  +
  +    if (mip->head == interp) {
  +        mip->head = interp->next;
  +        interp->next = NULL;
  +        MP_TRACE_i(MP_FUNC, "shifting head from 0x%lx to 0x%lx\n",
  +                   (unsigned long)interp, (unsigned long)mip->head);
  +    }
  +    else if (mip->tail == interp) {
  +        modperl_interp_t *tmp = mip->head;
  +        /* XXX: implement a prev pointer */
  +        while (tmp->next && tmp->next->next) {
  +            tmp = tmp->next;
  +        }
  +
  +        tmp->next = NULL;
  +        mip->tail = tmp;
  +        MP_TRACE_i(MP_FUNC, "popping tail 0x%lx, now 0x%lx\n",
  +                   (unsigned long)interp, (unsigned long)mip->tail);
  +    }
  +    else {
  +        modperl_interp_t *tmp = mip->head;
  +
  +        while (tmp && tmp->next != interp) {
  +            tmp = tmp->next;
  +        }
  +
  +        if (!tmp) {
  +            MP_TRACE_i(MP_FUNC, "0x%lx not found\n",
  +                       (unsigned long)interp);
  +            MUTEX_UNLOCK(&mip->mip_lock);
  +            return;
  +        }
  +        tmp->next = tmp->next->next;
  +    }
  +
  +    mip->size--;
  +    MP_TRACE_i(MP_FUNC, "removed 0x%lx (size=%d)\n",
  +               (unsigned long)interp, mip->size);
  +
  +    MUTEX_UNLOCK(&mip->mip_lock);
  +}
  +
   void modperl_interp_pool_init(server_rec *s, ap_pool_t *p,
                                 PerlInterpreter *perl)
   {
  +    pTHX;
       MP_dSCFG(s);
       modperl_interp_pool_t *mip = 
           (modperl_interp_pool_t *)ap_pcalloc(p, sizeof(*mip));
  -    modperl_interp_t *cur_interp = NULL;
  -    ap_status_t rc;
       int i;
  -
  -    rc = ap_create_lock(&mip->mip_lock, APR_MUTEX, APR_LOCKALL, "mip", p);
   
  -    if (rc != APR_SUCCESS) {
  -        exit(1); /*XXX*/
  -    }
  -
  -    mip->parent = modperl_interp_new(p, NULL);
  -    mip->parent->perl = perl;
  -    mip->parent->mip_lock = mip->mip_lock;
  +    mip->ap_pool = p;
  +    mip->parent = modperl_interp_new(p, mip, NULL);
  +    aTHX = mip->parent->perl = perl;
  +    
  +    MUTEX_INIT(&mip->mip_lock);
  +    COND_INIT(&mip->available);
   
   #ifdef USE_ITHREADS
       mip->start = 3; /*XXX*/
  -    
  +    mip->max = 4;
  +    mip->max_spare = 3;
  +
       for (i=0; i<mip->start; i++) {
  -        modperl_interp_t *interp = modperl_interp_new(p, mip->parent);
  -        interp->perl = perl_clone(perl, TRUE);
  -        MpInterpCLONED_On(interp);
  +        modperl_interp_t *interp = modperl_interp_new(p, mip, perl);
   
  -        if (cur_interp) {
  -            cur_interp->next = interp;
  -            cur_interp = cur_interp->next;
  -        }
  -        else {
  -            mip->head = cur_interp = interp;
  -        }
  +        modperl_interp_pool_add(mip, interp);
       }
   #endif
   
       MP_TRACE_i(MP_FUNC, "parent == 0x%lx "
  -               "start=%d, min_spare=%d, max_spare=%d\n",
  +               "start=%d, max=%d, min_spare=%d, max_spare=%d\n",
                  (unsigned long)mip->parent, 
  -               mip->start, mip->min_spare, mip->max_spare);
  +               mip->max, mip->start, mip->min_spare, mip->max_spare);
   
       ap_register_cleanup(p, (void*)mip,
                           modperl_interp_pool_destroy, ap_null_cleanup);
  @@ -170,19 +240,34 @@
       scfg->mip = mip;
   }
   
  -
   ap_status_t modperl_interp_unselect(void *data)
   {
       modperl_interp_t *interp = (modperl_interp_t *)data;
  +    modperl_interp_pool_t *mip = interp->mip;
   
  -    ap_lock(interp->mip_lock);
  +    MUTEX_LOCK(&mip->mip_lock);
   
       MpInterpIN_USE_Off(interp);
   
  -    MP_TRACE_i(MP_FUNC, "0x%lx now available\n",
  -               (unsigned long)interp);
  +    mip->in_use--;
  +
  +    MP_TRACE_i(MP_FUNC, "0x%lx now available (%d in use, %d running)\n",
  +               (unsigned long)interp, mip->in_use, mip->size);
  +
  +    if (mip->in_use == (mip->max - 1)) {
  +        MP_TRACE_i(MP_FUNC, "broadcast available\n");
  +        COND_SIGNAL(&mip->available);
  +    }
  +    else if (mip->size > mip->max_spare) {
  +        MP_TRACE_i(MP_FUNC, "throttle down (max_spare=%d, %d running)\n",
  +                   mip->max_spare, mip->size);
  +        MUTEX_UNLOCK(&mip->mip_lock);
  +        modperl_interp_pool_remove(mip, interp);
  +        modperl_interp_destroy(interp);
  +        return APR_SUCCESS;
  +    }
   
  -    ap_unlock(interp->mip_lock);
  +    MUTEX_UNLOCK(&mip->mip_lock);
   
       return APR_SUCCESS;
   }
  
  
  
  1.3       +13 -3     modperl-2.0/src/modules/perl/modperl_interp.h
  
  Index: modperl_interp.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_interp.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- modperl_interp.h  2000/04/15 17:51:44     1.2
  +++ modperl_interp.h  2000/04/15 22:43:10     1.3
  @@ -2,7 +2,8 @@
   #define MODPERL_INTERP_H
   
   modperl_interp_t *modperl_interp_new(ap_pool_t *p,
  -                                     modperl_interp_t *parent);
  +                                     modperl_interp_pool_t *mip,
  +                                     PerlInterpreter *perl);
   
   void modperl_interp_destroy(modperl_interp_t *interp);
   
  @@ -10,11 +11,20 @@
   
   modperl_interp_t *modperl_interp_get(server_rec *s);
   
  +ap_status_t modperl_interp_unselect(void *data);
  +
  +int modperl_interp_select(request_rec *r);
  +
  +
   void modperl_interp_pool_init(server_rec *s, ap_pool_t *p,
                                 PerlInterpreter *perl);
   
  -ap_status_t modperl_interp_unselect(void *data);
  +ap_status_t modperl_interp_pool_destroy(void *data);
   
  -int modperl_interp_select(request_rec *r);
  +void modperl_interp_pool_add(modperl_interp_pool_t *mip,
  +                             modperl_interp_t *interp);
  +
  +void modperl_interp_pool_remove(modperl_interp_pool_t *mip,
  +                                modperl_interp_t *interp);
   
   #endif /* MODPERL_INTERP_H */
  
  
  
  1.3       +10 -5     modperl-2.0/src/modules/perl/modperl_types.h
  
  Index: modperl_types.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_types.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- modperl_types.h   2000/04/14 23:52:55     1.2
  +++ modperl_types.h   2000/04/15 22:43:10     1.3
  @@ -24,23 +24,28 @@
   /* mod_perl structures */
   
   typedef struct modperl_interp_t modperl_interp_t;
  +typedef struct modperl_interp_pool_t modperl_interp_pool_t;
   
   struct modperl_interp_t {
  -    ap_lock_t *mip_lock;
  +    modperl_interp_pool_t *mip;
       PerlInterpreter *perl;
       modperl_interp_t *next;
       int flags;
   };
   
  -typedef struct {
  -    ap_lock_t *mip_lock;
  +struct modperl_interp_pool_t {
  +    ap_pool_t *ap_pool;
  +    perl_mutex mip_lock;
  +    perl_cond available;
       int start; /* number of Perl intepreters to start (clone) */
       int min_spare; /* minimum number of spare Perl interpreters */
       int max_spare; /* maximum number of spare Perl interpreters */
       int size; /* current number of Perl interpreters */
  +    int max; /* maximum number of Perl interpreters */
  +    int in_use; /* number of Perl interpreters currrently in use */
       modperl_interp_t *parent; /* from which to perl_clone() */
  -    modperl_interp_t *head;
  -} modperl_interp_pool_t;
  +    modperl_interp_t *head, *tail;
  +};
   
   typedef struct {
       MpAV *handlers[MP_PROCESS_NUM_HANDLERS];
  
  
  

Reply via email to