From eec443afc262c239c36052689431044072d28100 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 22 Nov 2021 17:07:58 +0300 Subject: [PATCH] advapi32: Improve PerfCreateInstance() stub. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard --- dlls/advapi32/tests/perf.c | 63 +++++++++++++++++++++-- dlls/kernelbase/main.c | 102 ++++++++++++++++++++++++++++++++++--- include/perflib.h | 3 ++ 3 files changed, 157 insertions(+), 11 deletions(-) diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index d76d6ddd44a..9236ea8bb75 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -42,17 +42,24 @@ void test_provider_init(void) static struct { PERF_COUNTERSET_INFO counterset; - PERF_COUNTER_INFO counter; + PERF_COUNTER_INFO counter[2]; } pc_template = { {{0}}, - {1, PERF_COUNTER_COUNTER, PERF_ATTRIB_BY_REFERENCE, sizeof(PERF_COUNTER_INFO), PERF_DETAIL_NOVICE, 0, 0}, + { + {1, PERF_COUNTER_COUNTER, PERF_ATTRIB_BY_REFERENCE, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + {2, PERF_COUNTER_COUNTER, PERF_ATTRIB_BY_REFERENCE, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + }, }; + PERF_COUNTERSET_INSTANCE *instance; PERF_PROVIDER_CONTEXT prov_context; + UINT64 counter1, counter2; HANDLE prov, prov2; - ULONG ret; + ULONG ret, size; BOOL bret; prov = (HANDLE)0xdeadbeef; @@ -99,7 +106,7 @@ void test_provider_init(void) pc_template.counterset.CounterSetGuid = test_set_guid; pc_template.counterset.ProviderGuid = test_guid; - pc_template.counterset.NumCounters = 1; + pc_template.counterset.NumCounters = 2; pc_template.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); ok(!ret, "Got unexpected ret %u.\n", ret); @@ -115,6 +122,54 @@ void test_provider_init(void) ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); ok(ret == ERROR_ALREADY_EXISTS, "Got unexpected ret %u.\n", ret); + SetLastError(0xdeadbeef); + instance = PerfCreateInstance(prov, NULL, L"1", 1); + ok(!instance, "Got unexpected instance %p.\n", instance); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected error %u.\n", GetLastError()); + + SetLastError(0xdeadbeef); + instance = PerfCreateInstance(prov, &test_guid, L"1", 1); + ok(!instance, "Got unexpected instance %p.\n", instance); + ok(GetLastError() == ERROR_NOT_FOUND, "Got unexpected error %u.\n", GetLastError()); + + SetLastError(0xdeadbeef); + instance = PerfCreateInstance(prov, &test_guid, NULL, 1); + ok(!instance, "Got unexpected instance %p.\n", instance); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected error %u.\n", GetLastError()); + + SetLastError(0xdeadbeef); + instance = PerfCreateInstance(prov, &test_set_guid, L"11", 1); + ok(!!instance, "Got NULL instance.\n"); + ok(GetLastError() == 0xdeadbeef, "Got unexpected error %u.\n", GetLastError()); + ok(instance->InstanceId == 1, "Got unexpected InstanceId %u.\n", instance->InstanceId); + ok(instance->InstanceNameSize == 6, "Got unexpected InstanceNameSize %u.\n", instance->InstanceNameSize); + ok(IsEqualGUID(&instance->CounterSetGuid, &test_set_guid), "Got unexpected guid %s.\n", + debugstr_guid(&instance->CounterSetGuid)); + + ok(instance->InstanceNameOffset == sizeof(*instance) + sizeof(UINT64) * 2, + "Got unexpected InstanceNameOffset %u.\n", instance->InstanceNameOffset); + ok(!lstrcmpW((WCHAR *)((BYTE *)instance + instance->InstanceNameOffset), L"11"), + "Got unexpected instance name %s.\n", + debugstr_w((WCHAR *)((BYTE *)instance + instance->InstanceNameOffset))); + size = ((sizeof(*instance) + sizeof(UINT64) * 2 + instance->InstanceNameSize) + 7) & ~7; + ok(size == instance->dwSize, "Got unexpected size %u, instance->dwSize %u.\n", size, instance->dwSize); + + ret = PerfSetCounterRefValue(prov, instance, 1, &counter1); + todo_wine ok(!ret, "Got unexpected ret %u.\n", ret); + ret = PerfSetCounterRefValue(prov, instance, 2, &counter2); + todo_wine ok(!ret, "Got unexpected ret %u.\n", ret); + + ret = PerfSetCounterRefValue(prov, instance, 0, &counter2); + todo_wine ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret); + + todo_wine ok(*(void **)(instance + 1) == &counter1, "Got unexpected counter value %p.\n", + *(void **)(instance + 1)); + todo_wine ok(*(void **)((BYTE *)instance + sizeof(*instance) + sizeof(UINT64)) == &counter2, + "Got unexpected counter value %p.\n", *(void **)(instance + 1)); + + ret = PerfDeleteInstance(prov, instance); + ok(!ret, "Got unexpected ret %u.\n", ret); + ret = PerfStopProvider(prov); ok(!ret, "Got unexpected ret %u.\n", ret); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 403c0cf6cd2..d90bedcc637 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -30,6 +30,7 @@ #include "wine/debug.h" #include "kernelbase.h" #include "wine/heap.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(kernelbase); @@ -160,12 +161,21 @@ struct counterset_template PERF_COUNTER_INFO counter[1]; }; +struct counterset_instance +{ + struct list entry; + struct counterset_template *template; + PERF_COUNTERSET_INSTANCE instance; +}; + struct perf_provider { GUID guid; PERFLIBREQUEST callback; struct counterset_template **countersets; unsigned int counterset_count; + + struct list instance_list; }; static struct perf_provider *perf_provider_from_handle(HANDLE prov) @@ -176,20 +186,82 @@ static struct perf_provider *perf_provider_from_handle(HANDLE prov) /*********************************************************************** * PerfCreateInstance (KERNELBASE.@) */ -PPERF_COUNTERSET_INSTANCE WINAPI PerfCreateInstance(HANDLE handle, LPCGUID guid, - const WCHAR *name, ULONG id) +PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance( HANDLE handle, const GUID *guid, + const WCHAR *name, ULONG id ) { - FIXME("%p %s %s %u: stub\n", handle, debugstr_guid(guid), debugstr_w(name), id); - return NULL; + struct perf_provider *prov = perf_provider_from_handle( handle ); + struct counterset_template *template; + struct counterset_instance *inst; + unsigned int i; + ULONG size; + + FIXME( "handle %p, guid %s, name %s, id %u semi-stub.\n", handle, debugstr_guid(guid), debugstr_w(name), id ); + + if (!prov || !guid || !name) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + + for (i = 0; i < prov->counterset_count; ++i) + if (IsEqualGUID(guid, &prov->countersets[i]->counterset.CounterSetGuid)) break; + + if (i == prov->counterset_count) + { + SetLastError( ERROR_NOT_FOUND ); + return NULL; + } + + template = prov->countersets[i]; + + LIST_FOR_EACH_ENTRY(inst, &prov->instance_list, struct counterset_instance, entry) + { + if (inst->template == template && inst->instance.InstanceId == id) + { + SetLastError( ERROR_ALREADY_EXISTS ); + return NULL; + } + } + + size = (sizeof(PERF_COUNTERSET_INSTANCE) + template->counterset.NumCounters * sizeof(UINT64) + + (lstrlenW( name ) + 1) * sizeof(WCHAR) + 7) & ~7; + inst = heap_alloc_zero( offsetof(struct counterset_instance, instance) + size ); + if (!inst) + { + SetLastError( ERROR_OUTOFMEMORY ); + return NULL; + } + + inst->template = template; + inst->instance.CounterSetGuid = *guid; + inst->instance.dwSize = size; + inst->instance.InstanceId = id; + inst->instance.InstanceNameOffset = sizeof(PERF_COUNTERSET_INSTANCE) + + template->counterset.NumCounters * sizeof(UINT64); + inst->instance.InstanceNameSize = (lstrlenW( name ) + 1) * sizeof(WCHAR); + memcpy( (BYTE *)&inst->instance + inst->instance.InstanceNameOffset, name, inst->instance.InstanceNameSize ); + list_add_tail( &prov->instance_list, &inst->entry ); + + return &inst->instance; } /*********************************************************************** * PerfDeleteInstance (KERNELBASE.@) */ -ULONG WINAPI PerfDeleteInstance(HANDLE provider, PPERF_COUNTERSET_INSTANCE block) +ULONG WINAPI PerfDeleteInstance(HANDLE provider, PERF_COUNTERSET_INSTANCE *block) { - FIXME("%p %p: stub\n", provider, block); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov = perf_provider_from_handle( provider ); + struct counterset_instance *inst; + + TRACE( "provider %p, block %p.\n", provider, block ); + + if (!prov || !block) return ERROR_INVALID_PARAMETER; + + inst = CONTAINING_RECORD(block, struct counterset_instance, instance); + list_remove( &inst->entry ); + heap_free( inst ); + + return ERROR_SUCCESS; } /*********************************************************************** @@ -229,6 +301,8 @@ ULONG WINAPI PerfSetCounterSetInfo( HANDLE handle, PERF_COUNTERSET_INFO *templat return ERROR_OUTOFMEMORY; } memcpy( new, template, size ); + for (i = 0; i < template->NumCounters; ++i) + new->counter[i].Offset = i * sizeof(UINT64); new_array[prov->counterset_count++] = new; prov->countersets = new_array; @@ -273,7 +347,11 @@ ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HA if (!guid || !context || !provider) return ERROR_INVALID_PARAMETER; if (context->ContextSize < sizeof(*context)) return ERROR_INVALID_PARAMETER; + if (context->MemAllocRoutine || context->MemFreeRoutine) + FIXME("Memory allocation routine is not supported.\n"); + if (!(prov = heap_alloc_zero( sizeof(*prov) ))) return ERROR_OUTOFMEMORY; + list_init( &prov->instance_list ); memcpy( &prov->guid, guid, sizeof(prov->guid) ); prov->callback = context->ControlCallback; *provider = prov; @@ -287,10 +365,20 @@ ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HA ULONG WINAPI PerfStopProvider(HANDLE handle) { struct perf_provider *prov = perf_provider_from_handle( handle ); + struct counterset_instance *inst, *next; unsigned int i; TRACE( "handle %p.\n", handle ); + if (!list_empty( &prov->instance_list )) + WARN( "Stopping provider with active counter instances.\n" ); + + LIST_FOR_EACH_ENTRY_SAFE(inst, next, &prov->instance_list, struct counterset_instance, entry) + { + list_remove( &inst->entry ); + heap_free( inst ); + } + for (i = 0; i < prov->counterset_count; ++i) heap_free( prov->countersets[i] ); heap_free( prov->countersets ); diff --git a/include/perflib.h b/include/perflib.h index 5a2a1162ae7..54ea8ccb614 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -81,6 +81,9 @@ typedef struct _PROVIDER_CONTEXT { LPVOID pMemContext; } PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT; +PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance(HANDLE, const GUID *, const WCHAR *, ULONG); +ULONG WINAPI PerfDeleteInstance(HANDLE, PERF_COUNTERSET_INSTANCE *); +ULONG WINAPI PerfSetCounterRefValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, void *); ULONG WINAPI PerfSetCounterSetInfo(HANDLE, PERF_COUNTERSET_INFO *, ULONG); ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *);