Event loops: started once when services' first clients come at once

loopsstart() runs on the thread of the service whose client is the first
one to be served on a loop, not on the configuration's thread: two
services given their first clients at the same time could each initialize
its mutex, take it, and start loops of their own. A loop of the second
array was then given to a thread of the first one as well: two threads
ran one loop, and its timers and fibers were taken by both (crashes in
the timers' heap, seen on Windows under load).

The mutex is a global one now, made at startup with the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-27 14:40:30 +03:00
parent 97ab683654
commit 63cfcafbc5
4 changed files with 12 additions and 13 deletions

View File

@ -491,6 +491,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
_3proxy_mutex_init(&bandlim_mutex); _3proxy_mutex_init(&bandlim_mutex);
_3proxy_mutex_init(&connlim_mutex); _3proxy_mutex_init(&connlim_mutex);
_3proxy_mutex_init(&tc_mutex); _3proxy_mutex_init(&tc_mutex);
_3proxy_mutex_init(&loops_mutex);
_3proxy_mutex_init(&tpool.mutex); _3proxy_mutex_init(&tpool.mutex);
#ifndef NORADIUS #ifndef NORADIUS
_3proxy_mutex_init(&rad_mutex); _3proxy_mutex_init(&rad_mutex);

View File

@ -37,6 +37,8 @@ void transparent_install(void);
_3proxy_mutex_t bandlim_mutex; _3proxy_mutex_t bandlim_mutex;
_3proxy_mutex_t connlim_mutex; _3proxy_mutex_t connlim_mutex;
_3proxy_mutex_t tc_mutex; _3proxy_mutex_t tc_mutex;
/* the event loops, started by the first client served on one */
_3proxy_mutex_t loops_mutex;
_3proxy_mutex_t config_mutex; _3proxy_mutex_t config_mutex;
int runningservices = 0; int runningservices = 0;
_3proxy_mutex_t runningservices_mutex; _3proxy_mutex_t runningservices_mutex;

View File

@ -85,8 +85,6 @@ struct loopjob {
static struct looper *loopers; static struct looper *loopers;
static unsigned nloopers, nextlooper; static unsigned nloopers, nextlooper;
static int loopsfailed; static int loopsfailed;
static _3proxy_mutex_t loopers_mutex;
static int loopers_mutex_init;
/* the loop of this thread, NULL but in a loop's thread */ /* the loop of this thread, NULL but in a loop's thread */
static LTLS struct looper *curlooper; static LTLS struct looper *curlooper;
@ -1111,20 +1109,17 @@ static int loopsstart(void){
if(nloopers) return 0; if(nloopers) return 0;
if(loopsfailed) return 1; if(loopsfailed) return 1;
if(!loopers_mutex_init){ /* the first clients of services may come at once, each from the
/* the first services start from the configuration's thread */ thread of its service */
_3proxy_mutex_init(&loopers_mutex); _3proxy_mutex_lock(&loops_mutex);
loopers_mutex_init = 1;
}
_3proxy_mutex_lock(&loopers_mutex);
if(nloopers || loopsfailed){ if(nloopers || loopsfailed){
_3proxy_mutex_unlock(&loopers_mutex); _3proxy_mutex_unlock(&loops_mutex);
return loopsfailed; return loopsfailed;
} }
n = runconf->loops? (unsigned)runconf->loops : ncpus(); n = runconf->loops? (unsigned)runconf->loops : ncpus();
if(!fiberusable() || !(loopers = calloc(n, sizeof(*loopers)))){ if(!fiberusable() || !(loopers = calloc(n, sizeof(*loopers)))){
loopsfailed = 1; loopsfailed = 1;
_3proxy_mutex_unlock(&loopers_mutex); _3proxy_mutex_unlock(&loops_mutex);
return 1; return 1;
} }
for(i = 0; i < n; i++){ for(i = 0; i < n; i++){
@ -1166,7 +1161,7 @@ static int loopsstart(void){
#endif #endif
fiberpollfunc = fiberpoll; fiberpollfunc = fiberpoll;
} }
_3proxy_mutex_unlock(&loopers_mutex); _3proxy_mutex_unlock(&loops_mutex);
return !i; return !i;
} }
@ -1196,9 +1191,9 @@ static struct loopjob *loopjobnew(size_t stacksize){
static void loopspawn(struct loopjob *job, struct clientparam *param){ static void loopspawn(struct loopjob *job, struct clientparam *param){
struct looper *lp; struct looper *lp;
_3proxy_mutex_lock(&loopers_mutex); _3proxy_mutex_lock(&loops_mutex);
lp = loopers + (nextlooper++ % nloopers); lp = loopers + (nextlooper++ % nloopers);
_3proxy_mutex_unlock(&loopers_mutex); _3proxy_mutex_unlock(&loops_mutex);
job->param = param; job->param = param;
looppost(&lp->l, &job->m); looppost(&lp->l, &job->m);
} }

View File

@ -611,6 +611,7 @@ extern _3proxy_sem_t serviceexited;
extern _3proxy_mutex_t bandlim_mutex; extern _3proxy_mutex_t bandlim_mutex;
extern _3proxy_mutex_t connlim_mutex; extern _3proxy_mutex_t connlim_mutex;
extern _3proxy_mutex_t tc_mutex; extern _3proxy_mutex_t tc_mutex;
extern _3proxy_mutex_t loops_mutex;
extern _3proxy_mutex_t log_mutex; extern _3proxy_mutex_t log_mutex;
extern _3proxy_mutex_t rad_mutex; extern _3proxy_mutex_t rad_mutex;
extern struct datatype datatypes[64]; extern struct datatype datatypes[64];