diff --git a/src/mainconf.c b/src/mainconf.c index b4dbf74..be25534 100644 --- a/src/mainconf.c +++ b/src/mainconf.c @@ -152,6 +152,11 @@ static void srvstrings(struct srvstart *s){ /* Releases what the preparation and the run took, s itself excepted. */ static void srvdiscard(struct srvstart *s){ + /* a slot taken for a service which never ran: srvfree() waits for all */ + if(s->haveslot){ + _3proxy_sem_unlock(s->srv.childslots); + s->haveslot = 0; + } srvfree(&s->srv); srvstrings(s); } @@ -245,6 +250,7 @@ static int srvprepare(struct srvstart *s, int argc, char **argv){ s->cbc_string = s->cbl_string = NULL; s->iscbc = s->iscbl = 0; + s->haveslot = 0; #ifdef STDMAIN #ifndef _WIN32 s->inetd = 0; diff --git a/src/mainlisten.c b/src/mainlisten.c index fd682ab..f9f6085 100644 --- a/src/mainlisten.c +++ b/src/mainlisten.c @@ -374,6 +374,11 @@ void mainclaim(void *service){ struct srvparam *srv = &s->srv; struct listener *l, *found = NULL, *newl; + /* The slot it keeps for its next client taken first: once on the + listener, it is where the clients of older services move after a reload + (reattach()), which must find that slot taken, as it is once the service + accepts, and not take more than the others of its maxconn. */ + if(!s->isudp && !s->haveslot && !_3proxy_sem_timedlock(srv->childslots, 0)) s->haveslot = 1; /* made beforehand, as the mutex is held from finding a listener to joining it, lest its last service let go of it meanwhile */ if((newl = malloc(sizeof(*newl)))){ diff --git a/src/proxymain.c b/src/proxymain.c index b38afe3..f0a8158 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -26,6 +26,9 @@ struct srvstart { struct clientparam defparam; unsigned char *cbc_string, *cbl_string; int isudp, iscbc, iscbl; + /* the slot a TCP service keeps for its next client, taken before it can + be found on its listener: srvrun() takes it over */ + int haveslot; const struct udpservice *udp; #ifndef _WIN32 pthread_attr_t pa; @@ -121,9 +124,11 @@ static int srvrun(struct srvstart *s); static int srvrun(struct srvstart *s){ struct srvparam *srv = &s->srv; struct clientparam *defparam = &s->defparam; - int res = 0, haveslot = 0; + int res = 0, haveslot = s->haveslot; /* -r: a TCP service connects out for each client instead of listening */ int connectback = !s->isudp && s->iscbc; + + s->haveslot = 0; #ifndef _WIN32 pthread_attr_init(&s->pa); pthread_attr_setstacksize(&s->pa,threadstacksize(srv->stacksize));