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];