services: Use threadpool API instead of custom wait implementation.

Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Sebastian Lackner 2016-08-18 09:38:24 +02:00 committed by Alexandre Julliard
parent 6fc42341ec
commit 9dfa1022e9
4 changed files with 67 additions and 132 deletions

View File

@ -1710,6 +1710,9 @@ WINADVAPI BOOL WINAPI ClearEventLogW(HANDLE,LPCWSTR);
WINADVAPI BOOL WINAPI CloseEventLog(HANDLE); WINADVAPI BOOL WINAPI CloseEventLog(HANDLE);
WINBASEAPI BOOL WINAPI CloseHandle(HANDLE); WINBASEAPI BOOL WINAPI CloseHandle(HANDLE);
WINBASEAPI VOID WINAPI CloseThreadpool(PTP_POOL); 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 VOID WINAPI CloseThreadpoolWork(PTP_WORK);
WINBASEAPI BOOL WINAPI CommConfigDialogA(LPCSTR,HWND,LPCOMMCONFIG); WINBASEAPI BOOL WINAPI CommConfigDialogA(LPCSTR,HWND,LPCOMMCONFIG);
WINBASEAPI BOOL WINAPI CommConfigDialogW(LPCWSTR,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 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); 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_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 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 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); 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 SetThreadPriority(HANDLE,INT);
WINBASEAPI BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL); WINBASEAPI BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL);
WINADVAPI BOOL WINAPI SetThreadToken(PHANDLE,HANDLE); 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 HANDLE WINAPI SetTimerQueueTimer(HANDLE,WAITORTIMERCALLBACK,PVOID,DWORD,DWORD,BOOL);
WINBASEAPI BOOL WINAPI SetTimeZoneInformation(const TIME_ZONE_INFORMATION *); WINBASEAPI BOOL WINAPI SetTimeZoneInformation(const TIME_ZONE_INFORMATION *);
WINADVAPI BOOL WINAPI SetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWORD); WINADVAPI BOOL WINAPI SetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWORD);

View File

