[PATCH] programs/services: Add a 3000 ms timeout to StartService. (v2)
This patch avoids simultaneous services startup race and fixes bug 44904. This version of the patch adds a timeout parameter to scmdatabase_lock_startup() to make the approach more generic. Please feel free to choose either old or new version of the patch. Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru> --- programs/services/rpc.c | 4 ++-- programs/services/services.c | 15 ++++++++++++--- programs/services/services.h | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 5ecd6601a5..efbcd7645b 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -1212,7 +1212,7 @@ DWORD __cdecl svcctl_StartServiceW( if (service->service_entry->config.dwStartType == SERVICE_DISABLED) return ERROR_SERVICE_DISABLED; - if (!scmdatabase_lock_startup(service->service_entry->db)) + if (!scmdatabase_lock_startup(service->service_entry->db, 3000)) return ERROR_SERVICE_DATABASE_LOCKED; err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors); @@ -1374,7 +1374,7 @@ DWORD __cdecl svcctl_LockServiceDatabase( if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS) return err; - if (!scmdatabase_lock_startup(manager->db)) + if (!scmdatabase_lock_startup(manager->db, 0)) return ERROR_SERVICE_DATABASE_LOCKED; lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock)); diff --git a/programs/services/services.c b/programs/services/services.c index f7c47b5bc2..eba98d6ee8 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -361,7 +361,7 @@ static void scmdatabase_autostart_services(struct scmdatabase *db) scmdatabase_unlock(db); qsort(services_list, size, sizeof(services_list[0]), compare_tags); - while (!scmdatabase_lock_startup(db)) Sleep(10); + scmdatabase_lock_startup(db, INFINITE); for (i = 0; i < size; i++) { @@ -619,9 +619,18 @@ static DWORD scmdatabase_load_services(struct scmdatabase *db) return ERROR_SUCCESS; } -BOOL scmdatabase_lock_startup(struct scmdatabase *db) +BOOL scmdatabase_lock_startup(struct scmdatabase *db, int timeout) { - return !InterlockedCompareExchange(&db->service_start_lock, TRUE, FALSE); + while (InterlockedCompareExchange(&db->service_start_lock, TRUE, FALSE)) + { + if (timeout != INFINITE) + { + timeout -= 10; + if (timeout <= 0) return FALSE; + } + Sleep(10); + } + return TRUE; } void scmdatabase_unlock_startup(struct scmdatabase *db) diff --git a/programs/services/services.h b/programs/services/services.h index fd19ed32f4..5a79c35778 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -77,7 +77,7 @@ struct service_entry *scmdatabase_find_service(struct scmdatabase *db, LPCWSTR n struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase *db, LPCWSTR name); DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *entry); -BOOL scmdatabase_lock_startup(struct scmdatabase *db); +BOOL scmdatabase_lock_startup(struct scmdatabase *db, int timeout); void scmdatabase_unlock_startup(struct scmdatabase *db); void scmdatabase_lock(struct scmdatabase *db); -- 2.16.3
participants (1)
-
Dmitry Timoshkov