[PATCH 3/4] advapi32: Improve PerfCreateInstance() stub.

Paul Gofman pgofman at codeweavers.com
Mon Nov 22 08:07:58 CST 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 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 *);
-- 
2.33.1




More information about the wine-devel mailing list