Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Avoids crash in Edge Webview embedded in Forza Horizon 5. Technically it is enough just to fake success from these stubs but PerfCreateInstance returns a documented (albeit wrongly) structure and it looks better to return correcly layed out data.
dlls/advapi32/tests/Makefile.in | 1 + dlls/advapi32/tests/perf.c | 100 ++++++++++++++++++++++++++++++++ dlls/kernelbase/main.c | 49 +++++++++++++--- include/perflib.h | 4 ++ 4 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 dlls/advapi32/tests/perf.c
diff --git a/dlls/advapi32/tests/Makefile.in b/dlls/advapi32/tests/Makefile.in index 12583e59f57..2e9b007a91f 100644 --- a/dlls/advapi32/tests/Makefile.in +++ b/dlls/advapi32/tests/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ crypt_sha.c \ eventlog.c \ lsa.c \ + perf.c \ registry.c \ security.c \ service.c diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c new file mode 100644 index 00000000000..34fedd2b645 --- /dev/null +++ b/dlls/advapi32/tests/perf.c @@ -0,0 +1,100 @@ +/* + * Unit tests for Perflib functions + * + * Copyright (c) 2021 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "perflib.h" + +#include "wine/test.h" + +static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size) +{ + ok(0, "Provider callback called.\n"); + return ERROR_SUCCESS; +} + +void test_provider_init(void) +{ + static GUID test_guid = {0xdeadbeef, 0x0001, 0x0002, {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; + PERF_PROVIDER_CONTEXT prov_context; + HANDLE prov, prov2; + ULONG ret; + BOOL bret; + + prov = (HANDLE)0xdeadbeef; + ret = PerfStartProvider(NULL, test_provider_callback, &prov); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov); + + prov = (HANDLE)0xdeadbeef; + ret = PerfStartProvider(&test_guid, test_provider_callback, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov); + + prov = (HANDLE)0xdeadbeef; + ret = PerfStartProvider(&test_guid, test_provider_callback, &prov); + ok(!ret, "Got unexpected ret %u.\n", ret); + ok(prov != (HANDLE)0xdeadbeef, "Provider handle is not set.\n"); + + prov2 = prov; + ret = PerfStartProvider(&test_guid, test_provider_callback, &prov2); + ok(!ret, "Got unexpected ret %u.\n", ret); + ok(prov2 != prov, "Got the same provider handle.\n"); + + ret = PerfStopProvider(prov2); + ok(!ret, "Got unexpected ret %u.\n", ret); + + if (0) + { + /* Access violation on Windows. */ + PerfStopProvider(prov2); + } + + /* Provider handle is a pointer and not a kernel object handle. */ + bret = DuplicateHandle(GetCurrentProcess(), prov, GetCurrentProcess(), &prov2, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(!bret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected bret %d, err %u.\n", bret, GetLastError()); + bret = IsBadWritePtr(prov, 8); + ok(!bret, "Handle does not point to the data.\n"); + + ret = PerfStopProvider(prov); + ok(!ret, "Got unexpected ret %u.\n", ret); + + memset( &prov_context, 0, sizeof(prov_context) ); + prov = (HANDLE)0xdeadbeef; + ret = PerfStartProviderEx( &test_guid, &prov_context, &prov ); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov); + + prov_context.ContextSize = sizeof(prov_context) + 1; + ret = PerfStartProviderEx( &test_guid, &prov_context, &prov ); + ok(!ret, "Got unexpected ret %u.\n", ret); + ok(prov != (HANDLE)0xdeadbeef, "Provider handle is not set.\n"); + + ret = PerfStopProvider(prov); + ok(!ret, "Got unexpected ret %u.\n", ret); +} + +START_TEST(perf) +{ + test_provider_init(); +} diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index e6cf892a4dc..d468c84f619 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -154,6 +154,17 @@ LONG WINAPI AppPolicyGetWindowingModel(HANDLE token, AppPolicyWindowingModel *po return ERROR_SUCCESS; }
+struct perf_provider +{ + GUID guid; + PERFLIBREQUEST callback; +}; + +static struct perf_provider *perf_provider_from_handle(HANDLE prov) +{ + return (struct perf_provider *)prov; +} + /*********************************************************************** * PerfCreateInstance (KERNELBASE.@) */ @@ -195,19 +206,37 @@ ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PPERF_COUNTERSET_INSTANCE i /*********************************************************************** * PerfStartProvider (KERNELBASE.@) */ -ULONG WINAPI PerfStartProvider(GUID *guid, PERFLIBREQUEST callback, HANDLE *provider) +ULONG WINAPI PerfStartProvider( GUID *guid, PERFLIBREQUEST callback, HANDLE *provider ) { - FIXME("%s %p %p: stub\n", debugstr_guid(guid), callback, provider); - return ERROR_CALL_NOT_IMPLEMENTED; + PERF_PROVIDER_CONTEXT ctx; + + FIXME( "guid %s, callback %p, provider %p semi-stub.\n", debugstr_guid(guid), callback, provider ); + + memset( &ctx, 0, sizeof(ctx) ); + ctx.ContextSize = sizeof(ctx); + ctx.ControlCallback = callback; + + return PerfStartProviderEx( guid, &ctx, provider ); }
/*********************************************************************** * PerfStartProviderEx (KERNELBASE.@) */ -ULONG WINAPI PerfStartProviderEx(GUID *guid, PPERF_PROVIDER_CONTEXT context, HANDLE *provider) +ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HANDLE *provider ) { - FIXME("%s %p %p: stub\n", debugstr_guid(guid), context, provider); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov; + + FIXME( "guid %s, context %p, provider %p semi-stub.\n", debugstr_guid(guid), context, provider ); + + if (!guid || !context || !provider) return ERROR_INVALID_PARAMETER; + if (context->ContextSize < sizeof(*context)) return ERROR_INVALID_PARAMETER; + + if (!(prov = heap_alloc_zero( sizeof(*prov) ))) return ERROR_OUTOFMEMORY; + memcpy( &prov->guid, guid, sizeof(prov->guid) ); + prov->callback = context->ControlCallback; + *provider = prov; + + return STATUS_SUCCESS; }
/*********************************************************************** @@ -215,8 +244,12 @@ ULONG WINAPI PerfStartProviderEx(GUID *guid, PPERF_PROVIDER_CONTEXT context, HAN */ ULONG WINAPI PerfStopProvider(HANDLE handle) { - FIXME("%p: stub\n", handle); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov = perf_provider_from_handle( handle ); + + TRACE( "handle %p.\n", handle ); + + heap_free( prov ); + return STATUS_SUCCESS; }
/*********************************************************************** diff --git a/include/perflib.h b/include/perflib.h index 2d3f6efb419..47bc0716541 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -51,6 +51,10 @@ typedef struct _PROVIDER_CONTEXT { LPVOID pMemContext; } PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT;
+ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); +ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *); +ULONG WINAPI PerfStopProvider(HANDLE); + #ifdef __cplusplus } /* extern "C" */ #endif
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/advapi32/tests/perf.c | 39 ++++++++++++++++++++++++++++ dlls/kernelbase/main.c | 52 +++++++++++++++++++++++++++++++++++--- include/perflib.h | 31 +++++++++++++++++++++++ include/winperf.h | 29 +++++++++++++++++++++ 4 files changed, 148 insertions(+), 3 deletions(-)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 34fedd2b645..d76d6ddd44a 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winerror.h" #include "perflib.h" +#include "winperf.h"
#include "wine/test.h"
@@ -35,7 +36,20 @@ static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size)
void test_provider_init(void) { + static GUID test_set_guid = {0xdeadbeef, 0x0002, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; + static GUID test_set_guid2 = {0xdeadbeef, 0x0003, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; static GUID test_guid = {0xdeadbeef, 0x0001, 0x0002, {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; + static struct + { + PERF_COUNTERSET_INFO counterset; + PERF_COUNTER_INFO counter; + } + pc_template = + { + {{0}}, + {1, PERF_COUNTER_COUNTER, PERF_ATTRIB_BY_REFERENCE, sizeof(PERF_COUNTER_INFO), PERF_DETAIL_NOVICE, 0, 0}, + }; + PERF_PROVIDER_CONTEXT prov_context; HANDLE prov, prov2; ULONG ret; @@ -76,6 +90,31 @@ void test_provider_init(void) bret = IsBadWritePtr(prov, 8); ok(!bret, "Handle does not point to the data.\n");
+ pc_template.counterset.CounterSetGuid = test_set_guid; + pc_template.counterset.ProviderGuid = test_guid; + pc_template.counterset.NumCounters = 0; + pc_template.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template.counterset)); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + pc_template.counterset.CounterSetGuid = test_set_guid; + pc_template.counterset.ProviderGuid = test_guid; + pc_template.counterset.NumCounters = 1; + 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); + + pc_template.counterset.CounterSetGuid = test_set_guid2; + /* Looks like ProviderGuid doesn't need to match provider. */ + pc_template.counterset.ProviderGuid = test_set_guid; + pc_template.counterset.NumCounters = 1; + 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); + + ret = PerfSetCounterSetInfo(prov, &pc_template.counterset, sizeof(pc_template)); + ok(ret == ERROR_ALREADY_EXISTS, "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 d468c84f619..403c0cf6cd2 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -154,10 +154,18 @@ LONG WINAPI AppPolicyGetWindowingModel(HANDLE token, AppPolicyWindowingModel *po return ERROR_SUCCESS; }
+struct counterset_template +{ + PERF_COUNTERSET_INFO counterset; + PERF_COUNTER_INFO counter[1]; +}; + struct perf_provider { GUID guid; PERFLIBREQUEST callback; + struct counterset_template **countersets; + unsigned int counterset_count; };
static struct perf_provider *perf_provider_from_handle(HANDLE prov) @@ -187,10 +195,44 @@ ULONG WINAPI PerfDeleteInstance(HANDLE provider, PPERF_COUNTERSET_INSTANCE block /*********************************************************************** * PerfSetCounterSetInfo (KERNELBASE.@) */ -ULONG WINAPI PerfSetCounterSetInfo(HANDLE handle, PPERF_COUNTERSET_INFO template, ULONG size) +ULONG WINAPI PerfSetCounterSetInfo( HANDLE handle, PERF_COUNTERSET_INFO *template, ULONG size ) { - FIXME("%p %p %u: stub\n", handle, template, size); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov = perf_provider_from_handle( handle ); + struct counterset_template **new_array; + struct counterset_template *new; + unsigned int i; + + FIXME( "handle %p, template %p, size %u semi-stub.\n", handle, template, size ); + + if (!prov || !template) return ERROR_INVALID_PARAMETER; + if (!template->NumCounters) return ERROR_INVALID_PARAMETER; + if (size < sizeof(*template) || (size - (sizeof(*template))) / sizeof(PERF_COUNTER_INFO) < template->NumCounters) + return ERROR_INVALID_PARAMETER; + + for (i = 0; i < prov->counterset_count; ++i) + { + if (IsEqualGUID( &template->CounterSetGuid, &prov->countersets[i]->counterset.CounterSetGuid )) + return ERROR_ALREADY_EXISTS; + } + + size = offsetof( struct counterset_template, counter[template->NumCounters] ); + if (!(new = heap_alloc( size ))) return ERROR_OUTOFMEMORY; + + if (prov->counterset_count) + new_array = heap_realloc( prov->countersets, sizeof(*prov->countersets) * (prov->counterset_count + 1) ); + else + new_array = heap_alloc( sizeof(*prov->countersets) ); + + if (!new_array) + { + heap_free( new ); + return ERROR_OUTOFMEMORY; + } + memcpy( new, template, size ); + new_array[prov->counterset_count++] = new; + prov->countersets = new_array; + + return STATUS_SUCCESS; }
/*********************************************************************** @@ -245,9 +287,13 @@ ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HA ULONG WINAPI PerfStopProvider(HANDLE handle) { struct perf_provider *prov = perf_provider_from_handle( handle ); + unsigned int i;
TRACE( "handle %p.\n", handle );
+ for (i = 0; i < prov->counterset_count; ++i) + heap_free( prov->countersets[i] ); + heap_free( prov->countersets ); heap_free( prov ); return STATUS_SUCCESS; } diff --git a/include/perflib.h b/include/perflib.h index 47bc0716541..5a2a1162ae7 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -34,6 +34,19 @@ typedef struct _PERF_COUNTERSET_INFO { ULONG InstanceType; } PERF_COUNTERSET_INFO, * PPERF_COUNTERSET_INFO;
+/* PERF_COUNTERSET_INFO InstanceType values. */ +#define PERF_COUNTERSET_FLAG_MULTIPLE 0x00000002 +#define PERF_COUNTERSET_FLAG_AGGREGATE 0x00000004 +#define PERF_COUNTERSET_FLAG_HISTORY 0x00000008 +#define PERF_COUNTERSET_FLAG_INSTANCE 0x00000010 + +#define PERF_COUNTERSET_SINGLE_INSTANCE 0 +#define PERF_COUNTERSET_MULTI_INSTANCES PERF_COUNTERSET_FLAG_MULTIPLE +#define PERF_COUNTERSET_SINGLE_AGGREGATE PERF_COUNTERSET_FLAG_AGGREGATE +#define PERF_COUNTERSET_MULTI_AGGREGATE (PERF_COUNTERSET_FLAG_AGGREGATE | PERF_COUNTERSET_FLAG_MULTIPLE) +#define PERF_COUNTERSET_SINGLE_AGGREGATE_HISTORY (PERF_COUNTERSET_FLAG_HISTORY | PERF_COUNTERSET_SINGLE_AGGREGATE) +#define PERF_COUNTERSET_INSTANCE_AGGREGATE (PERF_COUNTERSET_MULTI_AGGREGATE | PERF_COUNTERSET_FLAG_INSTANCE) + typedef struct _PERF_COUNTERSET_INSTANCE { GUID CounterSetGuid; ULONG dwSize; @@ -42,6 +55,23 @@ typedef struct _PERF_COUNTERSET_INSTANCE { ULONG InstanceNameSize; } PERF_COUNTERSET_INSTANCE, * PPERF_COUNTERSET_INSTANCE;
+typedef struct _PERF_COUNTER_INFO { + ULONG CounterId; + ULONG Type; + ULONGLONG Attrib; + ULONG Size; + ULONG DetailLevel; + LONG Scale; + ULONG Offset; +} PERF_COUNTER_INFO, *PPERF_COUNTER_INFO; + +/* PERF_COUNTER_INFO Attrib flags. */ +#define PERF_ATTRIB_BY_REFERENCE 0x00000001 +#define PERF_ATTRIB_NO_DISPLAYABLE 0x00000002 +#define PERF_ATTRIB_NO_GROUP_SEPARATOR 0x00000004 +#define PERF_ATTRIB_DISPLAY_AS_REAL 0x00000008 +#define PERF_ATTRIB_DISPLAY_AS_HEX 0x00000010 + typedef struct _PROVIDER_CONTEXT { DWORD ContextSize; DWORD Reserved; @@ -51,6 +81,7 @@ typedef struct _PROVIDER_CONTEXT { LPVOID pMemContext; } PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT;
+ULONG WINAPI PerfSetCounterSetInfo(HANDLE, PERF_COUNTERSET_INFO *, ULONG); ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *); ULONG WINAPI PerfStopProvider(HANDLE); diff --git a/include/winperf.h b/include/winperf.h index 113bfbae40f..926da8f8c4a 100644 --- a/include/winperf.h +++ b/include/winperf.h @@ -161,6 +161,35 @@ typedef struct _PERF_COUNTER_BLOCK DWORD ByteLength; } PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK;
+#define PERF_COUNTER_VALUE 0x00000000 +#define PERF_COUNTER_RATE 0x00010000 +#define PERF_COUNTER_FRACTION 0x00020000 +#define PERF_COUNTER_BASE 0x00030000 +#define PERF_COUNTER_ELAPSED 0x00040000 +#define PERF_COUNTER_QUEUELEN 0x00050000 +#define PERF_COUNTER_HISTOGRAM 0x00060000 +#define PERF_COUNTER_PRECISION 0x00070000 + +#define PERF_TEXT_UNICODE 0x00000000 +#define PERF_TEXT_ASCII 0x00010000 + +#define PERF_TIMER_TICK 0x00000000 +#define PERF_TIMER_100NS 0x00100000 +#define PERF_OBJECT_TIMER 0x00200000 + +#define PERF_DELTA_COUNTER 0x00400000 +#define PERF_DELTA_BASE 0x00800000 +#define PERF_INVERSE_COUNTER 0x01000000 +#define PERF_MULTI_COUNTER 0x02000000 + +#define PERF_DISPLAY_NO_SUFFIX 0x00000000 +#define PERF_DISPLAY_PER_SEC 0x10000000 +#define PERF_DISPLAY_PERCENT 0x20000000 +#define PERF_DISPLAY_SECONDS 0x30000000 +#define PERF_DISPLAY_NOSHOW 0x40000000 + +#define PERF_COUNTER_COUNTER (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | \ + PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC)
#include <poppack.h>
Signed-off-by: Paul Gofman pgofman@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 *);
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/advapi32/tests/perf.c | 10 +++++----- dlls/kernelbase/main.c | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 9236ea8bb75..a0862e65ea4 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -155,16 +155,16 @@ void test_provider_init(void) 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); + ok(!ret, "Got unexpected ret %u.\n", ret); ret = PerfSetCounterRefValue(prov, instance, 2, &counter2); - todo_wine ok(!ret, "Got unexpected ret %u.\n", ret); + 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); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret);
- todo_wine ok(*(void **)(instance + 1) == &counter1, "Got unexpected counter value %p.\n", + 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, + ok(*(void **)((BYTE *)instance + sizeof(*instance) + sizeof(UINT64)) == &counter2, "Got unexpected counter value %p.\n", *(void **)(instance + 1));
ret = PerfDeleteInstance(prov, instance); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index d90bedcc637..775c1c2ac07 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -312,11 +312,29 @@ ULONG WINAPI PerfSetCounterSetInfo( HANDLE handle, PERF_COUNTERSET_INFO *templat /*********************************************************************** * PerfSetCounterRefValue (KERNELBASE.@) */ -ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PPERF_COUNTERSET_INSTANCE instance, +ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *instance, ULONG counterid, void *address) { - FIXME("%p %p %u %p: stub\n", provider, instance, counterid, address); - return ERROR_CALL_NOT_IMPLEMENTED; + struct perf_provider *prov = perf_provider_from_handle( provider ); + struct counterset_template *template; + struct counterset_instance *inst; + unsigned int i; + + FIXME( "provider %p, instance %p, counterid %u, address %p semi-stub.\n", + provider, instance, counterid, address ); + + if (!prov || !instance || !address) return ERROR_INVALID_PARAMETER; + + inst = CONTAINING_RECORD(instance, struct counterset_instance, instance); + template = inst->template; + + for (i = 0; i < template->counterset.NumCounters; ++i) + if (template->counter[i].CounterId == counterid) break; + + if (i == template->counterset.NumCounters) return ERROR_NOT_FOUND; + *(void **)((BYTE *)&inst->instance + sizeof(PERF_COUNTERSET_INSTANCE) + template->counter[i].Offset) = address; + + return STATUS_SUCCESS; }
/***********************************************************************
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=102454
Your paranoid android.
=== w1064 (32 bit report) ===
advapi32: eventlog: Timeout