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);
|
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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue