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:
parent
6fc42341ec
commit
9dfa1022e9
|
@ -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);
|
||||
|
|
|
@ -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 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)
|
||||
{
|
||||
struct timeout_queue_elem *elem;
|
||||
ULARGE_INTEGER time;
|
||||
TP_CALLBACK_ENVIRON environment;
|
||||
LARGE_INTEGER timestamp;
|
||||
TP_WAIT *wait;
|
||||
FILETIME ft;
|
||||
|
||||
if (!(elem = HeapAlloc(GetProcessHeap(), 0, sizeof(*elem))))
|
||||
return;
|
||||
memset(&environment, 0, sizeof(environment));
|
||||
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);
|
||||
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;
|
||||
|
||||
EnterCriticalSection(&timeout_queue_cs);
|
||||
list_add_head(&timeout_queue, &elem->entry);
|
||||
LeaveCriticalSection(&timeout_queue_cs);
|
||||
|
||||
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;
|
||||
RpcMgmtStopServerListening(NULL);
|
||||
RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
|
||||
|
||||
wait_handles[0] = __wine_make_process_system();
|
||||
wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
timeout_queue_event = wait_handles[1];
|
||||
/* synchronize with CloseThreadpoolWait */
|
||||
EnterCriticalSection(&shutdown_cs);
|
||||
service_shutdown = TRUE;
|
||||
LeaveCriticalSection(&shutdown_cs);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
|
||||
CloseThreadpoolCleanupGroup(cleanup_group);
|
||||
CloseHandle(exit_event);
|
||||
}
|
||||
|
||||
void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue