DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
EventWaitHandle.cpp
Go to the documentation of this file.
1#include "pch.h"
6#include "System/Char.h"
9#include <chrono>
10#include <mutex>
11#include <condition_variable>
12
13#if defined(_WIN32)
14#include <windows.h>
15#endif
16
17namespace DotNetDupe {
18 namespace System {
19 namespace Threading {
20
21 struct EventWaitHandle::Impl {
22 std::mutex mutex;
23 std::condition_variable cv;
24 };
25
26 EventWaitHandle::EventWaitHandle(bool initialState, bool manualReset)
27 : _state(initialState), _manualReset(manualReset), _name(""), _hHandle(nullptr), _pImpl(new Impl()) {}
28
29 static bool s_dummyCreatedNew = false;
30 EventWaitHandle::EventWaitHandle(const String& sName, bool initialState, bool manualReset, bool openAlways)
31 : EventWaitHandle(initialState, manualReset, sName, openAlways, s_dummyCreatedNew) {}
32
33 EventWaitHandle::EventWaitHandle(bool initialState, bool manualReset, const String& sName, bool openAlways)
34 : EventWaitHandle(initialState, manualReset, sName, openAlways, s_dummyCreatedNew) {}
35
36#if defined(_WIN32)
37 static HANDLE OpenOrCreateWin32Event(const std::wstring& wsName, bool manualReset, bool initialState, bool openAlways, bool& bCreatedNew) {
39 HANDLE hHandle = ::CreateEventW(NULL, manualReset ? TRUE : FALSE, initialState ? TRUE : FALSE, wsName.c_str());
40 if (hHandle != NULL) {
41 bCreatedNew = (::GetLastError() != ERROR_ALREADY_EXISTS);
42 return hHandle;
43 }
44 if (::GetLastError() == ERROR_ACCESS_DENIED) {
45 throw UnauthorizedAccessException("Access denied creating EventWaitHandle synchronization object.");
46 }
47
49 bCreatedNew = false;
50 if (!openAlways) {
51 throw WaitHandleCannotBeOpenedException("Event creation returned null handle and openAlways is false.");
52 }
53 hHandle = ::OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, wsName.c_str());
54 if (hHandle == NULL) {
55 if (::GetLastError() == ERROR_ACCESS_DENIED) {
56 throw UnauthorizedAccessException("Access denied opening existing EventWaitHandle synchronization object.");
57 }
58 throw WaitHandleCannotBeOpenedException("Failed to open existing event with SYNCHRONIZE access.");
59 }
60 return hHandle;
61 }
62#endif
63
64 EventWaitHandle::EventWaitHandle(bool initialState, bool manualReset, const String& sName, bool openAlways, bool& bCreatedNew)
65 : _state(initialState), _manualReset(manualReset), _name(sName), _hHandle(nullptr), _pImpl(new Impl()) {
66#if defined(_WIN32)
68 if (!_name.IsEmpty()) {
69 std::wstring wsName = Utils::StringConvert::Utf8ToWChar(_name.GetRawString());
70 _hHandle = OpenOrCreateWin32Event(wsName, manualReset, initialState, openAlways, bCreatedNew);
71 } else {
72 bCreatedNew = true;
73 }
74#else
75 bCreatedNew = true;
76#endif
77 }
78
81#if defined(_WIN32)
82 if (_hHandle != nullptr) {
83 ::CloseHandle((HANDLE)_hHandle);
84 _hHandle = nullptr;
85 }
86#endif
87 if (_pImpl != nullptr) {
88 delete _pImpl;
89 _pImpl = nullptr;
90 }
91 }
92
95 SmartPointer<EventWaitHandle> pResult = nullptr;
96 if (TryOpenExisting(sName, pResult)) {
97 return pResult;
98 }
99 throw WaitHandleCannotBeOpenedException("No event handle of the given name exists.");
100 }
101
104 pResult = nullptr;
105 if (sName.IsEmpty()) return false;
106
107#if defined(_WIN32)
109 std::wstring wsName = Utils::StringConvert::Utf8ToWChar(sName.GetRawString());
110 HANDLE h = ::OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, wsName.c_str());
111 if (!h) return false;
112
113 auto spEvt = SmartPointer<EventWaitHandle>::NewShared(false, false);
114 spEvt->_name = sName;
115 spEvt->_hHandle = h;
116 pResult = std::move(spEvt);
117 return true;
118#else
119 return false;
120#endif
121 }
122
125#if defined(_WIN32)
126 if (_hHandle != nullptr) {
127 return (::SetEvent((HANDLE)_hHandle) != FALSE);
128 }
129#endif
130 if (!_pImpl) return false;
131 std::lock_guard<std::mutex> lock(_pImpl->mutex);
132 _state = true;
133 if (_manualReset) {
134 _pImpl->cv.notify_all();
135 } else {
136 _pImpl->cv.notify_one();
137 }
138 return true;
139 }
140
143#if defined(_WIN32)
144 if (_hHandle != nullptr) {
145 return (::ResetEvent((HANDLE)_hHandle) != FALSE);
146 }
147#endif
148 if (!_pImpl) return false;
149 std::lock_guard<std::mutex> lock(_pImpl->mutex);
150 _state = false;
151 return true;
152 }
153
154 static bool WaitForEventCv(EventWaitHandle::Impl* pImpl, bool& bState, bool bManualReset) {
156 std::unique_lock<std::mutex> lock(pImpl->mutex);
157 pImpl->cv.wait(lock, [&bState]() { return bState; });
158 if (!bManualReset) bState = false;
159 return true;
160 }
161
162 static bool WaitForEventCv(EventWaitHandle::Impl* pImpl, bool& bState, bool bManualReset, int msTimeout) {
164 std::unique_lock<std::mutex> lock(pImpl->mutex);
165 bool bRes = pImpl->cv.wait_for(lock, std::chrono::milliseconds(msTimeout), [&bState]() { return bState; });
166 if (bRes) {
167 if (!bManualReset) bState = false;
168 return true;
169 }
170 throw TimeoutException("The wait operation timed out.");
171 }
172
175#if defined(_WIN32)
176 if (_hHandle != nullptr) {
177 DWORD dwWaitResult = ::WaitForSingleObject((HANDLE)_hHandle, INFINITE);
178 return (dwWaitResult == WAIT_OBJECT_0);
179 }
180#endif
181 if (!_pImpl) return false;
183 }
184
185 bool EventWaitHandle::WaitOne(int millisecondsTimeout) {
187#if defined(_WIN32)
188 if (_hHandle != nullptr) {
189 DWORD dwWaitResult = ::WaitForSingleObject((HANDLE)_hHandle, (DWORD)millisecondsTimeout);
190 if (dwWaitResult == WAIT_TIMEOUT) {
191 throw TimeoutException("The wait operation timed out.");
192 }
193 return (dwWaitResult == WAIT_OBJECT_0);
194 }
195#endif
196 if (!_pImpl) return false;
197 return WaitForEventCv(_pImpl, _state, _manualReset, millisecondsTimeout);
198 }
199 }
200 }
201}
Represents a Unicode character code point mirroring .NET System.Char.
Represents a thread synchronization event supporting automatic and manual reset modes.
Provides reference-counted and weak pointer memory management primitives ensuring zero raw ownership.
Utility routines for high-performance UTF-8, UTF-16, and wide-character string conversions.
Defines the exception thrown when the time allotted for a process or operation has expired.
The exception that is thrown when the operating system denies access because of an I/O error or a spe...
Exception thrown when an attempt to open a named system wait handle fails.
A unified smart pointer that supports both unique and shared ownership semantics.
static SmartPointer< T > NewShared()
Creates a Shared SmartPointer, default constructing T.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
Definition String.h:74
const char * GetRawString() const
Definition String.cpp:230
bool Set()
Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
static SmartPointer< EventWaitHandle > OpenExisting(const String &sName)
Opens an existing named system event wait handle.
static bool TryOpenExisting(const String &sName, SmartPointer< EventWaitHandle > &pResult)
Opens an existing named system event wait handle, and returns a value that indicates whether the oper...
bool WaitOne() override
Blocks the current thread until the current WaitHandle receives a signal.
~EventWaitHandle() override
Destructor closing event handle.
bool Reset()
Sets the state of the event to nonsignaled, causing threads to block.
EventWaitHandle(bool initialState, bool manualReset)
Initializes a new instance of the EventWaitHandle class, specifying whether the wait handle is initia...
WaitHandleCannotBeOpenedException(const String &sMessage)
Initializes a new instance of the WaitHandleCannotBeOpenedException class with a specified error mess...
TimeoutException(const String &sMessage)
Initializes a new instance of the TimeoutException class with a specified error message.
UnauthorizedAccessException()
Initializes a new instance of the UnauthorizedAccessException class with a default message.
Definition Exception.cpp:52
static std::wstring Utf8ToWChar(const char *pUtf8Str)
Converts a null-terminated UTF-8 char string into a UTF-16 std::wstring.
static HANDLE OpenOrCreateWin32Event(const std::wstring &wsName, bool manualReset, bool initialState, bool openAlways, bool &bCreatedNew)
static bool WaitForEventCv(EventWaitHandle::Impl *pImpl, bool &bState, bool bManualReset)