Andrew Eikum : advapi32: Also wait on services without a control thread during shutdown.
Alexandre Julliard
julliard at winehq.org
Tue Feb 6 15:55:51 CST 2018
Module: wine
Branch: master
Commit: e5294a7414ca81c4761c00421cd7d59d9b83caa8
URL: https://source.winehq.org/git/wine.git/?a=commit;h=e5294a7414ca81c4761c00421cd7d59d9b83caa8
Author: Andrew Eikum <aeikum at codeweavers.com>
Date: Tue Feb 6 10:43:57 2018 -0600
advapi32: Also wait on services without a control thread during shutdown.
Tested service messages during OS shutdown manually on Windows 7.
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/advapi32/service.c | 94 +++++++++++++++++++++++++++++++------------------
1 file changed, 59 insertions(+), 35 deletions(-)
diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 7d66326..70907e1 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -529,6 +529,63 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
return 1;
}
+/* wait for services which accept this type of message to become STOPPED */
+static void handle_shutdown_msg(DWORD msg, DWORD accept)
+{
+ SERVICE_STATUS st;
+ SERVICE_PRESHUTDOWN_INFO spi;
+ DWORD i, n = 0, sz, timeout = 2000;
+ ULONGLONG stop_time;
+ BOOL res, done = TRUE;
+ SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
+
+ EnterCriticalSection( &service_cs );
+ for (i = 0; i < nb_services; i++)
+ {
+ res = QueryServiceStatus( services[i]->full_access_handle, &st );
+ if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
+ continue;
+
+ done = FALSE;
+
+ if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
+ {
+ res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
+ (LPBYTE)&spi, sizeof(spi), &sz );
+ if (res)
+ {
+ FIXME( "service should be able to delay shutdown\n" );
+ timeout = max( spi.dwPreshutdownTimeout, timeout );
+ }
+ }
+
+ service_handle_control( services[i], msg, NULL, 0 );
+ wait_handles[n++] = services[i]->full_access_handle;
+ }
+ LeaveCriticalSection( &service_cs );
+
+ /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
+ timeout = min( timeout, 3000 );
+ stop_time = GetTickCount64() + timeout;
+
+ while (!done && GetTickCount64() < stop_time)
+ {
+ done = TRUE;
+ for (i = 0; i < n; i++)
+ {
+ res = QueryServiceStatus( wait_handles[i], &st );
+ if (!res || st.dwCurrentState == SERVICE_STOPPED)
+ continue;
+
+ done = FALSE;
+ Sleep( 100 );
+ break;
+ }
+ }
+
+ HeapFree( GetProcessHeap(), 0, wait_handles );
+}
+
/******************************************************************************
* service_run_main_thread
*/
@@ -583,41 +640,8 @@ static BOOL service_run_main_thread(void)
ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
if (!ret) /* system process event */
{
- SERVICE_STATUS st;
- SERVICE_PRESHUTDOWN_INFO spi;
- DWORD timeout = 5000;
- BOOL res;
-
- EnterCriticalSection( &service_cs );
- n = 0;
- for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
- {
- if (!services[i]->thread) continue;
-
- res = QueryServiceStatus(services[i]->full_access_handle, &st);
- ret = ERROR_SUCCESS;
- if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
- {
- res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
- (LPBYTE)&spi, sizeof(spi), &i );
- if (res)
- {
- FIXME("service should be able to delay shutdown\n");
- timeout += spi.dwPreshutdownTimeout;
- ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
- wait_handles[n++] = services[i]->thread;
- }
- }
- else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
- {
- ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
- wait_handles[n++] = services[i]->thread;
- }
- }
- LeaveCriticalSection( &service_cs );
-
- TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
- WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
+ handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
+ handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
ExitProcess(0);
}
else if (ret == 1)
More information about the wine-cvs
mailing list