diff --git a/src/3proxy.c b/src/3proxy.c index 54a982d..ff7c881 100644 --- a/src/3proxy.c +++ b/src/3proxy.c @@ -74,13 +74,8 @@ void __stdcall CommandHandler( DWORD dwCommand ) SetStatus( SERVICE_STOP_PENDING, 0, 1 ); conf.timetoexit = 1; conf.paused++; - Sleep(2000); - SetStatus( SERVICE_STOPPED, 0, 0 ); -#ifdef WITH_ODBC - _3proxy_mutex_lock(&log_mutex); - close_sql(); - _3proxy_mutex_unlock(&log_mutex); -#endif + /* ServiceMain() reports the service stopped once cyclestep() has + seen this and the services are done */ break; case SERVICE_CONTROL_PAUSE: SetStatus( SERVICE_PAUSE_PENDING, 0, 1 ); @@ -106,6 +101,13 @@ void __stdcall ServiceMain(int argc, unsigned char* argv[] ) SetStatus( SERVICE_START_PENDING, 0, 1 ); SetStatus( SERVICE_RUNNING, 0, 0 ); cyclestep(); +#ifdef WITH_ODBC + _3proxy_mutex_lock(&log_mutex); + close_sql(); + _3proxy_mutex_unlock(&log_mutex); +#endif + /* the last thing: the process may be ended once this is reported */ + SetStatus( SERVICE_STOPPED, 0, 0 ); } #endif @@ -240,6 +242,39 @@ void dumpcounters(struct trafcount *tlin, int counterd){ } } +/* Lets the services finish before the process exits, for EXITWAIT ms at + most: each one waits for its connections, and a connection may hang on + its peer. Posts left over from reloads are consumed on the way, the + count decides. */ +#define EXITWAIT 3000 +static unsigned long nowms(void){ +#ifdef _WIN32 + return (unsigned long)GetTickCount(); +#else + struct timeval tv; + + gettimeofday(&tv, NULL); + return (unsigned long)tv.tv_sec * 1000 + tv.tv_usec / 1000; +#endif +} + +static void waitservices(void){ + unsigned long start = nowms(), passed; + + for(;;){ + int n; + + _3proxy_mutex_lock(&runningservices_mutex); + n = runningservices; + _3proxy_mutex_unlock(&runningservices_mutex); + if(!n) return; + /* a clock set back makes this huge, which ends the wait as well */ + passed = nowms() - start; + if(passed >= EXITWAIT) return; + if(_3proxy_sem_timedlock(serviceexited, (unsigned)(EXITWAIT - passed))) return; + } +} + void cyclestep(void){ struct tm *tm; time_t minutecounter; @@ -336,9 +371,7 @@ void cyclestep(void){ if(conf.timetoexit){ conf.paused++; doschedule(); - usleep(SLEEPTIME*999); - usleep(SLEEPTIME*999); - usleep(SLEEPTIME*999); + waitservices(); return; } @@ -517,6 +550,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int } _3proxy_mutex_init(&config_mutex); + _3proxy_mutex_init(&runningservices_mutex); _3proxy_mutex_init(&bandlim_mutex); _3proxy_mutex_init(&connlim_mutex); _3proxy_mutex_init(&tc_mutex); @@ -524,7 +558,7 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int #ifndef NORADIUS _3proxy_mutex_init(&rad_mutex); #endif - if(_3proxy_sem_init(conf.threadinit, 1, 1)){ + if(_3proxy_sem_init(conf.threadinit, 1, 1) || _3proxy_sem_init_timed(serviceexited, 0, 0x7fffffff)){ fprintf(stderr, "semaphore init failed\n"); return 1; } diff --git a/src/conf.c b/src/conf.c index de2004f..31d4e85 100644 --- a/src/conf.c +++ b/src/conf.c @@ -38,6 +38,9 @@ _3proxy_mutex_t bandlim_mutex; _3proxy_mutex_t connlim_mutex; _3proxy_mutex_t tc_mutex; _3proxy_mutex_t config_mutex; +int runningservices = 0; +_3proxy_mutex_t runningservices_mutex; +_3proxy_sem_t serviceexited; int haveerror = 0; int linenum = 0; @@ -76,7 +79,18 @@ DWORD WINAPI startsrv(LPVOID data) { void * startsrv(void * data) { #endif struct child *d = (struct child *)data; + + /* counted here rather than where the service is listed, so every way + out of it is counted too; start_proxy_thread() waits for the service + to start, so it is counted by the time that returns */ + _3proxy_mutex_lock(&runningservices_mutex); + runningservices++; + _3proxy_mutex_unlock(&runningservices_mutex); mainfunc(d->argc, (char **)d->argv); + _3proxy_mutex_lock(&runningservices_mutex); + runningservices--; + _3proxy_mutex_unlock(&runningservices_mutex); + _3proxy_sem_unlock(serviceexited); return 0; } diff --git a/src/proxy.h b/src/proxy.h index cf1e5e6..7328bc5 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -467,6 +467,10 @@ struct dictionary; struct node; struct property; extern _3proxy_mutex_t config_mutex; +/* services running, and a post each time one of them has finished */ +extern int runningservices; +extern _3proxy_mutex_t runningservices_mutex; +extern _3proxy_sem_t serviceexited; extern _3proxy_mutex_t bandlim_mutex; extern _3proxy_mutex_t connlim_mutex; extern _3proxy_mutex_t tc_mutex;