Last active
November 6, 2023 17:29
-
-
Save yshui/2f1c5c8ce9d80e9eef1db4eab51344d0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// !!!!!!! | |
// result: | |
// 07f0:err:seh:_assert ../wine/dlls/ntdll/threadpool.c:2124: Assertion failed "!object->num_running_callbacks" | |
// wine: Assertion failed at address 00006FFFFFF76228 (thread 07f0), starting debugger... | |
#include <stdexcept> | |
#define COBJMACROS | |
#include <atomic> | |
#include <initguid.h> | |
#include <mfapi.h> | |
#include <mferror.h> | |
#include <mfidl.h> | |
#include <mfmediaengine.h> | |
#include <mfobjects.h> | |
#include <mftransform.h> | |
#include <stdio.h> | |
#include <wtypes.h> | |
template <typename... Args> void ok(bool cond, const char *fmt, Args... args) { | |
char buf[1024]; | |
if (!cond) { | |
snprintf(buf, sizeof(buf), fmt, args...); | |
fprintf(stderr, "error: %s\n", buf); | |
throw std::runtime_error(buf); | |
} | |
} | |
#define trace(fmt, ...) \ | |
fprintf(stderr, "%s: " fmt, __PRETTY_FUNCTION__, ##__VA_ARGS__) | |
static std::atomic<bool> called; | |
struct Callback final : public IMFAsyncCallback { | |
private: | |
std::atomic<int> ref = 1; | |
const int id; | |
public: | |
Callback(int id_) : id(id_) {} | |
HRESULT __stdcall QueryInterface(REFIID riid, void **obj) override { | |
if (!obj) { | |
return E_INVALIDARG; | |
} | |
if (riid == IID_IMFAsyncCallback) { | |
*(IMFAsyncCallback **)obj = this; | |
AddRef(); | |
return S_OK; | |
} | |
*obj = nullptr; | |
return E_NOINTERFACE; | |
} | |
ULONG __stdcall AddRef() override { | |
int ret = ref.fetch_add(1) + 1; | |
// trace("Callback::AddRef %d\n", ret); | |
return ret; | |
} | |
ULONG __stdcall Release() override { | |
int ret = ref.fetch_sub(1) - 1; | |
// trace("Callback::Release %d\n", ret); | |
return ret; | |
} | |
HRESULT __stdcall Invoke(IMFAsyncResult *result) override { | |
called.store(true); | |
return S_OK; | |
} | |
HRESULT __stdcall GetParameters(DWORD *flags, DWORD *queue) override { | |
*flags = 0; | |
*queue = MFASYNC_CALLBACK_QUEUE_STANDARD; | |
return S_OK; | |
} | |
}; | |
int main() { | |
auto hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); | |
ok(SUCCEEDED(hr), "MFStartup failed: 0x%08x\n", hr); | |
for (int i = 0; i < 10; i++) { | |
called.store(false); | |
auto callback = new Callback(i); | |
MFWORKITEM_KEY key; | |
hr = MFScheduleWorkItem(callback, nullptr, 0, &key); | |
ok(SUCCEEDED(hr), "MFScheduleWorkItem failed: 0x%08x\n", hr); | |
auto ref = callback->Release(); | |
hr = MFCancelWorkItem(key); | |
if (SUCCEEDED(hr)) { | |
trace("MFCancelWorkItem succeeded\n"); | |
Sleep(100); | |
if (called.load()) { | |
trace("hit race!\n"); | |
break; | |
} | |
} else { | |
trace("MFCancelWorkItem failed: 0x%08x\n", hr); | |
} | |
} | |
hr = MFShutdown(); | |
ok(SUCCEEDED(hr), "MFShutdown failed: 0x%08x\n", hr); | |
Sleep(100); // callback isn't released by shutdown, but a bit later | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment