Use a Windows event to stop tinc when running as a service.
Currently, when the tinc service handler callback (which runs in a separate thread) receives a service shutdown request, it calls event_exit() to request the event loop to exit. This approach has a few issues: - The event loop will only notice the exit request when the next event fires. This slows down tinc service shutdown. In some extreme cases (DeviceStandby enabled, long PingTimeout and no connections), shutdown can take ages. - Strictly speaking, because of the absence of memory barriers, there is no guarantee that the event loop will even notice an exit request coming from another thread. I suppose marking the "running" variable as "volatile" is supposed to alleviate that, but it's unclear whether that provides any guarantees with modern systems and compilers. This commit fixes the issue by leveraging the new event loop Windows interface, using a custom Windows event that is manually set when shutdown is requested.
This commit is contained in:
parent
2f9a1d4ab5
commit
ffbc99558c
2 changed files with 17 additions and 3 deletions
|
|
@ -108,6 +108,8 @@ static bool install_service(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static io_t stop_io;
|
||||
|
||||
DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
||||
switch(request) {
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
|
|
@ -124,16 +126,25 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
|||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
event_exit();
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwWaitHint = 1000;
|
||||
status.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
if (WSASetEvent(stop_io.event) == FALSE)
|
||||
abort();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static void stop_handler(void *data, int flags) {
|
||||
event_exit();
|
||||
}
|
||||
|
||||
VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
|
||||
extern int main2(int argc, char **argv);
|
||||
|
||||
io_add_event(&stop_io, stop_handler, NULL, WSACreateEvent());
|
||||
if (stop_io.event == FALSE)
|
||||
abort();
|
||||
|
||||
status.dwServiceType = SERVICE_WIN32;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
status.dwWin32ExitCode = 0;
|
||||
|
|
@ -160,6 +171,9 @@ VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
|
|||
SetServiceStatus(statushandle, &status);
|
||||
}
|
||||
|
||||
if (WSACloseEvent(stop_io.event) == FALSE)
|
||||
abort();
|
||||
io_del(&stop_io);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue