DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
Mutex.cpp
Go to the documentation of this file.
1#include "pch.h"
6#include "System/Char.h"
9#include <chrono>
10#include <mutex>
11
12#if defined(_WIN32)
13#include <windows.h>
14#endif
15
16namespace DotNetDupe {
17 namespace System {
18 namespace Threading {
19
20 struct Mutex::Impl {
21 std::timed_mutex mutex;
22 };
23
24 Mutex::Mutex() : _name(""), _hHandle(nullptr), _pImpl(new Impl()) {}
25
26 Mutex::Mutex(bool bInitiallyOwned) : _name(""), _hHandle(nullptr), _pImpl(new Impl()) {
28 if (bInitiallyOwned) {
29 _pImpl->mutex.lock();
30 }
31 }
32
33 static bool s_mutexDummyCreatedNew = false;
34 Mutex::Mutex(const String& sName, bool bInitiallyOwned, bool openAlways)
35 : Mutex(bInitiallyOwned, sName, openAlways, s_mutexDummyCreatedNew) {}
36
37 Mutex::Mutex(bool bInitiallyOwned, const String& sName, bool openAlways)
38 : Mutex(bInitiallyOwned, sName, openAlways, s_mutexDummyCreatedNew) {}
39
40#if defined(_WIN32)
41 static HANDLE OpenOrCreateWin32Mutex(const std::wstring& wsName, bool bInitiallyOwned, bool openAlways, bool& bCreatedNew) {
43 HANDLE hHandle = ::CreateMutexW(NULL, bInitiallyOwned ? TRUE : FALSE, wsName.c_str());
44 if (hHandle != NULL) {
45 bCreatedNew = (::GetLastError() != ERROR_ALREADY_EXISTS);
46 return hHandle;
47 }
48 if (::GetLastError() == ERROR_ACCESS_DENIED) {
49 throw UnauthorizedAccessException("Access denied creating Mutex synchronization object.");
50 }
51
53 bCreatedNew = false;
54 if (!openAlways) {
55 throw WaitHandleCannotBeOpenedException("Mutex creation returned null handle and openAlways is false.");
56 }
57 hHandle = ::OpenMutexW(SYNCHRONIZE, FALSE, wsName.c_str());
58 if (hHandle == NULL) {
59 if (::GetLastError() == ERROR_ACCESS_DENIED) {
60 throw UnauthorizedAccessException("Access denied opening existing Mutex synchronization object.");
61 }
62 throw WaitHandleCannotBeOpenedException("Failed to open existing mutex with SYNCHRONIZE access.");
63 }
64 return hHandle;
65 }
66#endif
67
68 Mutex::Mutex(bool bInitiallyOwned, const String& sName, bool openAlways, bool& bCreatedNew)
69 : _name(sName), _hHandle(nullptr), _pImpl(new Impl()) {
70#if defined(_WIN32)
72 if (!_name.IsEmpty()) {
73 std::wstring wsName = Utils::StringConvert::Utf8ToWChar(_name.GetRawString());
74 _hHandle = OpenOrCreateWin32Mutex(wsName, bInitiallyOwned, openAlways, bCreatedNew);
75 } else {
76 bCreatedNew = true;
77 if (bInitiallyOwned) {
78 _pImpl->mutex.lock();
79 }
80 }
81#else
82 bCreatedNew = true;
83 if (bInitiallyOwned) {
84 _pImpl->mutex.lock();
85 }
86#endif
87 }
88
91#if defined(_WIN32)
92 if (_hHandle != nullptr) {
93 ::CloseHandle((HANDLE)_hHandle);
94 _hHandle = nullptr;
95 }
96#endif
97 if (_pImpl != nullptr) {
98 delete _pImpl;
99 _pImpl = nullptr;
100 }
101 }
102
105 SmartPointer<Mutex> pResult = nullptr;
106 if (TryOpenExisting(sName, pResult)) {
107 return pResult;
108 }
109 throw WaitHandleCannotBeOpenedException("No mutex handle of the given name exists.");
110 }
111
112 bool Mutex::TryOpenExisting(const String& sName, SmartPointer<Mutex>& pResult) {
114 pResult = SmartPointer<Mutex>();
115 if (sName.IsEmpty()) return false;
116
117#if defined(_WIN32)
119 std::wstring wsName = Utils::StringConvert::Utf8ToWChar(sName.GetRawString());
120 HANDLE h = ::OpenMutexW(SYNCHRONIZE, FALSE, wsName.c_str());
121 if (h == NULL) return false;
122
124 spM->_name = sName;
125 spM->_hHandle = h;
126 pResult = std::move(spM);
127 return true;
128#else
129 return false;
130#endif
131 }
132
135#if defined(_WIN32)
136 if (_hHandle != nullptr) {
137 DWORD dwWaitResult = ::WaitForSingleObject((HANDLE)_hHandle, INFINITE);
138 return (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED);
139 }
140#endif
141 if (_pImpl) _pImpl->mutex.lock();
142 return true;
143 }
144
145 bool Mutex::WaitOne(int millisecondsTimeout) {
147#if defined(_WIN32)
148 if (_hHandle != nullptr) {
149 DWORD dwWaitResult = ::WaitForSingleObject((HANDLE)_hHandle, (DWORD)millisecondsTimeout);
150 if (dwWaitResult == WAIT_TIMEOUT) {
151 throw TimeoutException("The wait operation timed out.");
152 }
153 return (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED);
154 }
155#endif
156 if (!_pImpl || !_pImpl->mutex.try_lock_for(std::chrono::milliseconds(millisecondsTimeout))) {
157 throw TimeoutException("The wait operation timed out.");
158 }
159 return true;
160 }
161
162 int Mutex::Release(int releaseCount) {
164#if defined(_WIN32)
165 if (_hHandle != nullptr) {
166 ::ReleaseMutex((HANDLE)_hHandle);
167 return 0;
168 }
169#endif
170 if (_pImpl) _pImpl->mutex.unlock();
171 return 0;
172 }
173 }
174 }
175}
Represents a Unicode character code point mirroring .NET System.Char.
A synchronization primitive that can also be used for interprocess synchronization.
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
static SmartPointer< Mutex > OpenExisting(const String &sName)
Opens an existing named system mutex.
Definition Mutex.cpp:103
Mutex()
Initializes a new instance of the Mutex class with default properties.
Definition Mutex.cpp:24
int Release(int releaseCount=1) override
Releases the Mutex once.
Definition Mutex.cpp:162
~Mutex() override
Destructor releasing encapsulated mutex resources.
Definition Mutex.cpp:89
static bool TryOpenExisting(const String &sName, SmartPointer< Mutex > &pResult)
Opens an existing named system mutex, and returns a value that indicates whether the operation succee...
Definition Mutex.cpp:112
bool WaitOne() override
Blocks the current thread until the current WaitHandle receives a signal.
Definition Mutex.cpp:133
Exception thrown when an attempt to open a system synchronization handle that does not exist fails.
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 OpenOrCreateWin32Mutex(const std::wstring &wsName, bool bInitiallyOwned, bool openAlways, bool &bCreatedNew)
Definition Mutex.cpp:41
static bool s_mutexDummyCreatedNew
Definition Mutex.cpp:33