@@ -75,8 +75,8 @@ class ScopedNotifyAllT {
7575// / A ConditionVariable that works with Mutex to allow -- as an example --
7676// / multi-threaded producers and consumers to signal each other in a safe way.
7777class ConditionVariable {
78- friend class Mutex ;
79- friend class StaticMutex ;
78+ friend class ConditionMutex ;
79+ friend class StaticConditionMutex ;
8080
8181 ConditionVariable (const ConditionVariable &) = delete ;
8282 ConditionVariable &operator =(const ConditionVariable &) = delete ;
@@ -137,21 +137,27 @@ template <typename T, bool Inverted> class ScopedLockT {
137137};
138138
139139class Mutex ;
140+ class ConditionMutex ;
140141class StaticMutex ;
142+ class StaticConditionMutex ;
141143
142144// / A stack based object that locks the supplied mutex on construction
143145// / and unlocks it on destruction.
144146// /
145147// / Precondition: Mutex unlocked by this thread, undefined otherwise.
146148typedef ScopedLockT<Mutex, false > ScopedLock;
149+ typedef ScopedLockT<ConditionMutex, false > ConditionScopedLock;
147150typedef ScopedLockT<StaticMutex, false > StaticScopedLock;
151+ typedef ScopedLockT<StaticConditionMutex, false > StaticConditionScopedLock;
148152
149153// / A stack based object that unlocks the supplied mutex on construction
150154// / and relocks it on destruction.
151155// /
152156// / Precondition: Mutex locked by this thread, undefined otherwise.
153157typedef ScopedLockT<Mutex, true > ScopedUnlock;
158+ typedef ScopedLockT<ConditionMutex, true > ConditionScopedUnlock;
154159typedef ScopedLockT<StaticMutex, true > StaticScopedUnlock;
160+ typedef ScopedLockT<StaticConditionMutex, true > StaticConditionScopedUnlock;
155161
156162// / A Mutex object that supports `BasicLockable` and `Lockable` C++ concepts.
157163// / See http://en.cppreference.com/w/cpp/concept/BasicLockable
@@ -211,6 +217,85 @@ class Mutex {
211217 // / - Does not throw exceptions but will halt on error (fatalError).
212218 bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
213219
220+ // / Acquires lock before calling the supplied critical section and releases
221+ // / lock on return from critical section.
222+ // /
223+ // / This call can block while waiting for the lock to become available.
224+ // /
225+ // / For example the following mutates value while holding the mutex lock.
226+ // /
227+ // / ```
228+ // / mutex.lock([&value] { value++; });
229+ // / ```
230+ // /
231+ // / Precondition: Mutex not held by this thread, undefined otherwise.
232+ template <typename CriticalSection>
233+ auto withLock (CriticalSection criticalSection)
234+ -> decltype(criticalSection()) {
235+ ScopedLock guard (*this );
236+ return criticalSection ();
237+ }
238+
239+ private:
240+ MutexHandle Handle;
241+ };
242+
243+ // / A Mutex object that also supports ConditionVariables.
244+ // /
245+ // / This is NOT a recursive mutex.
246+ class ConditionMutex {
247+
248+ ConditionMutex (const ConditionMutex &) = delete ;
249+ ConditionMutex &operator =(const ConditionMutex &) = delete ;
250+ ConditionMutex (ConditionMutex &&) = delete ;
251+ ConditionMutex &operator =(ConditionMutex &&) = delete ;
252+
253+ public:
254+ // / Constructs a non-recursive mutex.
255+ // /
256+ // / If `checked` is true the mutex will attempt to check for misuse and
257+ // / fatalError when detected. If `checked` is false (the default) the
258+ // / mutex will make little to no effort to check for misuse (more efficient).
259+ explicit ConditionMutex (bool checked = false ) {
260+ MutexPlatformHelper::init (Handle, checked);
261+ }
262+ ~ConditionMutex () { MutexPlatformHelper::destroy (Handle); }
263+
264+ // / The lock() method has the following properties:
265+ // / - Behaves as an atomic operation.
266+ // / - Blocks the calling thread until exclusive ownership of the mutex
267+ // / can be obtained.
268+ // / - Prior m.unlock() operations on the same mutex synchronize-with
269+ // / this lock operation.
270+ // / - The behavior is undefined if the calling thread already owns
271+ // / the mutex (likely a deadlock).
272+ // / - Does not throw exceptions but will halt on error (fatalError).
273+ void lock () { MutexPlatformHelper::lock (Handle); }
274+
275+ // / The unlock() method has the following properties:
276+ // / - Behaves as an atomic operation.
277+ // / - Releases the calling thread's ownership of the mutex and
278+ // / synchronizes-with the subsequent successful lock operations on
279+ // / the same object.
280+ // / - The behavior is undefined if the calling thread does not own
281+ // / the mutex.
282+ // / - Does not throw exceptions but will halt on error (fatalError).
283+ void unlock () { MutexPlatformHelper::unlock (Handle); }
284+
285+ // / The try_lock() method has the following properties:
286+ // / - Behaves as an atomic operation.
287+ // / - Attempts to obtain exclusive ownership of the mutex for the calling
288+ // / thread without blocking. If ownership is not obtained, returns
289+ // / immediately. The function is allowed to spuriously fail and return
290+ // / even if the mutex is not currently owned by another thread.
291+ // / - If try_lock() succeeds, prior unlock() operations on the same object
292+ // / synchronize-with this operation. lock() does not synchronize with a
293+ // / failed try_lock()
294+ // / - The behavior is undefined if the calling thread already owns
295+ // / the mutex (likely a deadlock)?
296+ // / - Does not throw exceptions but will halt on error (fatalError).
297+ bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
298+
214299 // / Releases lock, waits on supplied condition, and relocks before returning.
215300 // /
216301 // / Precondition: Mutex held by this thread, undefined otherwise.
@@ -232,7 +317,7 @@ class Mutex {
232317 // / Precondition: Mutex not held by this thread, undefined otherwise.
233318 template <typename CriticalSection>
234319 auto withLock (CriticalSection criticalSection) -> decltype(criticalSection()){
235- ScopedLock guard (*this );
320+ ConditionScopedLock guard (*this );
236321 return criticalSection ();
237322 }
238323
@@ -318,7 +403,7 @@ class Mutex {
318403 }
319404
320405private:
321- MutexHandle Handle;
406+ ConditionMutexHandle Handle;
322407};
323408
324409// / Compile time adjusted stack based object that locks/unlocks the supplied
@@ -557,7 +642,7 @@ class ReadWriteLock {
557642// /
558643// / Use ConditionVariable instead unless you need static allocation.
559644class StaticConditionVariable {
560- friend class StaticMutex ;
645+ friend class StaticConditionMutex ;
561646
562647 StaticConditionVariable (const StaticConditionVariable &) = delete ;
563648 StaticConditionVariable &operator =(const StaticConditionVariable &) = delete ;
@@ -612,6 +697,45 @@ class StaticMutex {
612697 // / See Mutex::try_lock
613698 bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
614699
700+ // / See Mutex::lock
701+ template <typename CriticalSection>
702+ auto withLock (CriticalSection criticalSection)
703+ -> decltype(criticalSection()) {
704+ StaticScopedLock guard (*this );
705+ return criticalSection ();
706+ }
707+
708+ private:
709+ MutexHandle Handle;
710+ };
711+
712+ // / A static allocation variant of ConditionMutex.
713+ // /
714+ // / Use ConditionMutex instead unless you need static allocation.
715+ class StaticConditionMutex {
716+
717+ StaticConditionMutex (const StaticMutex &) = delete ;
718+ StaticConditionMutex &operator =(const StaticMutex &) = delete ;
719+ StaticConditionMutex (StaticMutex &&) = delete ;
720+ StaticConditionMutex &operator =(StaticMutex &&) = delete ;
721+
722+ public:
723+ #if SWIFT_MUTEX_SUPPORTS_CONSTEXPR
724+ constexpr
725+ #endif
726+ StaticConditionMutex ()
727+ : Handle(MutexPlatformHelper::conditionStaticInit()) {
728+ }
729+
730+ // / See Mutex::lock
731+ void lock () { MutexPlatformHelper::lock (Handle); }
732+
733+ // / See Mutex::unlock
734+ void unlock () { MutexPlatformHelper::unlock (Handle); }
735+
736+ // / See Mutex::try_lock
737+ bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
738+
615739 // / See Mutex::wait
616740 void wait (StaticConditionVariable &condition) {
617741 ConditionPlatformHelper::wait (condition.Handle , Handle);
@@ -623,7 +747,7 @@ class StaticMutex {
623747 // / See Mutex::lock
624748 template <typename CriticalSection>
625749 auto withLock (CriticalSection criticalSection) -> decltype(criticalSection()){
626- StaticScopedLock guard (*this );
750+ StaticConditionScopedLock guard (*this );
627751 return criticalSection ();
628752 }
629753
@@ -661,7 +785,7 @@ class StaticMutex {
661785 }
662786
663787private:
664- MutexHandle Handle;
788+ ConditionMutexHandle Handle;
665789};
666790
667791// / A static allocation variant of ReadWriteLock.
@@ -772,21 +896,18 @@ class StaticUnsafeMutex {
772896 MutexHandle Handle;
773897};
774898
775- // / A "small" variant of a Mutex. This allocates the mutex on the heap, for
776- // / places where having the mutex inline takes up too much space.
777- // /
778- // / TODO: On OSes that provide a smaller mutex type (e.g. os_unfair_lock on
779- // / Darwin), make SmallMutex use that and store it inline, or make Mutex use it
780- // / and this can become a typedef there.
781- class SmallMutex {
782- SmallMutex (const SmallMutex &) = delete ;
783- SmallMutex &operator =(const SmallMutex &) = delete ;
784- SmallMutex (SmallMutex &&) = delete ;
785- SmallMutex &operator =(SmallMutex &&) = delete ;
899+ // / An indirect variant of a Mutex. This allocates the mutex on the heap, for
900+ // / places where having the mutex inline takes up too much space. Used for
901+ // / SmallMutex on platforms where Mutex is large.
902+ class IndirectMutex {
903+ IndirectMutex (const IndirectMutex &) = delete ;
904+ IndirectMutex &operator =(const IndirectMutex &) = delete ;
905+ IndirectMutex (IndirectMutex &&) = delete ;
906+ IndirectMutex &operator =(IndirectMutex &&) = delete ;
786907
787908public:
788- explicit SmallMutex (bool checked = false ) { Ptr = new Mutex (checked); }
789- ~SmallMutex () { delete Ptr; }
909+ explicit IndirectMutex (bool checked = false ) { Ptr = new Mutex (checked); }
910+ ~IndirectMutex () { delete Ptr; }
790911
791912 void lock () { Ptr->lock (); }
792913
@@ -798,6 +919,12 @@ class SmallMutex {
798919 Mutex *Ptr;
799920};
800921
922+ // / A "small" mutex, which is pointer sized or smaller, for places where the
923+ // / mutex is stored inline with limited storage space. This uses a normal Mutex
924+ // / when that is small, and otherwise uses IndirectMutex.
925+ using SmallMutex =
926+ std::conditional_t <sizeof (Mutex) <= sizeof (void *), Mutex, IndirectMutex>;
927+
801928// Enforce literal requirements for static variants.
802929#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR
803930static_assert (std::is_literal_type<StaticMutex>::value,
0 commit comments