From: Aric Stewart Subject: [PATCH 3/5] programs/services: Break services into Loader groups Message-Id: <30e17af2-4e34-df2e-ae28-f005539246ff@codeweavers.com> Date: Tue, 9 Aug 2016 11:40:24 -0500 Sort the groups by the service's tag to start in order Signed-off-by: Aric Stewart --- programs/services/services.c | 101 ++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/programs/services/services.c b/programs/services/services.c index ae5da2b..177ac2f 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -36,6 +36,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(service); +struct service_group { + struct list entry; + struct service_entry **services_list; + unsigned int size; + unsigned int count; +}; + HANDLE g_hStartedEvent; struct scmdatabase *active_database; @@ -318,16 +325,55 @@ static void scmdatabase_remove_service(struct scmdatabase *db, struct service_en service->entry.next = service->entry.prev = NULL; } +static int compare_tags(const void* a, const void *b) +{ + struct service_entry *service_a = (struct service_entry*)a; + struct service_entry *service_b = (struct service_entry*)b; + return service_a->config.dwTagId - service_b->config.dwTagId; +} + +static void scmdatabase_autostart_service_group(struct service_entry **group, int size) +{ + struct service_entry *service; + int i; + + qsort(group, sizeof(*group), size, compare_tags); + + for (i = 0; i < size; i++) + { + DWORD err; + service = group[i]; + err = service_start(service, 0, NULL); + if (err != ERROR_SUCCESS) + WINE_FIXME("Auto-start service %s failed to start: %d\n", + wine_dbgstr_w(service->name), err); + release_service(service); + } +} + +static void add_service_to_group(struct service_group* group, struct service_entry *service) +{ + if (group->count + 1 >= group->size) + { + struct service_entry **slist_new; + group->size *= 2; + slist_new = HeapReAlloc(GetProcessHeap(), 0, group->services_list, group->size * sizeof(group->services_list[0])); + if (!slist_new) + ERR("Out of memory\n"); + group->services_list = slist_new; + } + group->services_list[group->count] = service; + InterlockedIncrement(&service->ref_count); + group->count++; +} + static void scmdatabase_autostart_services(struct scmdatabase *db) { - struct service_entry **services_list; - unsigned int i = 0; - unsigned int size = 32; + struct list service_groups; struct service_entry *service; + struct service_group *group, *next; - services_list = HeapAlloc(GetProcessHeap(), 0, size * sizeof(services_list[0])); - if (!services_list) - return; + list_init(&service_groups); scmdatabase_lock(db); @@ -337,36 +383,39 @@ static void scmdatabase_autostart_services(struct scmdatabase *db) service->config.dwStartType == SERVICE_SYSTEM_START || service->config.dwStartType == SERVICE_AUTO_START) { - if (i+1 >= size) + int found = 0; + + LIST_FOR_EACH_ENTRY(group, &service_groups, struct service_group, entry) { - struct service_entry **slist_new; - size *= 2; - slist_new = HeapReAlloc(GetProcessHeap(), 0, services_list, size * sizeof(services_list[0])); - if (!slist_new) + if (lstrcmpW(group->services_list[0]->config.lpLoadOrderGroup, service->config.lpLoadOrderGroup)==0) + { + add_service_to_group(group, service); + found = 1; break; - services_list = slist_new; + } + } + + if (!found) + { + group = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*group)); + group->services_list = HeapAlloc(GetProcessHeap(), 0, sizeof(*group->services_list) * 25); + group->size = 25; + group->count = 0; + list_add_tail(&service_groups, &group->entry); + add_service_to_group(group, service); } - services_list[i] = service; - InterlockedIncrement(&service->ref_count); - i++; } } scmdatabase_unlock(db); - size = i; - for (i = 0; i < size; i++) + LIST_FOR_EACH_ENTRY_SAFE(group, next, &service_groups, struct service_group, entry) { - DWORD err; - service = services_list[i]; - err = service_start(service, 0, NULL); - if (err != ERROR_SUCCESS) - WINE_FIXME("Auto-start service %s failed to start: %d\n", - wine_dbgstr_w(service->name), err); - release_service(service); + scmdatabase_autostart_service_group(group->services_list, group->count); + list_remove(&group->entry); + HeapFree(GetProcessHeap(), 0, group->services_list); + HeapFree(GetProcessHeap(), 0, group); } - - HeapFree(GetProcessHeap(), 0, services_list); } static void scmdatabase_wait_terminate(struct scmdatabase *db)