From 8f6c4dd5362b1f708291ece6d211195685892725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Jan 2017 10:07:06 +0100 Subject: [PATCH] Fix LocalTaskSemaphore. Fixes a potential hang, potential over-use of lock slots and only needs a single LocalManualEvent now instead of one created for each wait. --- source/vibe/core/sync.d | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/source/vibe/core/sync.d b/source/vibe/core/sync.d index faa09a0..3ae3219 100644 --- a/source/vibe/core/sync.d +++ b/source/vibe/core/sync.d @@ -147,7 +147,6 @@ class LocalTaskSemaphore private { static struct ThreadWaiter { - LocalManualEvent signal; ubyte priority; uint seq; } @@ -156,11 +155,13 @@ class LocalTaskSemaphore uint m_maxLocks; uint m_locks; uint m_seq; + LocalManualEvent m_signal; } this(uint max_locks) { m_maxLocks = max_locks; + m_signal = createManualEvent(); } /// Maximum number of concurrent locks @@ -192,7 +193,7 @@ class LocalTaskSemaphore /** Acquires a lock. - Once the limit of concurrent locks is reaced, this method will block + Once the limit of concurrent locks is reached, this method will block until the number of locks drops below the limit. */ void lock(ubyte priority = 0) @@ -203,43 +204,38 @@ class LocalTaskSemaphore return; ThreadWaiter w; - w.signal = createManualEvent(); w.priority = priority; w.seq = min(0, m_seq - w.priority); if (++m_seq == uint.max) rewindSeq(); () @trusted { m_waiters.insert(w); } (); - do w.signal.wait(); while (!tryLock()); - // on resume: - destroy(w.signal); + + while (true) { + m_signal.waitUninterruptible(); + if (m_waiters.front.seq == w.seq && tryLock()) { + m_locks++; + return; + } + } } /** Gives up an existing lock. */ void unlock() { + assert(m_locks >= 1); m_locks--; - if (m_waiters.length > 0 && available > 0) { - ThreadWaiter w = m_waiters.front(); - w.signal.emit(); // resume one - () @trusted { m_waiters.removeFront(); } (); - } + if (m_waiters.length > 0) + m_signal.emit(); // resume one } // if true, a goes after b. ie. b comes out front() /// private static bool asc(ref ThreadWaiter a, ref ThreadWaiter b) { - if (a.seq == b.seq) { - if (a.priority == b.priority) { - // resolve using the pointer address - return (cast(size_t)&a.signal) > (cast(size_t) &b.signal); - } - // resolve using priority + if (a.priority != b.priority) return a.priority < b.priority; - } - // resolve using seq number return a.seq > b.seq; }