advapi32: Improve PerfCreateInstance() stub.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2021-11-22 17:07:58 +03:00 committed by Alexandre Julliard
parent ee8af8ff28
commit eec443afc2
3 changed files with 157 additions and 11 deletions

View File

@ -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);

View File

@ -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 );

View File

@ -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 *);