Startup and lock counts in native Windows are separate, and the lock count does not decrease when an async result is freed if the platform has been started.
-- v3: rtworkq: Do not unlock the platform when async result objects are freed if the platform is started. rtworkq: Introduce a platform startup count. rtworkq/tests: Test work queue. mfplat/tests: Test platform startup and lock counts. mfplat/tests: Test mixing of MF platform functions with their Rtwq equivalents. mfplat/tests: Introduce a helper to check the platform lock count. mfplat/tests: Release callback2 in test_event_queue().
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/mfplat.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 2b17b069d1d..203defec77a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -4391,6 +4391,7 @@ static void test_event_queue(void) ok(ret == 1 || broken(ret == 2) /* Vista */, "Unexpected refcount %ld, expected 1.\n", ret); IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + IMFAsyncCallback_Release(&callback2->IMFAsyncCallback_iface);
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/mfplat.c | 63 ++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 16 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 203defec77a..9539646d6ab 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -219,6 +219,37 @@ static void check_attributes_(const char *file, int line, IMFAttributes *attribu } }
+#define check_platform_lock_count(a) check_platform_lock_count_(__LINE__, a, FALSE) +#define check_and_clear_platform_lock_count(a) check_platform_lock_count_(__LINE__, a, TRUE) +static void check_platform_lock_count_(unsigned int line, unsigned int expected, BOOL clear) +{ + unsigned int i, relock, count = 0; + DWORD queue; + HRESULT hr; + + for (;;) + { + if (FAILED(hr = MFAllocateWorkQueue(&queue))) + break; + MFUnlockWorkQueue(queue); + + hr = MFUnlockPlatform(); + if (FAILED(hr)) + break; + ++count; + } + + relock = count; + if (clear) + relock = min(relock, 1); + + for (i = 0; i < relock; ++i) + MFLockPlatform(); + + todo_wine_if(clear) + ok_(__FILE__, line)(count == expected, "Unexpected lock count %u.\n", count); +} + struct d3d9_surface_readback { IDirect3DSurface9 *surface, *readback_surface; @@ -1664,6 +1695,14 @@ static void test_source_resolver(void)
IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); IMFAsyncCallback_Release(&callback2->IMFAsyncCallback_iface); + + /* TODO: Wine leaks some async results. */ + Sleep(100); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_and_clear_platform_lock_count(1); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); }
static void init_functions(void) @@ -3834,10 +3873,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr);
- hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1);
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -3852,10 +3888,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr);
- hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1);
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -3864,10 +3897,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr);
- hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1);
/* Unlocking implies shutdown. */ hr = MFUnlockPlatform(); @@ -3879,10 +3909,7 @@ static void test_startup(void) hr = MFLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr);
- hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1);
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -13328,5 +13355,9 @@ START_TEST(mfplat) test_MFCreatePathFromURL(); test_2dbuffer_copy();
+ MFStartup(MF_VERSION, MFSTARTUP_FULL); + check_platform_lock_count(1); + MFShutdown(); + CoUninitialize(); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/Makefile.in | 2 +- dlls/mfplat/tests/mfplat.c | 57 +++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/tests/Makefile.in b/dlls/mfplat/tests/Makefile.in index 217ea437b3c..05c14288769 100644 --- a/dlls/mfplat/tests/Makefile.in +++ b/dlls/mfplat/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfplat.dll -IMPORTS = ole32 mfplat user32 d3d9 dxva2 mfuuid propsys uuid strmiids +IMPORTS = ole32 mfplat user32 d3d9 dxva2 mfuuid propsys uuid strmiids rtworkq
SOURCES = \ mfplat.c \ diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 9539646d6ab..cd7fd628741 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -42,6 +42,7 @@ #include "evr.h" #include "mfmediaengine.h" #include "codecapi.h" +#include "rtworkq.h"
#include "wine/test.h"
@@ -3864,6 +3865,8 @@ static void test_MFCreateAsyncResult(void)
static void test_startup(void) { + struct test_callback *callback; + IMFAsyncResult *result; DWORD queue; HRESULT hr;
@@ -3913,6 +3916,60 @@ static void test_startup(void)
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Rtwq equivalence */ + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + check_platform_lock_count(1); + + /* Matching MFStartup() with RtwqShutdown() causes shutdown. */ + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Failed to allocate a queue, hr %#lx.\n", hr); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* RtwqStartup() enables MF functions */ + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + check_platform_lock_count(1); + + callback = create_test_callback(NULL); + + /* MF platform lock is the Rtwq lock */ + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock platform, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Failed to allocate a queue, hr %#lx.\n", hr); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(1); + + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock platform, hr %#lx.\n", hr); + check_platform_lock_count(2); + + IMFAsyncResult_Release(result); + + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); }
static void test_allocate_queue(void)
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/mfplat.c | 194 +++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index cd7fd628741..0afbb6c07b8 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3972,6 +3972,199 @@ static void test_startup(void) IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); }
+void test_startup_counts(void) +{ + IMFAsyncResult *result, *result2, *callback_result; + struct test_callback *callback; + MFWORKITEM_KEY key, key2; + DWORD res, queue; + LONG refcount; + HRESULT hr; + + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFAllocateWorkQueue(&queue); + todo_wine + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + callback = create_test_callback(&test_async_callback_result_vtbl); + + /* Create async results without startup. */ + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + IMFAsyncResult_Release(result); + IMFAsyncResult_Release(result2); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Before startup the platform lock count does not track the maximum AsyncResult count. */ + check_platform_lock_count(1); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Startup only locks once. */ + todo_wine + check_platform_lock_count(1); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform locked by the AsyncResult object. */ + check_platform_lock_count(2); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(3); + + IMFAsyncResult_Release(result); + IMFAsyncResult_Release(result2); + /* Platform lock count for AsyncResult objects does not decrease + * unless the platform is in shutdown state. */ + todo_wine + check_platform_lock_count(3); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform lock count tracks the maximum AsyncResult count plus one for startup. */ + todo_wine + check_platform_lock_count(3); + IMFAsyncResult_Release(result); + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 100, &callback_result); + ok(res == 0, "got %#lx\n", res); + refcount = IMFAsyncResult_Release(callback_result); + /* Release of an internal lock occurs in a worker thread. */ + flaky_wine + ok(!refcount, "Unexpected refcount %ld.\n", refcount); + todo_wine + check_platform_lock_count(3); + + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + todo_wine + check_platform_lock_count(5); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Platform is in shutdown state if either the lock count or the startup count is <= 0. */ + hr = MFAllocateWorkQueue(&queue); + todo_wine + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + /* Platform can be unlocked after shutdown. */ + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + /* Platform locks for AsyncResult objects were released on shutdown, but the explicit lock was not. */ + check_platform_lock_count(2); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Zero lock count. */ + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Negative lock count. */ + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(2); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Release an AsyncResult object after shutdown. Lock count tracks the AsyncResult count. + * It's not possible to show if unlock occurs immedately or on the next startup. */ + IMFAsyncResult_Release(result); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(2); + /* Release an AsyncResult object after shutdown and startup */ + IMFAsyncResult_Release(result); + todo_wine + check_platform_lock_count(2); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + /* The AsyncResult created for the item locks the platform */ + check_platform_lock_count(2); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key2); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + check_platform_lock_count(3); + + /* Platform locks for scheduled items are not released */ + hr = MFCancelWorkItem(key); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + hr = MFCancelWorkItem(key2); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + todo_wine + check_platform_lock_count(3); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + todo_wine + check_platform_lock_count(3); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + todo_wine + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + hr = MFCancelWorkItem(key); + todo_wine + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 0, &result); + ok(res == WAIT_TIMEOUT, "got res %#lx\n", res); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + /* Shutdown while a scheduled item is pending leaks the internal AsyncResult. */ + todo_wine + check_platform_lock_count(2); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); +} + static void test_allocate_queue(void) { DWORD queue, queue2; @@ -13340,6 +13533,7 @@ START_TEST(mfplat) CoInitialize(NULL);
test_startup(); + test_startup_counts(); test_register(); test_media_type(); test_MFCreateMediaEvent();
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/rtworkq/tests/rtworkq.c | 329 +++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+)
diff --git a/dlls/rtworkq/tests/rtworkq.c b/dlls/rtworkq/tests/rtworkq.c index 2ff74d57b84..1eb7f9c59a8 100644 --- a/dlls/rtworkq/tests/rtworkq.c +++ b/dlls/rtworkq/tests/rtworkq.c @@ -19,12 +19,148 @@ #include <stdarg.h> #include <string.h>
+#define COBJMACROS + #include "windef.h" #include "winbase.h" +#include "initguid.h" #include "rtworkq.h"
#include "wine/test.h"
+/* Should be kept in sync with corresponding MFASYNC_CALLBACK_ constants. */ +enum rtwq_callback_queue_id +{ + RTWQ_CALLBACK_QUEUE_UNDEFINED = 0x00000000, + RTWQ_CALLBACK_QUEUE_STANDARD = 0x00000001, + RTWQ_CALLBACK_QUEUE_RT = 0x00000002, + RTWQ_CALLBACK_QUEUE_IO = 0x00000003, + RTWQ_CALLBACK_QUEUE_TIMER = 0x00000004, + RTWQ_CALLBACK_QUEUE_MULTITHREADED = 0x00000005, + RTWQ_CALLBACK_QUEUE_LONG_FUNCTION = 0x00000007, + RTWQ_CALLBACK_QUEUE_PRIVATE_MASK = 0xffff0000, + RTWQ_CALLBACK_QUEUE_ALL = 0xffffffff, +}; + +#define check_platform_lock_count(a) check_platform_lock_count_(__LINE__, a) +static void check_platform_lock_count_(unsigned int line, unsigned int expected) +{ + unsigned int i, count = 0; + DWORD queue; + HRESULT hr; + + for (;;) + { + if (FAILED(hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue))) + break; + RtwqUnlockWorkQueue(queue); + + hr = RtwqUnlockPlatform(); + if (FAILED(hr)) + break; + ++count; + } + + for (i = 0; i < count; ++i) + RtwqLockPlatform(); + + ok_(__FILE__, line)(count == expected, "Unexpected lock count %u.\n", count); +} + +struct test_callback +{ + IRtwqAsyncCallback IRtwqAsyncCallback_iface; + LONG refcount; + HANDLE event; + IRtwqAsyncResult *result; +}; + +static struct test_callback *impl_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_callback, IRtwqAsyncCallback_iface); +} + +static HRESULT WINAPI testcallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IRtwqAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IRtwqAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI testcallback_AddRef(IRtwqAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IRtwqAsyncCallback(iface); + return InterlockedIncrement(&callback->refcount); +} + +static ULONG WINAPI testcallback_Release(IRtwqAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IRtwqAsyncCallback(iface); + ULONG refcount = InterlockedDecrement(&callback->refcount); + + if (!refcount) + { + CloseHandle(callback->event); + free(callback); + } + + return refcount; +} + +static HRESULT WINAPI testcallback_GetParameters(IRtwqAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testcallback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result) +{ + struct test_callback *callback = impl_from_IRtwqAsyncCallback(iface); + + callback->result = result; + SetEvent(callback->event); + + return S_OK; +} + +static const IRtwqAsyncCallbackVtbl testcallbackvtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + testcallback_Invoke, +}; + +static struct test_callback * create_test_callback(void) +{ + struct test_callback *callback = calloc(1, sizeof(*callback)); + + callback->IRtwqAsyncCallback_iface.lpVtbl = &testcallbackvtbl; + callback->refcount = 1; + callback->event = CreateEventA(NULL, FALSE, FALSE, NULL); + + return callback; +} + +static DWORD wait_async_callback_result(IRtwqAsyncCallback *iface, DWORD timeout, IRtwqAsyncResult **result) +{ + struct test_callback *callback = impl_from_IRtwqAsyncCallback(iface); + DWORD res = WaitForSingleObject(callback->event, timeout); + + *result = callback->result; + callback->result = NULL; + + return res; +} + static void test_platform_init(void) { APTTYPEQUALIFIER qualifier; @@ -101,7 +237,200 @@ static void test_platform_init(void) ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); }
+static void test_work_queue(void) +{ + IRtwqAsyncResult *result, *result2, *callback_result; + struct test_callback *test_callback; + RTWQWORKITEM_KEY key, key2; + DWORD res, queue; + LONG refcount; + HRESULT hr; + + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); + todo_wine + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + test_callback = create_test_callback(); + + /* Create async results without startup. */ + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + IRtwqAsyncResult_Release(result); + IRtwqAsyncResult_Release(result2); + + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Before startup the platform lock count does not track the maximum AsyncResult count. */ + check_platform_lock_count(1); + + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Startup only locks once. */ + todo_wine + check_platform_lock_count(1); + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform locked by the AsyncResult object. */ + check_platform_lock_count(2); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(3); + + IRtwqAsyncResult_Release(result); + IRtwqAsyncResult_Release(result2); + /* Platform lock count for AsyncResult objects does not decrease + * unless the platform is in shutdown state. */ + todo_wine + check_platform_lock_count(3); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform lock count tracks the maximum AsyncResult count plus one for startup. */ + todo_wine + check_platform_lock_count(3); + + hr = RtwqPutWorkItem(RTWQ_CALLBACK_QUEUE_STANDARD, 0, result); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&test_callback->IRtwqAsyncCallback_iface, 100, &callback_result); + ok(res == 0, "got %#lx\n", res); + /* TODO: Wine often has a release call pending in another thread at this point. */ + refcount = IRtwqAsyncResult_Release(result); + flaky_wine + todo_wine + ok(!refcount, "Unexpected refcount %ld.\n", refcount); + todo_wine + check_platform_lock_count(3); + + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + todo_wine + check_platform_lock_count(5); + + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Platform is in shutdown state if either the lock count or the startup count is <= 0. */ + hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); + todo_wine + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + /* Platform can be unlocked after shutdown. */ + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + /* Platform locks for AsyncResult objects were released on shutdown, but the explicit lock was not. */ + check_platform_lock_count(2); + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Zero lock count. */ + hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = RtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Negative lock count. */ + hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = RtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(2); + + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Release an AsyncResult object after shutdown. Platform lock count tracks the AsyncResult + * count. It's not possible to show if unlock occurs immedately or on the next startup. */ + IRtwqAsyncResult_Release(result); + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(1); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + hr = RtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(2); + /* Release an AsyncResult object after shutdown and startup. */ + IRtwqAsyncResult_Release(result); + todo_wine + check_platform_lock_count(2); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = RtwqScheduleWorkItem(result, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + check_platform_lock_count(2); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = RtwqScheduleWorkItem(result2, -5000, &key2); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + check_platform_lock_count(3); + + hr = RtwqCancelWorkItem(key); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + hr = RtwqCancelWorkItem(key2); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + IRtwqAsyncResult_Release(result); + IRtwqAsyncResult_Release(result2); + todo_wine + check_platform_lock_count(3); + + hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = RtwqScheduleWorkItem(result, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + todo_wine + check_platform_lock_count(3); + + hr = RtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + /* Shutdown while a scheduled item is pending leaks the AsyncResult. */ + refcount = IRtwqAsyncResult_Release(result); + ok(refcount == 1, "Unexpected refcount %ld.\n", refcount); + IRtwqAsyncResult_Release(result); + + hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + hr = RtwqCancelWorkItem(key); + todo_wine + ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + res = wait_async_callback_result(&test_callback->IRtwqAsyncCallback_iface, 0, &callback_result); + ok(res == WAIT_TIMEOUT, "got res %#lx\n", res); + + IRtwqAsyncCallback_Release(&test_callback->IRtwqAsyncCallback_iface); +} + START_TEST(rtworkq) { test_platform_init(); + test_work_queue(); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/mfplat.c | 14 ++++++++------ dlls/rtworkq/queue.c | 11 +++++++---- dlls/rtworkq/tests/rtworkq.c | 4 ---- 3 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 0afbb6c07b8..b1ed9a2b7a8 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3984,7 +3984,6 @@ void test_startup_counts(void) hr = MFLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); hr = MFAllocateWorkQueue(&queue); - todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); hr = MFUnlockPlatform(); ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); @@ -4007,7 +4006,6 @@ void test_startup_counts(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); /* Startup only locks once. */ - todo_wine check_platform_lock_count(1); hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -4058,7 +4056,6 @@ void test_startup_counts(void)
/* Platform is in shutdown state if either the lock count or the startup count is <= 0. */ hr = MFAllocateWorkQueue(&queue); - todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
/* Platform can be unlocked after shutdown. */ @@ -4142,11 +4139,9 @@ void test_startup_counts(void) ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr);
hr = MFAllocateWorkQueue(&queue); - todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
hr = MFCancelWorkItem(key); - todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 0, &result); @@ -4156,7 +4151,6 @@ void test_startup_counts(void) ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr);
/* Shutdown while a scheduled item is pending leaks the internal AsyncResult. */ - todo_wine check_platform_lock_count(2);
hr = MFShutdown(); @@ -4672,6 +4666,14 @@ static void test_event_queue(void)
hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* TODO: Wine leaks an async result. */ + Sleep(100); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_and_clear_platform_lock_count(1); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); }
static void test_presentation_descriptor(void) diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index 9046a70b359..4486aafc253 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -66,6 +66,7 @@ static CRITICAL_SECTION_DEBUG queues_critsect_debug = }; static CRITICAL_SECTION queues_section = { &queues_critsect_debug, -1, 0, 0, 0, 0 };
+static LONG startup_count; static LONG platform_lock; static CO_MTA_USAGE_COOKIE mta_cookie;
@@ -954,7 +955,7 @@ static HRESULT alloc_user_queue(const struct queue_desc *desc, DWORD *queue_id)
*queue_id = RTWQ_CALLBACK_QUEUE_UNDEFINED;
- if (platform_lock <= 0) + if (startup_count <= 0 || platform_lock <= 0) return RTWQ_E_SHUTDOWN;
if (!(queue = calloc(1, sizeof(*queue)))) @@ -1206,8 +1207,9 @@ static void init_system_queues(void)
HRESULT WINAPI RtwqStartup(void) { - if (InterlockedIncrement(&platform_lock) == 1) + if (InterlockedIncrement(&startup_count) == 1) { + RtwqLockPlatform(); init_system_queues(); }
@@ -1234,12 +1236,13 @@ static void shutdown_system_queues(void)
HRESULT WINAPI RtwqShutdown(void) { - if (platform_lock <= 0) + if (startup_count <= 0) return S_OK;
- if (InterlockedExchangeAdd(&platform_lock, -1) == 1) + if (InterlockedExchangeAdd(&startup_count, -1) == 1) { shutdown_system_queues(); + RtwqUnlockPlatform(); }
return S_OK; diff --git a/dlls/rtworkq/tests/rtworkq.c b/dlls/rtworkq/tests/rtworkq.c index 1eb7f9c59a8..df5a06e3690 100644 --- a/dlls/rtworkq/tests/rtworkq.c +++ b/dlls/rtworkq/tests/rtworkq.c @@ -249,7 +249,6 @@ static void test_work_queue(void) hr = RtwqLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); - todo_wine ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); hr = RtwqUnlockPlatform(); ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); @@ -272,7 +271,6 @@ static void test_work_queue(void) hr = RtwqStartup(); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); /* Startup only locks once. */ - todo_wine check_platform_lock_count(1); hr = RtwqShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -323,7 +321,6 @@ static void test_work_queue(void)
/* Platform is in shutdown state if either the lock count or the startup count is <= 0. */ hr = RtwqAllocateWorkQueue(RTWQ_STANDARD_WORKQUEUE, &queue); - todo_wine ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
/* Platform can be unlocked after shutdown. */ @@ -420,7 +417,6 @@ static void test_work_queue(void) ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
hr = RtwqCancelWorkItem(key); - todo_wine ok(hr == RTWQ_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
res = wait_async_callback_result(&test_callback->IRtwqAsyncCallback_iface, 0, &callback_result);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mfplat/tests/mfplat.c | 7 ------- dlls/rtworkq/queue.c | 37 +++++++++++++++++++++++++++++++++--- dlls/rtworkq/tests/rtworkq.c | 7 ------- 3 files changed, 34 insertions(+), 17 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index b1ed9a2b7a8..31773c4184c 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -4023,13 +4023,11 @@ void test_startup_counts(void) IMFAsyncResult_Release(result2); /* Platform lock count for AsyncResult objects does not decrease * unless the platform is in shutdown state. */ - todo_wine check_platform_lock_count(3);
hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); /* Platform lock count tracks the maximum AsyncResult count plus one for startup. */ - todo_wine check_platform_lock_count(3); IMFAsyncResult_Release(result);
@@ -4041,14 +4039,12 @@ void test_startup_counts(void) /* Release of an internal lock occurs in a worker thread. */ flaky_wine ok(!refcount, "Unexpected refcount %ld.\n", refcount); - todo_wine check_platform_lock_count(3);
hr = MFLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); hr = MFLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); - todo_wine check_platform_lock_count(5);
hr = MFShutdown(); @@ -4110,7 +4106,6 @@ void test_startup_counts(void) check_platform_lock_count(2); /* Release an AsyncResult object after shutdown and startup */ IMFAsyncResult_Release(result); - todo_wine check_platform_lock_count(2);
hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); @@ -4127,12 +4122,10 @@ void test_startup_counts(void) ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); hr = MFCancelWorkItem(key2); ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); - todo_wine check_platform_lock_count(3);
hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); - todo_wine check_platform_lock_count(3);
hr = MFShutdown(); diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index 4486aafc253..a4933fc62d7 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -66,6 +66,16 @@ static CRITICAL_SECTION_DEBUG queues_critsect_debug = }; static CRITICAL_SECTION queues_section = { &queues_critsect_debug, -1, 0, 0, 0, 0 };
+static union platform_lock_counts +{ + struct + { + UINT32 result_count; + UINT32 lock_count; + } counts; + LONG64 packed; +} platform_lock_counts; + static LONG startup_count; static LONG platform_lock; static CO_MTA_USAGE_COOKIE mta_cookie; @@ -1003,6 +1013,25 @@ static struct async_result *impl_from_IRtwqAsyncResult(IRtwqAsyncResult *iface) return CONTAINING_RECORD(iface, struct async_result, result.AsyncResult); }
+static void platform_lock_counts_add(INT32 new_results, INT32 new_locks) +{ + union platform_lock_counts old, new; + + do + { + new = old = platform_lock_counts; + new.counts.result_count += new_results; + + /* The lock count does not decrease unless the platform is not started. */ + if (new.counts.lock_count < new.counts.result_count || startup_count <= 0) + new.counts.lock_count = new.counts.result_count; + } + while (InterlockedCompareExchange64(&platform_lock_counts.packed, new.packed, old.packed) != old.packed); + + new_locks += new.counts.lock_count - old.counts.lock_count; + InterlockedAdd(&platform_lock, new_locks); +} + static HRESULT WINAPI async_result_QueryInterface(IRtwqAsyncResult *iface, REFIID riid, void **obj) { TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); @@ -1049,7 +1078,7 @@ static ULONG WINAPI async_result_Release(IRtwqAsyncResult *iface) CloseHandle(result->result.hEvent); free(result);
- RtwqUnlockPlatform(); + platform_lock_counts_add(-1, 0); }
return refcount; @@ -1136,7 +1165,7 @@ static HRESULT create_async_result(IUnknown *object, IRtwqAsyncCallback *callbac if (!(result = calloc(1, sizeof(*result)))) return E_OUTOFMEMORY;
- RtwqLockPlatform(); + platform_lock_counts_add(1, 0);
result->result.AsyncResult.lpVtbl = &async_result_vtbl; result->refcount = 1; @@ -1242,7 +1271,9 @@ HRESULT WINAPI RtwqShutdown(void) if (InterlockedExchangeAdd(&startup_count, -1) == 1) { shutdown_system_queues(); - RtwqUnlockPlatform(); + /* Shutdown frees excess locks for async results above the current result count. + * Typically no async results exist on shutdown, so all locks for them are freed. */ + platform_lock_counts_add(0, -1); }
return S_OK; diff --git a/dlls/rtworkq/tests/rtworkq.c b/dlls/rtworkq/tests/rtworkq.c index df5a06e3690..d1cd81d8f47 100644 --- a/dlls/rtworkq/tests/rtworkq.c +++ b/dlls/rtworkq/tests/rtworkq.c @@ -288,13 +288,11 @@ static void test_work_queue(void) IRtwqAsyncResult_Release(result2); /* Platform lock count for AsyncResult objects does not decrease * unless the platform is in shutdown state. */ - todo_wine check_platform_lock_count(3);
hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); /* Platform lock count tracks the maximum AsyncResult count plus one for startup. */ - todo_wine check_platform_lock_count(3);
hr = RtwqPutWorkItem(RTWQ_CALLBACK_QUEUE_STANDARD, 0, result); @@ -306,14 +304,12 @@ static void test_work_queue(void) flaky_wine todo_wine ok(!refcount, "Unexpected refcount %ld.\n", refcount); - todo_wine check_platform_lock_count(3);
hr = RtwqLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); hr = RtwqLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); - todo_wine check_platform_lock_count(5);
hr = RtwqShutdown(); @@ -375,7 +371,6 @@ static void test_work_queue(void) check_platform_lock_count(2); /* Release an AsyncResult object after shutdown and startup. */ IRtwqAsyncResult_Release(result); - todo_wine check_platform_lock_count(2);
hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); @@ -396,14 +391,12 @@ static void test_work_queue(void) ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); IRtwqAsyncResult_Release(result); IRtwqAsyncResult_Release(result2); - todo_wine check_platform_lock_count(3);
hr = RtwqCreateAsyncResult(NULL, &test_callback->IRtwqAsyncCallback_iface, NULL, &result); ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); hr = RtwqScheduleWorkItem(result, -5000, &key); ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); - todo_wine check_platform_lock_count(3);
hr = RtwqShutdown();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=151155
Your paranoid android.
=== w8 (32 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4042: Test failed: Unexpected lock count 1. mfplat.c:4048: Test failed: Unexpected lock count 3. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:4147: Test failed: Unexpected lock count 1. 0bf4:mfplat: unhandled exception c0000005 at 68754B26
=== w8adm (32 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4041: Test failed: Unexpected refcount 1. mfplat.c:4042: Test failed: Unexpected lock count 1. mfplat.c:4048: Test failed: Unexpected lock count 3. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:4147: Test failed: Unexpected lock count 1. 0aac:mfplat: unhandled exception c0000005 at 68BA4B26
=== w864 (32 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4042: Test failed: Unexpected lock count 1. mfplat.c:4048: Test failed: Unexpected lock count 3. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:4147: Test failed: Unexpected lock count 1. 0ac8:mfplat: unhandled exception c0000005 at 72934B26
=== w1064v1507 (32 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4042: Test failed: Unexpected lock count 1. mfplat.c:4048: Test failed: Unexpected lock count 3. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:1704: Test failed: Unexpected lock count 2. 0b28:mfplat: unhandled exception c0000005 at 748BFD7B
=== w1064v1809 (32 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 1f10:mfplat: unhandled exception c0000005 at 74846BF8
=== w1064_tsign (32 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 0670:mfplat: unhandled exception c0000005 at 74B19EE6
=== w10pro64 (32 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 0754:mfplat: unhandled exception c0000005 at 738DA066
=== w10pro64_en_AE_u8 (32 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 237c:mfplat: unhandled exception c0000005 at 7443A066
=== w11pro64 (32 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 1b00:mfplat: unhandled exception c0000005 at 73E5E68B
=== w864 (64 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4041: Test failed: Unexpected refcount 1. mfplat.c:4042: Test failed: Unexpected lock count 2. mfplat.c:4048: Test failed: Unexpected lock count 4. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:4147: Test failed: Unexpected lock count 1. 0ae4:mfplat: unhandled exception c0000005 at 0000000000BAD960
=== w1064v1507 (64 bit report) ===
mfplat: mfplat.c:4026: Test failed: Unexpected lock count 1. mfplat.c:4031: Test failed: Unexpected lock count 2. mfplat.c:4042: Test failed: Unexpected lock count 1. mfplat.c:4048: Test failed: Unexpected lock count 3. mfplat.c:4109: Test failed: Unexpected lock count 1. mfplat.c:4125: Test failed: Unexpected lock count 1. mfplat.c:4129: Test failed: Unexpected lock count 2. mfplat.c:1704: Test failed: Unexpected lock count 2. 0bd0:mfplat: unhandled exception c0000005 at 00000000008DD960
=== w1064v1809 (64 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 1e10:mfplat: unhandled exception c0000005 at 0000000000A9D960
=== w1064_2qxl (64 bit report) ===
mfplat: mfplat.c:1356: Test failed: Unexpected refcount 3 mfplat.c:1704: Test failed: Unexpected lock count 2. mfplat.c:4667: Test failed: Unexpected lock count 3. 1dc0:mfplat: unhandled exception c0000005 at 00000000009ED960
=== w1064_adm (64 bit report) ===
mfplat: mfplat.c:4041: Test failed: Unexpected refcount 1. mfplat.c:1356: Test failed: Unexpected refcount 3 mfplat.c:1704: Test failed: Unexpected lock count 2. 0dec:mfplat: unhandled exception c0000005 at 000000000038D960
=== w1064_tsign (64 bit report) ===
mfplat: mfplat.c:4041: Test failed: Unexpected refcount 1. mfplat.c:1356: Test failed: Unexpected refcount 3 mfplat.c:1704: Test failed: Unexpected lock count 2. 1e70:mfplat: unhandled exception c0000005 at 00000000009DD960
=== w10pro64 (64 bit report) ===
mfplat: mfplat.c:4041: Test failed: Unexpected refcount 1. mfplat.c:1704: Test failed: Unexpected lock count 2. 203c:mfplat: unhandled exception c0000005 at 0000000000F0D960
=== w10pro64_ar (64 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 23bc:mfplat: unhandled exception c0000005 at 00000000005BD960
=== w10pro64_ja (64 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 1254:mfplat: unhandled exception c0000005 at 00000000005BD960
=== w10pro64_zh_CN (64 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 1620:mfplat: unhandled exception c0000005 at 0000000000BFD960
=== w11pro64_amd (64 bit report) ===
mfplat: mfplat.c:1704: Test failed: Unexpected lock count 2. 209c:mfplat: unhandled exception c0000005 at 0000000000AAD960
=== w8 (32 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:306: Test failed: Unexpected refcount 1. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2. rtworkq.c:406: Test failed: Unexpected refcount 0.
=== w8adm (32 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2. rtworkq.c:406: Test failed: Unexpected refcount 0.
=== w864 (32 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:380: Test failed: Unexpected lock count 3. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2. rtworkq.c:406: Test failed: Unexpected refcount 0.
=== w1064v1507 (32 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2.
=== w864 (64 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2. rtworkq.c:406: Test failed: Unexpected refcount 0.
=== w1064v1507 (64 bit report) ===
rtworkq: rtworkq.c:291: Test failed: Unexpected lock count 1. rtworkq.c:296: Test failed: Unexpected lock count 2. rtworkq.c:307: Test failed: Unexpected lock count 1. rtworkq.c:313: Test failed: Unexpected lock count 3. rtworkq.c:374: Test failed: Unexpected lock count 1. rtworkq.c:394: Test failed: Unexpected lock count 1. rtworkq.c:400: Test failed: Unexpected lock count 2.
=== w1064_adm (64 bit report) ===
rtworkq: rtworkq.c:306: Test failed: Unexpected refcount 1.
=== w1064_tsign (64 bit report) ===
rtworkq: rtworkq.c:306: Test failed: Unexpected refcount 1.
=== debian11 (32 bit report) ===
Report validation errors: mfplat:mfplat crashed (c0000028)
=== debian11b (32 bit WoW report) ===
Report validation errors: mfplat:mfplat crashed (c0000028)
=== debian11b (64 bit WoW report) ===
user32: input.c:4306: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000002C400E4, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
The most likely explanation for the lock count not decreasing when async results are freed is that they are being cached. I may as well add that. The async result leak in test_source_resolver() is a bug in cancel cookies, but in native it's something else; probably their bug.