Module: wine Branch: master Commit: d90ec79be2104acb3e2f59e31d3309591cd4f50d URL: http://source.winehq.org/git/wine.git/?a=commit;h=d90ec79be2104acb3e2f59e31d...
Author: Piotr Caban piotr@codeweavers.com Date: Tue Dec 29 14:39:01 2015 +0100
ole32: Make clipboard latest_snapshot access thread safe.
Signed-off-by: Piotr Caban piotr@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ole32/clipboard.c | 31 +++++++++++++++++++++++++------ dlls/ole32/tests/clipboard.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/dlls/ole32/clipboard.c b/dlls/ole32/clipboard.c index db1e4a8..ca9520f 100644 --- a/dlls/ole32/clipboard.c +++ b/dlls/ole32/clipboard.c @@ -174,6 +174,15 @@ typedef struct PresentationDataHeader */ static ole_clipbrd* theOleClipboard;
+static CRITICAL_SECTION latest_snapshot_cs; +static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug = +{ + 0, 0, &latest_snapshot_cs, + { &latest_snapshot_cs_debug.ProcessLocksList, &latest_snapshot_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": clipboard last snapshot") } +}; +static CRITICAL_SECTION latest_snapshot_cs = { &latest_snapshot_cs_debug, -1, 0, 0, 0, 0 }; + static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd) { struct oletls *info = COM_CurrentInfo(); @@ -1042,13 +1051,17 @@ static ULONG WINAPI snapshot_Release(IDataObject *iface)
if (ref == 0) { - ole_clipbrd *clipbrd; - HRESULT hr = get_ole_clipbrd(&clipbrd); + EnterCriticalSection(&latest_snapshot_cs); + if (This->ref) + { + LeaveCriticalSection(&latest_snapshot_cs); + return ref; + } + if (theOleClipboard->latest_snapshot == This) + theOleClipboard->latest_snapshot = NULL; + LeaveCriticalSection(&latest_snapshot_cs);
if(This->data) IDataObject_Release(This->data); - - if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This) - clipbrd->latest_snapshot = NULL; HeapFree(GetProcessHeap(), 0, This); }
@@ -2192,17 +2205,23 @@ HRESULT WINAPI OleGetClipboard(IDataObject **obj) if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
seq_no = GetClipboardSequenceNumber(); + EnterCriticalSection(&latest_snapshot_cs); if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no) clipbrd->latest_snapshot = NULL;
if(!clipbrd->latest_snapshot) { clipbrd->latest_snapshot = snapshot_construct(seq_no); - if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY; + if(!clipbrd->latest_snapshot) + { + LeaveCriticalSection(&latest_snapshot_cs); + return E_OUTOFMEMORY; + } }
*obj = &clipbrd->latest_snapshot->IDataObject_iface; IDataObject_AddRef(*obj); + LeaveCriticalSection(&latest_snapshot_cs);
return S_OK; } diff --git a/dlls/ole32/tests/clipboard.c b/dlls/ole32/tests/clipboard.c index 81b3a1c..02097ea 100644 --- a/dlls/ole32/tests/clipboard.c +++ b/dlls/ole32/tests/clipboard.c @@ -1539,6 +1539,38 @@ static void test_getdatahere(void)
}
+static DWORD CALLBACK test_data_obj(void *arg) +{ + IDataObject *data_obj = arg; + + IDataObject_Release(data_obj); + return 0; +} + +static void test_multithreaded_clipboard(void) +{ + IDataObject *data_obj; + HANDLE thread; + HRESULT hr; + DWORD ret; + + OleInitialize(NULL); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "OleGetClipboard returned %x\n", hr); + + thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL); + ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError()); + ret = WaitForSingleObject(thread, 5000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "OleGetClipboard returned %x\n", hr); + IDataObject_Release(data_obj); + + OleUninitialize(); +} + START_TEST(clipboard) { test_set_clipboard(); @@ -1546,4 +1578,5 @@ START_TEST(clipboard) test_flushed_getdata(); test_nonole_clipboard(); test_getdatahere(); + test_multithreaded_clipboard(); }