[5/5] services: Use threadpool API instead of custom wait implementation.
Sebastian Lackner
sebastian at fds-team.de
Thu Aug 18 02:38:24 CDT 2016
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
I was planning to do this since a long time (to get rid of the MAXIMUM_WAIT_OBJECTS limitation),
but now I have a better reason. Following patches will spawn other asynchronous tasks and its
nice to use the threadpool API for that. Unfortunately we can't get rid of the critical section
because of M$s design flaws in the threadpool wait API. ;)
include/winbase.h | 6 +
programs/services/rpc.c | 177 ++++++++++++-------------------------------
programs/services/services.c | 9 +-
programs/services/services.h | 5 -
4 files changed, 66 insertions(+), 131 deletions(-)
diff --git a/include/winbase.h b/include/winbase.h
index 220a057..99e3107 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1710,6 +1710,9 @@ WINADVAPI BOOL WINAPI ClearEventLogW(HANDLE,LPCWSTR);
WINADVAPI BOOL WINAPI CloseEventLog(HANDLE);
WINBASEAPI BOOL WINAPI CloseHandle(HANDLE);
WINBASEAPI VOID WINAPI CloseThreadpool(PTP_POOL);
+WINBASEAPI VOID WINAPI CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP);
+WINBASEAPI VOID WINAPI CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP,BOOL,PVOID);
+WINBASEAPI VOID WINAPI CloseThreadpoolWait(PTP_WAIT);
WINBASEAPI VOID WINAPI CloseThreadpoolWork(PTP_WORK);
WINBASEAPI BOOL WINAPI CommConfigDialogA(LPCSTR,HWND,LPCOMMCONFIG);
WINBASEAPI BOOL WINAPI CommConfigDialogW(LPCWSTR,HWND,LPCOMMCONFIG);
@@ -1775,6 +1778,8 @@ WINADVAPI BOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR,P
WINADVAPI BOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR*,GUID*,BOOL,ULONG,HANDLE,PGENERIC_MAPPING);
WINADVAPI BOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR*,GUID**,ULONG,BOOL,ULONG,HANDLE,PGENERIC_MAPPING);
WINBASEAPI PTP_POOL WINAPI CreateThreadpool(PVOID);
+WINBASEAPI PTP_CLEANUP_GROUP WINAPI CreateThreadpoolCleanupGroup(void);
+WINBASEAPI PTP_WAIT WINAPI CreateThreadpoolWait(PTP_WAIT_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON);
WINBASEAPI PTP_WORK WINAPI CreateThreadpoolWork(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON);
WINBASEAPI BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION);
WINBASEAPI BOOL WINAPI CreateProcessW(LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
@@ -2510,6 +2515,7 @@ WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE,DWORD);
WINBASEAPI BOOL WINAPI SetThreadPriority(HANDLE,INT);
WINBASEAPI BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL);
WINADVAPI BOOL WINAPI SetThreadToken(PHANDLE,HANDLE);
+WINBASEAPI VOID WINAPI SetThreadpoolWait(PTP_WAIT,HANDLE,FILETIME *);
WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE,WAITORTIMERCALLBACK,PVOID,DWORD,DWORD,BOOL);
WINBASEAPI BOOL WINAPI SetTimeZoneInformation(const TIME_ZONE_INFORMATION *);
WINADVAPI BOOL WINAPI SetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWORD);
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 4cab79e..4c6301c 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -85,46 +85,51 @@ struct sc_lock
struct scmdatabase *db;
};
-static HANDLE timeout_queue_event;
-static CRITICAL_SECTION timeout_queue_cs;
-static CRITICAL_SECTION_DEBUG timeout_queue_cs_debug =
+static CRITICAL_SECTION shutdown_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
{
- 0, 0, &timeout_queue_cs,
- { &timeout_queue_cs_debug.ProcessLocksList, &timeout_queue_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": timeout_queue_cs") }
+ 0, 0, &shutdown_cs,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": shutdown_cs") }
};
-static CRITICAL_SECTION timeout_queue_cs = { &timeout_queue_cs_debug, -1, 0, 0, 0, 0 };
-static struct list timeout_queue = LIST_INIT(timeout_queue);
-struct timeout_queue_elem
-{
- struct list entry;
+static CRITICAL_SECTION shutdown_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+static BOOL service_shutdown;
- FILETIME time;
- struct process_entry *process;
-};
+static PTP_CLEANUP_GROUP cleanup_group;
+HANDLE exit_event;
-static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
+static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
+ TP_WAIT *wait, TP_WAIT_RESULT result)
{
- struct timeout_queue_elem *elem;
- ULARGE_INTEGER time;
+ struct process_entry *process = context;
+ if (result == WAIT_TIMEOUT) process_terminate(process);
+ release_process(process);
- if (!(elem = HeapAlloc(GetProcessHeap(), 0, sizeof(*elem))))
- return;
+ /* synchronize with CloseThreadpoolCleanupGroupMembers */
+ EnterCriticalSection(&shutdown_cs);
+ if (!service_shutdown) CloseThreadpoolWait(wait);
+ LeaveCriticalSection(&shutdown_cs);
+}
- elem->process = grab_process(process);
+static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
+{
+ TP_CALLBACK_ENVIRON environment;
+ LARGE_INTEGER timestamp;
+ TP_WAIT *wait;
+ FILETIME ft;
- GetSystemTimeAsFileTime(&elem->time);
- time.u.LowPart = elem->time.dwLowDateTime;
- time.u.HighPart = elem->time.dwHighDateTime;
- time.QuadPart += (ULONGLONG)timeout * 10000;
- elem->time.dwLowDateTime = time.u.LowPart;
- elem->time.dwHighDateTime = time.u.HighPart;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.CleanupGroup = cleanup_group;
- EnterCriticalSection(&timeout_queue_cs);
- list_add_head(&timeout_queue, &elem->entry);
- LeaveCriticalSection(&timeout_queue_cs);
+ timestamp.QuadPart = (ULONGLONG)timeout * -10000;
+ ft.dwLowDateTime = timestamp.u.LowPart;
+ ft.dwHighDateTime = timestamp.u.HighPart;
- SetEvent(timeout_queue_event);
+ if ((wait = CreateThreadpoolWait(terminate_callback, grab_process(process), &environment)))
+ SetThreadpoolWait(wait, process->process, &ft);
+ else
+ release_process(process);
}
static void free_service_strings(struct service_entry *old, struct service_entry *new)
@@ -1876,6 +1881,12 @@ DWORD RPC_Init(void)
WCHAR endpoint[] = SVCCTL_ENDPOINT;
DWORD err;
+ if (!(cleanup_group = CreateThreadpoolCleanupGroup()))
+ {
+ WINE_ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
+ return GetLastError();
+ }
+
if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
{
WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
@@ -1893,106 +1904,24 @@ DWORD RPC_Init(void)
WINE_ERR("RpcServerListen failed with error %u\n", err);
return err;
}
+
+ exit_event = __wine_make_process_system();
return ERROR_SUCCESS;
}
-DWORD events_loop(void)
+void RPC_Stop(void)
{
- struct timeout_queue_elem *iter, *iter_safe;
- DWORD err;
- HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
- DWORD timeout = INFINITE;
-
- wait_handles[0] = __wine_make_process_system();
- wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
- timeout_queue_event = wait_handles[1];
-
- SetEvent(g_hStartedEvent);
-
- WINE_TRACE("Entered main loop\n");
-
- do
- {
- DWORD num_handles = 2;
-
- /* monitor tracked process handles for process end */
- EnterCriticalSection(&timeout_queue_cs);
- LIST_FOR_EACH_ENTRY(iter, &timeout_queue, struct timeout_queue_elem, entry)
- {
- if(num_handles == MAXIMUM_WAIT_OBJECTS){
- WINE_TRACE("Exceeded maximum wait object count\n");
- break;
- }
- wait_handles[num_handles] = iter->process->process;
- num_handles++;
- }
- LeaveCriticalSection(&timeout_queue_cs);
-
- err = WaitForMultipleObjects(num_handles, wait_handles, FALSE, timeout);
- WINE_TRACE("Wait returned %d\n", err);
-
- if(err > WAIT_OBJECT_0 || err == WAIT_TIMEOUT)
- {
- FILETIME cur_time;
- ULARGE_INTEGER time;
- DWORD idx = 0;
-
- GetSystemTimeAsFileTime(&cur_time);
- time.u.LowPart = cur_time.dwLowDateTime;
- time.u.HighPart = cur_time.dwHighDateTime;
-
- EnterCriticalSection(&timeout_queue_cs);
- timeout = INFINITE;
- LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
- {
- if(CompareFileTime(&cur_time, &iter->time) >= 0 ||
- (err > WAIT_OBJECT_0 + 1 && idx == err - WAIT_OBJECT_0 - 2))
- {
- LeaveCriticalSection(&timeout_queue_cs);
- process_terminate(iter->process);
- EnterCriticalSection(&timeout_queue_cs);
-
- release_process(iter->process);
- list_remove(&iter->entry);
- HeapFree(GetProcessHeap(), 0, iter);
- }
- else
- {
- ULARGE_INTEGER time_diff;
-
- time_diff.u.LowPart = iter->time.dwLowDateTime;
- time_diff.u.HighPart = iter->time.dwHighDateTime;
- time_diff.QuadPart = (time_diff.QuadPart-time.QuadPart)/10000;
-
- if(time_diff.QuadPart < timeout)
- timeout = time_diff.QuadPart;
- }
- idx++;
- }
- LeaveCriticalSection(&timeout_queue_cs);
+ RpcMgmtStopServerListening(NULL);
+ RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
- if(timeout != INFINITE)
- timeout += 1000;
- }
- } while (err != WAIT_OBJECT_0);
+ /* synchronize with CloseThreadpoolWait */
+ EnterCriticalSection(&shutdown_cs);
+ service_shutdown = TRUE;
+ LeaveCriticalSection(&shutdown_cs);
- WINE_TRACE("Object signaled - wine shutdown\n");
- EnterCriticalSection(&timeout_queue_cs);
- LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
- {
- LeaveCriticalSection(&timeout_queue_cs);
- process_terminate(iter->process);
- EnterCriticalSection(&timeout_queue_cs);
-
- release_process(iter->process);
- list_remove(&iter->entry);
- HeapFree(GetProcessHeap(), 0, iter);
- }
- LeaveCriticalSection(&timeout_queue_cs);
-
- CloseHandle(wait_handles[0]);
- CloseHandle(wait_handles[1]);
- return ERROR_SUCCESS;
+ CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
+ CloseThreadpoolCleanupGroup(cleanup_group);
+ CloseHandle(exit_event);
}
void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
diff --git a/programs/services/services.c b/programs/services/services.c
index 1092a25..36ceae8 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -36,7 +36,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(service);
-HANDLE g_hStartedEvent;
struct scmdatabase *active_database;
DWORD service_pipe_timeout = 10000;
@@ -990,10 +989,10 @@ int main(int argc, char *argv[])
'C','o','n','t','r','o','l','\\',
'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
- HANDLE htok;
+ HANDLE started_event, htok;
DWORD err;
- g_hStartedEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
+ started_event = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &htok))
{
@@ -1019,8 +1018,10 @@ int main(int argc, char *argv[])
if ((err = RPC_Init()) == ERROR_SUCCESS)
{
scmdatabase_autostart_services(active_database);
- events_loop();
+ SetEvent(started_event);
+ WaitForSingleObject(exit_event, INFINITE);
scmdatabase_wait_terminate(active_database);
+ RPC_Stop();
}
scmdatabase_destroy(active_database);
if (env)
diff --git a/programs/services/services.h b/programs/services/services.h
index fb1374e..417efcd 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -98,13 +98,12 @@ void release_process(struct process_entry *process);
BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result);
void process_terminate(struct process_entry *process);
-extern HANDLE g_hStartedEvent;
-
extern DWORD service_pipe_timeout;
extern DWORD service_kill_timeout;
+extern HANDLE exit_event;
DWORD RPC_Init(void);
-DWORD events_loop(void);
+void RPC_Stop(void);
/* from utils.c */
LPWSTR strdupW(LPCWSTR str);
--
2.9.0
More information about the wine-patches
mailing list