@ -85,46 +85,51 @@ struct sc_lock
struct scmdatabase *db; struct scmdatabase *db;
}; };
static HANDLE timeout_queue_event; static CRITICAL_SECTION shutdown_cs;
static CRITICAL_SECTION timeout_queue_cs; static CRITICAL_SECTION_DEBUG critsect_debug =
static CRITICAL_SECTION_DEBUG timeout_queue_cs_debug =
{ {
0, 0, &timeout_queue_cs, 0, 0, &shutdown_cs,
{ &timeout_queue_cs_debug.ProcessLocksList, &timeout_queue_cs_debug.ProcessLocksList }, { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": timeout_queue_cs") } 0, 0, { (DWORD_PTR)(__FILE__ ": shutdown_cs") }
}; };
static CRITICAL_SECTION timeout_queue_cs = { &timeout_queue_cs_debug, -1, 0, 0, 0, 0 }; static CRITICAL_SECTION shutdown_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static struct list timeout_queue = LIST_INIT(timeout_queue); static BOOL service_shutdown;
struct timeout_queue_elem
{
struct list entry;
FILETIME time; static PTP_CLEANUP_GROUP cleanup_group;
struct process_entry *process; HANDLE exit_event;
};
static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
TP_WAIT *wait, TP_WAIT_RESULT result)
{
struct process_entry *process = context;
if (result == WAIT_TIMEOUT) process_terminate(process);
release_process(process);
/* synchronize with CloseThreadpoolCleanupGroupMembers */
EnterCriticalSection(&shutdown_cs);
if (!service_shutdown) CloseThreadpoolWait(wait);
LeaveCriticalSection(&shutdown_cs);
}
static void terminate_after_timeout(struct process_entry *process, DWORD timeout) static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
{ {
struct timeout_queue_elem *elem; TP_CALLBACK_ENVIRON environment;
ULARGE_INTEGER time; LARGE_INTEGER timestamp;
TP_WAIT *wait;
FILETIME ft;
if (!(elem = HeapAlloc(GetProcessHeap(), 0, sizeof(*elem)))) memset(&environment, 0, sizeof(environment));
return; environment.Version = 1;
environment.CleanupGroup = cleanup_group;
elem->process = grab_process(process); timestamp.QuadPart = (ULONGLONG)timeout * -10000;
ft.dwLowDateTime = timestamp.u.LowPart;
ft.dwHighDateTime = timestamp.u.HighPart;
GetSystemTimeAsFileTime(&elem->time); if ((wait = CreateThreadpoolWait(terminate_callback, grab_process(process), &environment)))
time.u.LowPart = elem->time.dwLowDateTime; SetThreadpoolWait(wait, process->process, &ft);
time.u.HighPart = elem->time.dwHighDateTime; else
time.QuadPart += (ULONGLONG)timeout * 10000; release_process(process);
elem->time.dwLowDateTime = time.u.LowPart;
elem->time.dwHighDateTime = time.u.HighPart;
EnterCriticalSection(&timeout_queue_cs);
list_add_head(&timeout_queue, &elem->entry);
LeaveCriticalSection(&timeout_queue_cs);
SetEvent(timeout_queue_event);
} }
static void free_service_strings(struct service_entry *old, struct service_entry *new) 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; WCHAR endpoint[] = SVCCTL_ENDPOINT;
DWORD err; 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) if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
{ {
WINE_ERR("RpcServerUseProtseq failed with error %u\n", err); 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); WINE_ERR("RpcServerListen failed with error %u\n", err);
return err; return err;
} }
exit_event = __wine_make_process_system();
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
DWORD events_loop(void) void RPC_Stop(void)
{ {
struct timeout_queue_elem *iter, *iter_safe; RpcMgmtStopServerListening(NULL);
DWORD err; RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
DWORD timeout = INFINITE;
wait_handles[0] = __wine_make_process_system(); /* synchronize with CloseThreadpoolWait */
wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL); EnterCriticalSection(&shutdown_cs);
timeout_queue_event = wait_handles[1]; service_shutdown = TRUE;
LeaveCriticalSection(&shutdown_cs);
SetEvent(g_hStartedEvent); CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
CloseThreadpoolCleanupGroup(cleanup_group);
WINE_TRACE("Entered main loop\n"); CloseHandle(exit_event);
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);
if(timeout != INFINITE)
timeout += 1000;
}
} while (err != WAIT_OBJECT_0);
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;
} }
void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle) void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)

View File

@ -36,7 +36,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(service); WINE_DEFAULT_DEBUG_CHANNEL(service);
HANDLE g_hStartedEvent;
struct scmdatabase *active_database; struct scmdatabase *active_database;
DWORD service_pipe_timeout = 10000; DWORD service_pipe_timeout = 10000;
@ -990,10 +989,10 @@ int main(int argc, char *argv[])
'C','o','n','t','r','o','l','\\', 'C','o','n','t','r','o','l','\\',
'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0}; 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT; static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
HANDLE htok; HANDLE started_event, htok;
DWORD err; 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)) if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &htok))
{ {
@ -1019,8 +1018,10 @@ int main(int argc, char *argv[])
if ((err = RPC_Init()) == ERROR_SUCCESS) if ((err = RPC_Init()) == ERROR_SUCCESS)
{ {
scmdatabase_autostart_services(active_database); scmdatabase_autostart_services(active_database);
events_loop(); SetEvent(started_event);
WaitForSingleObject(exit_event, INFINITE);
scmdatabase_wait_terminate(active_database); scmdatabase_wait_terminate(active_database);
RPC_Stop();
} }
scmdatabase_destroy(active_database); scmdatabase_destroy(active_database);
if (env) if (env)

View File

@ -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); BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result);
void process_terminate(struct process_entry *process); void process_terminate(struct process_entry *process);
extern HANDLE g_hStartedEvent;
extern DWORD service_pipe_timeout; extern DWORD service_pipe_timeout;
extern DWORD service_kill_timeout; extern DWORD service_kill_timeout;
extern HANDLE exit_event;
DWORD RPC_Init(void); DWORD RPC_Init(void);
DWORD events_loop(void); void RPC_Stop(void);
/* from utils.c */ /* from utils.c */
LPWSTR strdupW(LPCWSTR str); LPWSTR strdupW(LPCWSTR str);