Skip to content

Commit 770f3fd

Browse files
Replace std::mutex with DefaultUnnamedMutex to avoid named mutex exhaustion (#950)
* DefaultUnnamedMutex migration * Migrating from DefaultUnnamedMutex to Mutex * Revert renaming * Using macro instead of HC_PLATFORM --------- Co-authored-by: Raul Gomez Rodriguez <raulalbertog@microsoft.com>
1 parent 4f2bd4a commit 770f3fd

9 files changed

Lines changed: 36 additions & 15 deletions

File tree

Include/httpClient/pal.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <stdbool.h>
1414
#include <stddef.h>
1515
#include <stdint.h>
16+
#include <mutex>
1617

1718
#include <httpClient/config.h>
1819

@@ -494,3 +495,23 @@ enum class HCWebSocketCloseStatus : uint32_t
494495
};
495496

496497
}
498+
499+
// On some platforms, std::mutex default construction creates named mutexes which have a low
500+
// system-wide limit. DefaultUnnamedMutex forces unnamed mutex construction on affected platforms.
501+
// Define HC_USE_UNNAMED_MUTEX in your platform build props to enable the workaround.
502+
#if defined(HC_USE_UNNAMED_MUTEX)
503+
class DefaultUnnamedMutex : public std::mutex
504+
{
505+
public:
506+
DefaultUnnamedMutex() noexcept : std::mutex(nullptr) {}
507+
~DefaultUnnamedMutex() noexcept = default;
508+
DefaultUnnamedMutex(DefaultUnnamedMutex const&) = delete;
509+
DefaultUnnamedMutex& operator=(DefaultUnnamedMutex const&) = delete;
510+
void lock() { std::mutex::lock(); }
511+
bool try_lock() { return std::mutex::try_lock(); }
512+
void unlock() { std::mutex::unlock(); }
513+
native_handle_type native_handle() { return std::mutex::native_handle(); }
514+
};
515+
#else
516+
using DefaultUnnamedMutex = std::mutex;
517+
#endif

Source/Global/NetworkState.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class NetworkState
7676
static void CALLBACK HttpProviderCleanupComplete(XAsyncBlock* async);
7777
bool ScheduleCleanup();
7878

79-
std::mutex m_mutex;
79+
DefaultUnnamedMutex m_mutex;
8080

8181
UniquePtr<IHttpProvider> m_httpProvider;
8282

Source/Global/global.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ HRESULT http_singleton::singleton_access(
2525
_Out_ std::shared_ptr<http_singleton>& singleton
2626
) noexcept
2727
{
28-
static std::mutex s_mutex;
28+
static DefaultUnnamedMutex s_mutex;
2929
static std::shared_ptr<http_singleton> s_singleton{ nullptr };
3030
static uint8_t s_useCount{ 0 };
3131

32-
std::lock_guard<std::mutex> lock{ s_mutex };
32+
std::lock_guard<DefaultUnnamedMutex> lock{ s_mutex };
3333
switch (mode)
3434
{
3535
case singleton_access_mode::create:

Source/Task/AsyncLib.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct AsyncState
4545
XAsyncBlock providerAsyncBlock { };
4646
XAsyncBlock* userAsyncBlock = nullptr;
4747
XTaskQueueHandle queue = nullptr;
48-
std::mutex waitMutex;
48+
DefaultUnnamedMutex waitMutex;
4949
std::condition_variable waitCondition;
5050
bool waitSatisfied = false;
5151

Source/Task/AtomicVector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class AtomicVector
9494

9595
private:
9696

97-
std::mutex m_lock;
97+
DefaultUnnamedMutex m_lock;
9898
std::vector<TElement> m_buffers[2];
9999
std::atomic<uint32_t> m_indexAndRef { 0 };
100100
};

Source/Task/TaskQueueImpl.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class SubmitCallback
114114
};
115115

116116
std::atomic<uint64_t> m_nextToken{ 0 };
117-
std::mutex m_lock;
117+
DefaultUnnamedMutex m_lock;
118118
CallbackRegistration m_buffer1[SUBMIT_CALLBACK_MAX];
119119
CallbackRegistration m_buffer2[SUBMIT_CALLBACK_MAX];
120120
CallbackRegistration* m_buffers[2]= { m_buffer1, m_buffer2 };
@@ -149,7 +149,7 @@ class QueueWaitRegistry
149149

150150
std::atomic<uint64_t> m_nextToken{ 0 };
151151
StaticArray<WaitRegistration, QUEUE_WAIT_MAX> m_callbacks;
152-
std::mutex m_lock;
152+
DefaultUnnamedMutex m_lock;
153153
};
154154

155155
class TaskQueuePortImpl: public Api<ApiId::TaskQueuePort, ITaskQueuePort>
@@ -257,12 +257,12 @@ class TaskQueuePortImpl: public Api<ApiId::TaskQueuePort, ITaskQueuePort>
257257
std::atomic<uint32_t> m_processingSerializedTbCallback{ 0 };
258258
std::atomic<uint32_t> m_processingCallback{ 0 };
259259
std::condition_variable m_processingCallbackCv;
260-
std::mutex m_lock;
260+
DefaultUnnamedMutex m_lock;
261261
std::unique_ptr<LocklessQueue<QueueEntry>> m_queueList;
262262
std::unique_ptr<LocklessQueue<QueueEntry>> m_pendingList;
263263
std::unique_ptr<LocklessQueue<TerminationEntry*>> m_terminationList;
264264
std::unique_ptr<LocklessQueue<TerminationEntry*>> m_pendingTerminationList;
265-
std::mutex m_terminationLock;
265+
DefaultUnnamedMutex m_terminationLock;
266266
OS::WaitTimer m_timer;
267267
OS::ThreadPool m_threadPool;
268268
std::atomic<uint64_t> m_timerDue = { UINT64_MAX };
@@ -465,7 +465,7 @@ class TaskQueueImpl : public Api<ApiId::TaskQueue, ITaskQueue>
465465
struct TerminationData
466466
{
467467
bool terminated;
468-
std::mutex lock;
468+
DefaultUnnamedMutex lock;
469469
std::condition_variable cv;
470470
};
471471

Source/Task/ThreadPool_stl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,12 @@ namespace OS
220220

221221
std::atomic<uint32_t> m_refs{ 1 };
222222

223-
std::mutex m_wakeLock;
223+
DefaultUnnamedMutex m_wakeLock;
224224
std::condition_variable m_wake;
225225
uint32_t m_calls{ 0 };
226226
bool m_terminate{ false };
227227

228-
std::mutex m_activeLock;
228+
DefaultUnnamedMutex m_activeLock;
229229
std::condition_variable m_active;
230230
uint32_t m_activeCalls{ 0 };
231231

Source/Task/WaitTimer_stl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ namespace OS
5353
TimerEntry const& Peek() const noexcept;
5454
TimerEntry Pop() noexcept;
5555

56-
std::mutex m_mutex;
56+
DefaultUnnamedMutex m_mutex;
5757
std::condition_variable m_cv;
5858
std::vector<TimerEntry> m_queue; // used as a heap
5959
std::thread m_t;
@@ -64,7 +64,7 @@ namespace OS
6464
namespace
6565
{
6666
std::shared_ptr<TimerQueue> g_timerQueue;
67-
std::mutex g_timerQueueMutex;
67+
DefaultUnnamedMutex g_timerQueueMutex;
6868
}
6969

7070
TimerQueue::~TimerQueue()

Source/WebSocket/hcwebsocket.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class WebSocket : public std::enable_shared_from_this<WebSocket>
181181
void* context{ nullptr };
182182
};
183183

184-
std::mutex m_stateMutex;
184+
DefaultUnnamedMutex m_stateMutex;
185185
enum class State
186186
{
187187
Initial,

0 commit comments

Comments
 (0)