forked from Mirrors/wine-wine
services: Defer service delete until all handles are closed.
parent
f823b6abe3
commit
6a4c146962
|
@ -1087,6 +1087,8 @@ BOOL WINAPI DeleteService( SC_HANDLE hService )
|
||||||
{
|
{
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
|
||||||
|
TRACE("%p\n", hService);
|
||||||
|
|
||||||
__TRY
|
__TRY
|
||||||
{
|
{
|
||||||
err = svcctl_DeleteService(hService);
|
err = svcctl_DeleteService(hService);
|
||||||
|
|
|
@ -187,7 +187,7 @@ static void test_open_svc(void)
|
||||||
|
|
||||||
static void test_create_delete_svc(void)
|
static void test_create_delete_svc(void)
|
||||||
{
|
{
|
||||||
SC_HANDLE scm_handle, svc_handle1;
|
SC_HANDLE scm_handle, svc_handle1, svc_handle2;
|
||||||
CHAR username[UNLEN + 1], domain[MAX_PATH];
|
CHAR username[UNLEN + 1], domain[MAX_PATH];
|
||||||
DWORD user_size = UNLEN + 1;
|
DWORD user_size = UNLEN + 1;
|
||||||
CHAR account[UNLEN + 3];
|
CHAR account[UNLEN + 3];
|
||||||
|
@ -412,6 +412,11 @@ static void test_create_delete_svc(void)
|
||||||
ret = DeleteService(svc_handle1);
|
ret = DeleteService(svc_handle1);
|
||||||
ok(ret, "Expected success, got error %u\n", GetLastError());
|
ok(ret, "Expected success, got error %u\n", GetLastError());
|
||||||
|
|
||||||
|
/* Service is marked for delete, but handle is still open. Try to open service again. */
|
||||||
|
svc_handle2 = OpenServiceA(scm_handle, servicename, GENERIC_READ);
|
||||||
|
ok(svc_handle2 != NULL, "got %p, error %u\n", svc_handle2, GetLastError());
|
||||||
|
CloseServiceHandle(svc_handle2);
|
||||||
|
|
||||||
CloseServiceHandle(svc_handle1);
|
CloseServiceHandle(svc_handle1);
|
||||||
CloseServiceHandle(scm_handle);
|
CloseServiceHandle(scm_handle);
|
||||||
|
|
||||||
|
@ -2341,19 +2346,9 @@ static void test_refcount(void)
|
||||||
svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
|
svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
|
||||||
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
|
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
|
||||||
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
|
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
|
||||||
todo_wine
|
|
||||||
{
|
|
||||||
ok(!svc_handle5, "Expected failure\n");
|
ok(!svc_handle5, "Expected failure\n");
|
||||||
ok(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE,
|
ok(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE,
|
||||||
"Expected ERROR_SERVICE_MARKED_FOR_DELETE, got %d\n", GetLastError());
|
"Expected ERROR_SERVICE_MARKED_FOR_DELETE, got %d\n", GetLastError());
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: Remove this when Wine is fixed */
|
|
||||||
if (svc_handle5)
|
|
||||||
{
|
|
||||||
DeleteService(svc_handle5);
|
|
||||||
CloseServiceHandle(svc_handle5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close all the handles to the service and try again */
|
/* Close all the handles to the service and try again */
|
||||||
ret = CloseServiceHandle(svc_handle4);
|
ret = CloseServiceHandle(svc_handle4);
|
||||||
|
|
|
@ -481,8 +481,8 @@ DWORD __cdecl svcctl_CreateServiceW(
|
||||||
DWORD dwPasswordSize,
|
DWORD dwPasswordSize,
|
||||||
SC_RPC_HANDLE *phService)
|
SC_RPC_HANDLE *phService)
|
||||||
{
|
{
|
||||||
|
struct service_entry *entry, *found;
|
||||||
struct sc_manager_handle *manager;
|
struct sc_manager_handle *manager;
|
||||||
struct service_entry *entry;
|
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
|
||||||
WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
|
WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
|
||||||
|
@ -533,11 +533,14 @@ DWORD __cdecl svcctl_CreateServiceW(
|
||||||
|
|
||||||
scmdatabase_lock_exclusive(manager->db);
|
scmdatabase_lock_exclusive(manager->db);
|
||||||
|
|
||||||
if (scmdatabase_find_service(manager->db, lpServiceName))
|
if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
|
||||||
{
|
{
|
||||||
|
service_lock_exclusive(found);
|
||||||
|
err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
|
||||||
|
service_unlock(found);
|
||||||
scmdatabase_unlock(manager->db);
|
scmdatabase_unlock(manager->db);
|
||||||
free_service_entry(entry);
|
free_service_entry(entry);
|
||||||
return ERROR_SERVICE_EXISTS;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
|
if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
|
||||||
|
@ -568,16 +571,14 @@ DWORD __cdecl svcctl_DeleteService(
|
||||||
if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
|
if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
scmdatabase_lock_exclusive(service->service_entry->db);
|
|
||||||
service_lock_exclusive(service->service_entry);
|
service_lock_exclusive(service->service_entry);
|
||||||
|
|
||||||
if (!is_marked_for_delete(service->service_entry))
|
if (!is_marked_for_delete(service->service_entry))
|
||||||
err = scmdatabase_remove_service(service->service_entry->db, service->service_entry);
|
err = mark_for_delete(service->service_entry);
|
||||||
else
|
else
|
||||||
err = ERROR_SERVICE_MARKED_FOR_DELETE;
|
err = ERROR_SERVICE_MARKED_FOR_DELETE;
|
||||||
|
|
||||||
service_unlock(service->service_entry);
|
service_unlock(service->service_entry);
|
||||||
scmdatabase_unlock(service->service_entry->db);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *serv
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *service)
|
static DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *service)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -422,7 +422,14 @@ struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase
|
||||||
void release_service(struct service_entry *service)
|
void release_service(struct service_entry *service)
|
||||||
{
|
{
|
||||||
if (InterlockedDecrement(&service->ref_count) == 0 && is_marked_for_delete(service))
|
if (InterlockedDecrement(&service->ref_count) == 0 && is_marked_for_delete(service))
|
||||||
|
{
|
||||||
|
scmdatabase_lock_exclusive(service->db);
|
||||||
|
service_lock_exclusive(service);
|
||||||
|
scmdatabase_remove_service(service->db, service);
|
||||||
|
service_unlock(service);
|
||||||
|
scmdatabase_unlock(service->db);
|
||||||
free_service_entry(service);
|
free_service_entry(service);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD scmdatabase_create(struct scmdatabase **db)
|
static DWORD scmdatabase_create(struct scmdatabase **db)
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct service_entry
|
||||||
HANDLE control_pipe;
|
HANDLE control_pipe;
|
||||||
HANDLE overlapped_event;
|
HANDLE overlapped_event;
|
||||||
HANDLE status_changed_event;
|
HANDLE status_changed_event;
|
||||||
|
BOOL marked_for_delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct scmdatabase *active_database;
|
extern struct scmdatabase *active_database;
|
||||||
|
@ -57,7 +58,6 @@ extern struct scmdatabase *active_database;
|
||||||
struct service_entry *scmdatabase_find_service(struct scmdatabase *db, LPCWSTR name);
|
struct service_entry *scmdatabase_find_service(struct scmdatabase *db, LPCWSTR name);
|
||||||
struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase *db, LPCWSTR name);
|
struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase *db, LPCWSTR name);
|
||||||
DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *entry);
|
DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *entry);
|
||||||
DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *entry);
|
|
||||||
|
|
||||||
DWORD scmdatabase_lock_startup(struct scmdatabase *db);
|
DWORD scmdatabase_lock_startup(struct scmdatabase *db);
|
||||||
void scmdatabase_unlock_startup(struct scmdatabase *db);
|
void scmdatabase_unlock_startup(struct scmdatabase *db);
|
||||||
|
@ -106,7 +106,13 @@ static inline LPCWSTR get_display_name(struct service_entry *service)
|
||||||
|
|
||||||
static inline BOOL is_marked_for_delete(struct service_entry *service)
|
static inline BOOL is_marked_for_delete(struct service_entry *service)
|
||||||
{
|
{
|
||||||
return service->entry.next == NULL;
|
return service->marked_for_delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DWORD mark_for_delete(struct service_entry *service)
|
||||||
|
{
|
||||||
|
service->marked_for_delete = TRUE;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*WINE_PROGRAMS_UTILS_H_*/
|
#endif /*WINE_PROGRAMS_UTILS_H_*/
|
||||||
|
|
Loading…
Reference in New Issue