[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