Skip to content

Instantly share code, notes, and snippets.

@yshui
Last active November 6, 2023 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yshui/2f1c5c8ce9d80e9eef1db4eab51344d0 to your computer and use it in GitHub Desktop.
Save yshui/2f1c5c8ce9d80e9eef1db4eab51344d0 to your computer and use it in GitHub Desktop.
// !!!!!!!
// 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