diff --git a/programs/services/rpc.c b/programs/services/rpc.c index ece8dce8199..933f18d1af2 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -773,8 +773,8 @@ DWORD __cdecl svcctl_SetServiceStatus( if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED) run_after_timeout(service_terminate, service->service_entry, service_kill_timeout); - else if (service->service_entry->status_changed_event) - SetEvent(service->service_entry->status_changed_event); + else if (service->service_entry->process->status_changed_event) + SetEvent(service->service_entry->process->status_changed_event); return ERROR_SUCCESS; } @@ -984,26 +984,26 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d } /****************************************************************************** - * service_send_command + * process_send_command */ -BOOL service_send_command( struct service_entry *service, const void *data, DWORD size, DWORD *result ) +BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result) { OVERLAPPED overlapped; DWORD count, ret; BOOL r; - overlapped.hEvent = service->overlapped_event; - r = WriteFile(service->control_pipe, data, size, &count, &overlapped); + overlapped.hEvent = process->overlapped_event; + r = WriteFile(process->control_pipe, data, size, &count, &overlapped); if (!r && GetLastError() == ERROR_IO_PENDING) { - ret = WaitForSingleObject( service->overlapped_event, service_pipe_timeout ); + ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout); if (ret == WAIT_TIMEOUT) { WINE_ERR("sending command timed out\n"); *result = ERROR_SERVICE_REQUEST_TIMEOUT; return FALSE; } - r = GetOverlappedResult(service->control_pipe, &overlapped, &count, FALSE); + r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE); } if (!r || count != size) { @@ -1011,17 +1011,17 @@ BOOL service_send_command( struct service_entry *service, const void *data, DWOR *result = (!r ? GetLastError() : ERROR_WRITE_FAULT); return FALSE; } - r = ReadFile(service->control_pipe, result, sizeof *result, &count, &overlapped); + r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped); if (!r && GetLastError() == ERROR_IO_PENDING) { - ret = WaitForSingleObject( service->overlapped_event, service_pipe_timeout ); + ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout); if (ret == WAIT_TIMEOUT) { WINE_ERR("receiving command result timed out\n"); *result = ERROR_SERVICE_REQUEST_TIMEOUT; return FALSE; } - r = GetOverlappedResult(service->control_pipe, &overlapped, &count, FALSE); + r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE); } if (!r || count != sizeof *result) { @@ -1054,7 +1054,7 @@ static BOOL service_send_control(struct service_entry *service, DWORD dwControl, ssi->name_size = strlenW(service->name) + 1; strcpyW( ssi->data, service->name ); - r = service_send_command( service, ssi, ssi->total_size, result ); + r = process_send_command(service->process, ssi, ssi->total_size, result); HeapFree( GetProcessHeap(), 0, ssi ); return r; } @@ -1170,7 +1170,7 @@ DWORD __cdecl svcctl_ControlService( if (dwControl == SERVICE_CONTROL_STOP) service->service_entry->force_shutdown = TRUE; - control_mutex = service->service_entry->control_mutex; + control_mutex = service->service_entry->process->control_mutex; service_unlock(service->service_entry); ret = WaitForSingleObject(control_mutex, 30000); @@ -1926,7 +1926,7 @@ DWORD events_loop(void) WINE_TRACE("Exceeded maximum wait object count\n"); break; } - wait_handles[num_handles] = iter->service_entry->process; + wait_handles[num_handles] = iter->service_entry->process->process; num_handles++; } LeaveCriticalSection(&timeout_queue_cs); diff --git a/programs/services/services.c b/programs/services/services.c index 02a46f9f657..c49dad372f8 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -68,8 +68,30 @@ static const WCHAR SZ_DESCRIPTION[] = {'D','e','s','c','r','i','p','t','i' static const WCHAR SZ_PRESHUTDOWN[] = {'P','r','e','s','h','u','t','d','o','w','n','T','i','m','e','o','u','t',0}; static const WCHAR SZ_WOW64[] = {'W','O','W','6','4',0}; +static DWORD process_create(struct process_entry **entry) +{ + *entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**entry)); + if (!*entry) + return ERROR_NOT_ENOUGH_SERVER_MEMORY; + (*entry)->control_pipe = INVALID_HANDLE_VALUE; + /* all other fields are zero */ + return ERROR_SUCCESS; +} + +static void free_process_entry(struct process_entry *entry) +{ + CloseHandle(entry->process); + CloseHandle(entry->control_mutex); + CloseHandle(entry->control_pipe); + CloseHandle(entry->overlapped_event); + CloseHandle(entry->status_changed_event); + HeapFree(GetProcessHeap(), 0, entry); +} + DWORD service_create(LPCWSTR name, struct service_entry **entry) { + DWORD err; + *entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**entry)); if (!*entry) return ERROR_NOT_ENOUGH_SERVER_MEMORY; @@ -79,7 +101,12 @@ DWORD service_create(LPCWSTR name, struct service_entry **entry) HeapFree(GetProcessHeap(), 0, *entry); return ERROR_NOT_ENOUGH_SERVER_MEMORY; } - (*entry)->control_pipe = INVALID_HANDLE_VALUE; + if ((err = process_create(&(*entry)->process)) != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, (*entry)->process); + HeapFree(GetProcessHeap(), 0, *entry); + return err; + } (*entry)->status.dwCurrentState = SERVICE_STOPPED; (*entry)->status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; (*entry)->preshutdown_timeout = default_preshutdown_timeout; @@ -98,11 +125,7 @@ void free_service_entry(struct service_entry *entry) HeapFree(GetProcessHeap(), 0, entry->description); HeapFree(GetProcessHeap(), 0, entry->dependOnServices); HeapFree(GetProcessHeap(), 0, entry->dependOnGroups); - CloseHandle(entry->process); - CloseHandle(entry->control_mutex); - CloseHandle(entry->control_pipe); - CloseHandle(entry->overlapped_event); - CloseHandle(entry->status_changed_event); + free_process_entry(entry->process); HeapFree(GetProcessHeap(), 0, entry); } @@ -332,13 +355,14 @@ static void scmdatabase_wait_terminate(struct scmdatabase *db) run = FALSE; LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry) { - if(service->process) + struct process_entry *process = service->process; + if (process->process) { scmdatabase_unlock(db); - WaitForSingleObject(service->process, INFINITE); + WaitForSingleObject(process->process, INFINITE); scmdatabase_lock(db); - CloseHandle(service->process); - service->process = NULL; + CloseHandle(process->process); + process->process = NULL; run = TRUE; break; } @@ -729,7 +753,7 @@ static DWORD service_start_process(struct service_entry *service_entry, HANDLE * } service_entry->status.dwProcessId = pi.dwProcessId; - service_entry->process = pi.hProcess; + service_entry->process->process = pi.hProcess; *process = pi.hProcess; CloseHandle( pi.hThread ); @@ -738,7 +762,7 @@ static DWORD service_start_process(struct service_entry *service_entry, HANDLE * static DWORD service_wait_for_startup(struct service_entry *service_entry, HANDLE process_handle) { - HANDLE handles[2] = { service_entry->status_changed_event, process_handle }; + HANDLE handles[2] = { service_entry->process->status_changed_event, process_handle }; DWORD state, ret; WINE_TRACE("%p\n", service_entry); @@ -769,6 +793,7 @@ static DWORD service_wait_for_startup(struct service_entry *service_entry, HANDL static BOOL service_send_start_message(struct service_entry *service, HANDLE process_handle, LPCWSTR *argv, DWORD argc) { + struct process_entry *process = service->process; OVERLAPPED overlapped; DWORD i, len, result; service_start_info *ssi; @@ -777,16 +802,16 @@ static BOOL service_send_start_message(struct service_entry *service, HANDLE pro WINE_TRACE("%s %p %d\n", wine_dbgstr_w(service->name), argv, argc); - overlapped.hEvent = service->overlapped_event; - if (!ConnectNamedPipe(service->control_pipe, &overlapped)) + overlapped.hEvent = process->overlapped_event; + if (!ConnectNamedPipe(process->control_pipe, &overlapped)) { if (GetLastError() == ERROR_IO_PENDING) { HANDLE handles[2]; - handles[0] = service->overlapped_event; + handles[0] = process->overlapped_event; handles[1] = process_handle; if (WaitForMultipleObjects( 2, handles, FALSE, service_pipe_timeout ) != WAIT_OBJECT_0) - CancelIo( service->control_pipe ); + CancelIo(process->control_pipe); if (!HasOverlappedIoCompleted( &overlapped )) { WINE_ERR( "service %s failed to start\n", wine_dbgstr_w( service->name )); @@ -822,7 +847,7 @@ static BOOL service_send_start_message(struct service_entry *service, HANDLE pro } *p=0; - r = service_send_command( service, ssi, ssi->total_size, &result ); + r = process_send_command( process, ssi, ssi->total_size, &result ); if (r && result) { SetLastError(result); @@ -836,6 +861,7 @@ static BOOL service_send_start_message(struct service_entry *service, HANDLE pro DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv) { + struct process_entry *process = service->process; DWORD err; LPWSTR name; HANDLE process_handle = NULL; @@ -844,26 +870,26 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * if (err != ERROR_SUCCESS) return err; - if (WaitForSingleObject(service->process, 0) == WAIT_TIMEOUT) + if (WaitForSingleObject(process->process, 0) == WAIT_TIMEOUT) { scmdatabase_unlock_startup(service->db); return ERROR_SERVICE_ALREADY_RUNNING; } - CloseHandle(service->control_pipe); - service->control_mutex = CreateMutexW(NULL, TRUE, NULL); + CloseHandle(process->control_pipe); + process->control_mutex = CreateMutexW(NULL, TRUE, NULL); service->force_shutdown = FALSE; - if (!service->status_changed_event) - service->status_changed_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!service->overlapped_event) - service->overlapped_event = CreateEventW(NULL, TRUE, FALSE, NULL); + if (!process->status_changed_event) + process->status_changed_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!process->overlapped_event) + process->overlapped_event = CreateEventW(NULL, TRUE, FALSE, NULL); name = service_get_pipe_name(); - service->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + process->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL ); HeapFree(GetProcessHeap(), 0, name); - if (service->control_pipe==INVALID_HANDLE_VALUE) + if (process->control_pipe == INVALID_HANDLE_VALUE) { WINE_ERR("failed to create pipe for %s, error = %d\n", wine_dbgstr_w(service->name), GetLastError()); @@ -883,7 +909,7 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * } if (err == ERROR_SUCCESS) - ReleaseMutex(service->control_mutex); + ReleaseMutex(process->control_mutex); else service_terminate(service); scmdatabase_unlock_startup(service->db); @@ -895,16 +921,18 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * void service_terminate(struct service_entry *service) { + struct process_entry *process = service->process; + service_lock(service); - TerminateProcess(service->process, 0); - CloseHandle(service->process); - service->process = NULL; - CloseHandle(service->status_changed_event); - service->status_changed_event = NULL; - CloseHandle(service->control_mutex); - service->control_mutex = NULL; - CloseHandle(service->control_pipe); - service->control_pipe = INVALID_HANDLE_VALUE; + TerminateProcess(process->process, 0); + CloseHandle(process->process); + process->process = NULL; + CloseHandle(process->status_changed_event); + process->status_changed_event = NULL; + CloseHandle(process->control_mutex); + process->control_mutex = NULL; + CloseHandle(process->control_pipe); + process->control_pipe = INVALID_HANDLE_VALUE; service->status.dwProcessId = 0; service->status.dwCurrentState = SERVICE_STOPPED; diff --git a/programs/services/services.h b/programs/services/services.h index 7f43b222a72..206d655a902 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -31,6 +31,15 @@ struct scmdatabase CRITICAL_SECTION cs; }; +struct process_entry +{ + HANDLE process; + HANDLE control_mutex; + HANDLE control_pipe; + HANDLE overlapped_event; + HANDLE status_changed_event; +}; + struct service_entry { struct list entry; @@ -43,11 +52,7 @@ struct service_entry LPWSTR description; LPWSTR dependOnServices; LPWSTR dependOnGroups; - HANDLE process; - HANDLE control_mutex; - HANDLE control_pipe; - HANDLE overlapped_event; - HANDLE status_changed_event; + struct process_entry *process; BOOL force_shutdown; BOOL marked_for_delete; BOOL is_wow64; @@ -79,7 +84,10 @@ void service_lock(struct service_entry *service); void service_unlock(struct service_entry *service); DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv); void service_terminate(struct service_entry *service); -BOOL service_send_command( struct service_entry *service, const void *data, DWORD size, DWORD *result ); + +/* Process functions */ + +BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result); extern HANDLE g_hStartedEvent;