@@ -75,8 +75,8 @@ class ScopedNotifyAllT {
75
75
// / A ConditionVariable that works with Mutex to allow -- as an example --
76
76
// / multi-threaded producers and consumers to signal each other in a safe way.
77
77
class ConditionVariable {
78
- friend class Mutex ;
79
- friend class StaticMutex ;
78
+ friend class ConditionMutex ;
79
+ friend class StaticConditionMutex ;
80
80
81
81
ConditionVariable (const ConditionVariable &) = delete ;
82
82
ConditionVariable &operator =(const ConditionVariable &) = delete ;
@@ -137,21 +137,27 @@ template <typename T, bool Inverted> class ScopedLockT {
137
137
};
138
138
139
139
class Mutex ;
140
+ class ConditionMutex ;
140
141
class StaticMutex ;
142
+ class StaticConditionMutex ;
141
143
142
144
// / A stack based object that locks the supplied mutex on construction
143
145
// / and unlocks it on destruction.
144
146
// /
145
147
// / Precondition: Mutex unlocked by this thread, undefined otherwise.
146
148
typedef ScopedLockT<Mutex, false > ScopedLock;
149
+ typedef ScopedLockT<ConditionMutex, false > ConditionScopedLock;
147
150
typedef ScopedLockT<StaticMutex, false > StaticScopedLock;
151
+ typedef ScopedLockT<StaticConditionMutex, false > StaticConditionScopedLock;
148
152
149
153
// / A stack based object that unlocks the supplied mutex on construction
150
154
// / and relocks it on destruction.
151
155
// /
152
156
// / Precondition: Mutex locked by this thread, undefined otherwise.
153
157
typedef ScopedLockT<Mutex, true > ScopedUnlock;
158
+ typedef ScopedLockT<ConditionMutex, true > ConditionScopedUnlock;
154
159
typedef ScopedLockT<StaticMutex, true > StaticScopedUnlock;
160
+ typedef ScopedLockT<StaticConditionMutex, true > StaticConditionScopedUnlock;
155
161
156
162
// / A Mutex object that supports `BasicLockable` and `Lockable` C++ concepts.
157
163
// / See http://en.cppreference.com/w/cpp/concept/BasicLockable
@@ -211,6 +217,85 @@ class Mutex {
211
217
// / - Does not throw exceptions but will halt on error (fatalError).
212
218
bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
213
219
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
+
214
299
// / Releases lock, waits on supplied condition, and relocks before returning.
215
300
// /
216
301
// / Precondition: Mutex held by this thread, undefined otherwise.
@@ -232,7 +317,7 @@ class Mutex {
232
317
// / Precondition: Mutex not held by this thread, undefined otherwise.
233
318
template <typename CriticalSection>
234
319
auto withLock (CriticalSection criticalSection) -> decltype(criticalSection()){
235
- ScopedLock guard (*this );
320
+ ConditionScopedLock guard (*this );
236
321
return criticalSection ();
237
322
}
238
323
@@ -318,7 +403,7 @@ class Mutex {
318
403
}
319
404
320
405
private:
321
- MutexHandle Handle;
406
+ ConditionMutexHandle Handle;
322
407
};
323
408
324
409
// / Compile time adjusted stack based object that locks/unlocks the supplied
@@ -557,7 +642,7 @@ class ReadWriteLock {
557
642
// /
558
643
// / Use ConditionVariable instead unless you need static allocation.
559
644
class StaticConditionVariable {
560
- friend class StaticMutex ;
645
+ friend class StaticConditionMutex ;
561
646
562
647
StaticConditionVariable (const StaticConditionVariable &) = delete ;
563
648
StaticConditionVariable &operator =(const StaticConditionVariable &) = delete ;
@@ -612,6 +697,45 @@ class StaticMutex {
612
697
// / See Mutex::try_lock
613
698
bool try_lock () { return MutexPlatformHelper::try_lock (Handle); }
614
699
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
+
615
739
// / See Mutex::wait
616
740
void wait (StaticConditionVariable &condition) {
617
741
ConditionPlatformHelper::wait (condition.Handle , Handle);
@@ -623,7 +747,7 @@ class StaticMutex {
623
747
// / See Mutex::lock
624
748
template <typename CriticalSection>
625
749
auto withLock (CriticalSection criticalSection) -> decltype(criticalSection()){
626
- StaticScopedLock guard (*this );
750
+ StaticConditionScopedLock guard (*this );
627
751
return criticalSection ();
628
752
}
629
753
@@ -661,7 +785,7 @@ class StaticMutex {
661
785
}
662
786
663
787
private:
664
- MutexHandle Handle;
788
+ ConditionMutexHandle Handle;
665
789
};
666
790
667
791
// / A static allocation variant of ReadWriteLock.
@@ -772,21 +896,18 @@ class StaticUnsafeMutex {
772
896
MutexHandle Handle;
773
897
};
774
898
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 ;
786
907
787
908
public:
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; }
790
911
791
912
void lock () { Ptr->lock (); }
792
913
@@ -798,6 +919,12 @@ class SmallMutex {
798
919
Mutex *Ptr;
799
920
};
800
921
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
+
801
928
// Enforce literal requirements for static variants.
802
929
#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR
803
930
static_assert (std::is_literal_type<StaticMutex>::value,
0 commit comments