From: Yuxuan Shui yshui@codeweavers.com
Usually the threadpool holds a reference to the work_item, which is released when the work_item's callback is invoked (see `scheduled_item_cancelable_callback`). However if an item is cancelled by `queue_cancel_item`, that reference is not released.
This commit fixes this leak in `queue_cancel_item`, and also makes sure this reference is not double released if the callback happens to be running while `queue_cancel_item` is called. --- dlls/mfplat/tests/mfplat.c | 2 +- dlls/rtworkq/queue.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 363c240d13d..1e751b425fa 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3612,7 +3612,7 @@ static void test_scheduled_items(void) ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr);
refcount = IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); - todo_wine ok(refcount == 0, "Unexpected refcount %lu.\n", refcount); + ok(refcount == 0, "Unexpected refcount %lu.\n", refcount);
hr = MFCancelWorkItem(key); ok(hr == MF_E_NOT_FOUND || broken(hr == S_OK) /* < win10 */, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index 00b77bf6953..97d1cdc9f12 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -792,9 +792,10 @@ static void CALLBACK scheduled_item_cancelable_callback(TP_CALLBACK_INSTANCE *in TRACE("result object %p.\n", item->result);
if (queue_release_pending_item(item)) + { invoke_async_callback(item->result); - - IUnknown_Release(&item->IUnknown_iface); + IUnknown_Release(&item->IUnknown_iface); + } }
static void CALLBACK periodic_item_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_TIMER *timer) @@ -907,6 +908,7 @@ static HRESULT queue_cancel_item(struct queue *queue, RTWQWORKITEM_KEY key) else WARN("Unknown item key mask %#I64x.\n", key); queue_release_pending_item(item); + IUnknown_Release(&item->IUnknown_iface); hr = S_OK; break; }