Small changes for cygwin build
[folly.git] / folly / Synchronized.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * This module implements a Synchronized abstraction useful in
19  * mutex-based concurrency.
20  *
21  * @author: Andrei Alexandrescu (andrei.alexandrescu@fb.com)
22  */
23
24 #ifndef SYNCHRONIZED_H_
25 #define SYNCHRONIZED_H_
26
27 #include <type_traits>
28 #include <mutex>
29 #include <boost/thread.hpp>
30 #include <folly/Preprocessor.h>
31 #include <folly/Traits.h>
32
33 namespace folly {
34
35 namespace detail {
36 enum InternalDoNotUse {};
37
38 /**
39  * Free function adaptors for std:: and boost::
40  */
41
42 /**
43  * Yields true iff T has .lock() and .unlock() member functions. This
44  * is done by simply enumerating the mutexes with this interface in
45  * std and boost.
46  */
47 template <class T>
48 struct HasLockUnlock {
49   enum { value = IsOneOf<T,
50          std::mutex, std::recursive_mutex,
51          boost::mutex, boost::recursive_mutex, boost::shared_mutex
52 // OSX and Cygwin don't have timed mutexes
53 #if !defined(__APPLE__) && !defined(__CYGWIN__)
54         ,std::timed_mutex, std::recursive_timed_mutex,
55          boost::timed_mutex, boost::recursive_timed_mutex
56 #endif
57          >::value };
58 };
59
60 /**
61  * Acquires a mutex for reading by calling .lock(). The exception is
62  * boost::shared_mutex, which has a special read-lock primitive called
63  * .lock_shared().
64  */
65 template <class T>
66 typename std::enable_if<
67   HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
68 acquireRead(T& mutex) {
69   mutex.lock();
70 }
71
72 /**
73  * Special case for boost::shared_mutex.
74  */
75 template <class T>
76 typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
77 acquireRead(T& mutex) {
78   mutex.lock_shared();
79 }
80
81 /**
82  * Acquires a mutex for reading with timeout by calling .timed_lock(). This
83  * applies to three of the boost mutex classes as enumerated below.
84  */
85 template <class T>
86 typename std::enable_if<std::is_same<T, boost::shared_mutex>::value, bool>::type
87 acquireRead(T& mutex,
88             unsigned int milliseconds) {
89   return mutex.timed_lock_shared(boost::posix_time::milliseconds(milliseconds));
90 }
91
92 /**
93  * Acquires a mutex for reading and writing by calling .lock().
94  */
95 template <class T>
96 typename std::enable_if<HasLockUnlock<T>::value>::type
97 acquireReadWrite(T& mutex) {
98   mutex.lock();
99 }
100
101 // OSX and Cygwin don't have timed mutexes
102 #if !defined(__APPLE__) && !defined(__CYGWIN__)
103 /**
104  * Acquires a mutex for reading and writing with timeout by calling
105  * .try_lock_for(). This applies to two of the std mutex classes as
106  * enumerated below.
107  */
108 template <class T>
109 typename std::enable_if<
110   IsOneOf<T, std::timed_mutex, std::recursive_timed_mutex>::value, bool>::type
111 acquireReadWrite(T& mutex,
112                  unsigned int milliseconds) {
113   // work around try_lock_for bug in some gcc versions, see
114   // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562
115   return mutex.try_lock()
116       || (milliseconds > 0 &&
117           mutex.try_lock_until(std::chrono::system_clock::now() +
118                                std::chrono::milliseconds(milliseconds)));
119 }
120
121 /**
122  * Acquires a mutex for reading and writing with timeout by calling
123  * .timed_lock(). This applies to three of the boost mutex classes as
124  * enumerated below.
125  */
126 template <class T>
127 typename std::enable_if<
128   IsOneOf<T, boost::shared_mutex, boost::timed_mutex,
129           boost::recursive_timed_mutex>::value, bool>::type
130 acquireReadWrite(T& mutex,
131                  unsigned int milliseconds) {
132   return mutex.timed_lock(boost::posix_time::milliseconds(milliseconds));
133 }
134 #endif // __APPLE__
135
136 /**
137  * Releases a mutex previously acquired for reading by calling
138  * .unlock(). The exception is boost::shared_mutex, which has a
139  * special primitive called .unlock_shared().
140  */
141 template <class T>
142 typename std::enable_if<
143   HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
144 releaseRead(T& mutex) {
145   mutex.unlock();
146 }
147
148 /**
149  * Special case for boost::shared_mutex.
150  */
151 template <class T>
152 typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
153 releaseRead(T& mutex) {
154   mutex.unlock_shared();
155 }
156
157 /**
158  * Releases a mutex previously acquired for reading-writing by calling
159  * .unlock().
160  */
161 template <class T>
162 typename std::enable_if<HasLockUnlock<T>::value>::type
163 releaseReadWrite(T& mutex) {
164   mutex.unlock();
165 }
166
167 } // namespace detail
168
169 /**
170  * Synchronized<T> encapsulates an object of type T (a "datum") paired
171  * with a mutex. The only way to access the datum is while the mutex
172  * is locked, and Synchronized makes it virtually impossible to do
173  * otherwise. The code that would access the datum in unsafe ways
174  * would look odd and convoluted, thus readily alerting the human
175  * reviewer. In contrast, the code that uses Synchronized<T> correctly
176  * looks simple and intuitive.
177  *
178  * The second parameter must be a mutex type. Supported mutexes are
179  * std::mutex, std::recursive_mutex, std::timed_mutex,
180  * std::recursive_timed_mutex, boost::mutex, boost::recursive_mutex,
181  * boost::shared_mutex, boost::timed_mutex,
182  * boost::recursive_timed_mutex, and the folly/RWSpinLock.h
183  * classes.
184  *
185  * You may define Synchronized support by defining 4-6 primitives in
186  * the same namespace as the mutex class (found via ADL).  The
187  * primitives are: acquireRead, acquireReadWrite, releaseRead, and
188  * releaseReadWrite. Two optional primitives for timout operations are
189  * overloads of acquireRead and acquireReadWrite. For signatures,
190  * refer to the namespace detail below, which implements the
191  * primitives for mutexes in std and boost.
192  */
193 template <class T, class Mutex = boost::shared_mutex>
194 struct Synchronized {
195   /**
196    * Default constructor leaves both members call their own default
197    * constructor.
198    */
199   Synchronized() = default;
200
201   /**
202    * Copy constructor copies the data (with locking the source and
203    * all) but does NOT copy the mutex. Doing so would result in
204    * deadlocks.
205    */
206   Synchronized(const Synchronized& rhs) {
207     auto guard = rhs.operator->();
208     datum_ = rhs.datum_;
209   }
210
211   /**
212    * Move constructor moves the data (with locking the source and all)
213    * but does not move the mutex.
214    */
215   Synchronized(Synchronized&& rhs) {
216     auto guard = rhs.operator->();
217     datum_ = std::move(rhs.datum_);
218   }
219
220   /**
221    * Constructor taking a datum as argument copies it. There is no
222    * need to lock the constructing object.
223    */
224   explicit Synchronized(const T& rhs) : datum_(rhs) {}
225
226   /**
227    * Constructor taking a datum rvalue as argument moves it. Again,
228    * there is no need to lock the constructing object.
229    */
230   explicit Synchronized(T&& rhs) : datum_(std::move(rhs)) {}
231
232   /**
233    * The canonical assignment operator only assigns the data, NOT the
234    * mutex. It locks the two objects in ascending order of their
235    * addresses.
236    */
237   Synchronized& operator=(const Synchronized& rhs) {
238     if (this == &rhs) {
239       // Self-assignment, pass.
240     } else if (this < &rhs) {
241       auto guard1 = operator->();
242       auto guard2 = rhs.operator->();
243       datum_ = rhs.datum_;
244     } else {
245       auto guard1 = rhs.operator->();
246       auto guard2 = operator->();
247       datum_ = rhs.datum_;
248     }
249     return *this;
250   }
251
252   /**
253    * Move assignment operator, only assigns the data, NOT the
254    * mutex. It locks the two objects in ascending order of their
255    * addresses.
256    */
257   Synchronized& operator=(Synchronized&& rhs) {
258     if (this == &rhs) {
259       // Self-assignment, pass.
260     } else if (this < &rhs) {
261       auto guard1 = operator->();
262       auto guard2 = rhs.operator->();
263       datum_ = std::move(rhs.datum_);
264     } else {
265       auto guard1 = rhs.operator->();
266       auto guard2 = operator->();
267       datum_ = std::move(rhs.datum_);
268     }
269     return *this;
270   }
271
272   /**
273    * Lock object, assign datum.
274    */
275   Synchronized& operator=(const T& rhs) {
276     auto guard = operator->();
277     datum_ = rhs;
278     return *this;
279   }
280
281   /**
282    * Lock object, move-assign datum.
283    */
284   Synchronized& operator=(T&& rhs) {
285     auto guard = operator->();
286     datum_ = std::move(rhs);
287     return *this;
288   }
289
290   /**
291    * A LockedPtr lp keeps a modifiable (i.e. non-const)
292    * Synchronized<T> object locked for the duration of lp's
293    * existence. Because of this, you get to access the datum's methods
294    * directly by using lp->fun().
295    */
296   struct LockedPtr {
297     /**
298      * Found no reason to leave this hanging.
299      */
300     LockedPtr() = delete;
301
302     /**
303      * Takes a Synchronized and locks it.
304      */
305     explicit LockedPtr(Synchronized* parent) : parent_(parent) {
306       acquire();
307     }
308
309     /**
310      * Takes a Synchronized and attempts to lock it for some
311      * milliseconds. If not, the LockedPtr will be subsequently null.
312      */
313     LockedPtr(Synchronized* parent, unsigned int milliseconds) {
314       using namespace detail;
315       if (acquireReadWrite(parent->mutex_, milliseconds)) {
316         parent_ = parent;
317         return;
318       }
319       // Could not acquire the resource, pointer is null
320       parent_ = nullptr;
321     }
322
323     /**
324      * This is used ONLY inside SYNCHRONIZED_DUAL. It initializes
325      * everything properly, but does not lock the parent because it
326      * "knows" someone else will lock it. Please do not use.
327      */
328     LockedPtr(Synchronized* parent, detail::InternalDoNotUse)
329         : parent_(parent) {
330     }
331
332     /**
333      * Copy ctor adds one lock.
334      */
335     LockedPtr(const LockedPtr& rhs) : parent_(rhs.parent_) {
336       acquire();
337     }
338
339     /**
340      * Assigning from another LockedPtr results in freeing the former
341      * lock and acquiring the new one. The method works with
342      * self-assignment (does nothing).
343      */
344     LockedPtr& operator=(const LockedPtr& rhs) {
345       if (parent_ != rhs.parent_) {
346         if (parent_) parent_->mutex_.unlock();
347         parent_ = rhs.parent_;
348         acquire();
349       }
350       return *this;
351     }
352
353     /**
354      * Destructor releases.
355      */
356     ~LockedPtr() {
357       using namespace detail;
358       if (parent_) releaseReadWrite(parent_->mutex_);
359     }
360
361     /**
362      * Safe to access the data. Don't save the obtained pointer by
363      * invoking lp.operator->() by hand. Also, if the method returns a
364      * handle stored inside the datum, don't use this idiom - use
365      * SYNCHRONIZED below.
366      */
367     T* operator->() {
368       return parent_ ? &parent_->datum_ : nullptr;
369     }
370
371     /**
372      * This class temporarily unlocks a LockedPtr in a scoped
373      * manner. It is used inside of the UNSYNCHRONIZED macro.
374      */
375     struct Unsynchronizer {
376       explicit Unsynchronizer(LockedPtr* p) : parent_(p) {
377         using namespace detail;
378         releaseReadWrite(parent_->parent_->mutex_);
379       }
380       Unsynchronizer(const Unsynchronizer&) = delete;
381       Unsynchronizer& operator=(const Unsynchronizer&) = delete;
382       ~Unsynchronizer() {
383         parent_->acquire();
384       }
385       LockedPtr* operator->() const {
386         return parent_;
387       }
388     private:
389       LockedPtr* parent_;
390     };
391     friend struct Unsynchronizer;
392     Unsynchronizer typeHackDoNotUse();
393
394     template <class P1, class P2>
395     friend void lockInOrder(P1& p1, P2& p2);
396
397   private:
398     void acquire() {
399       using namespace detail;
400       if (parent_) acquireReadWrite(parent_->mutex_);
401     }
402
403     // This is the entire state of LockedPtr.
404     Synchronized* parent_;
405   };
406
407   /**
408    * ConstLockedPtr does exactly what LockedPtr does, but for const
409    * Synchronized objects. Of interest is that ConstLockedPtr only
410    * uses a read lock, which is faster but more restrictive - you only
411    * get to call const methods of the datum.
412    *
413    * Much of the code between LockedPtr and
414    * ConstLockedPtr is identical and could be factor out, but there
415    * are enough nagging little differences to not justify the trouble.
416    */
417   struct ConstLockedPtr {
418     ConstLockedPtr() = delete;
419     explicit ConstLockedPtr(const Synchronized* parent) : parent_(parent) {
420       acquire();
421     }
422     ConstLockedPtr(const Synchronized* parent, detail::InternalDoNotUse)
423         : parent_(parent) {
424     }
425     ConstLockedPtr(const ConstLockedPtr& rhs) : parent_(rhs.parent_) {
426       acquire();
427     }
428     explicit ConstLockedPtr(const LockedPtr& rhs) : parent_(rhs.parent_) {
429       acquire();
430     }
431     ConstLockedPtr(const Synchronized* parent, unsigned int milliseconds) {
432       if (parent->mutex_.timed_lock_shared(
433             boost::posix_time::milliseconds(milliseconds))) {
434         parent_ = parent;
435         return;
436       }
437       // Could not acquire the resource, pointer is null
438       parent_ = nullptr;
439     }
440
441     ConstLockedPtr& operator=(const ConstLockedPtr& rhs) {
442       if (parent_ != rhs.parent_) {
443         if (parent_) parent_->mutex_.unlock_shared();
444         parent_ = rhs.parent_;
445         acquire();
446       }
447     }
448     ~ConstLockedPtr() {
449       using namespace detail;
450       if (parent_) releaseRead(parent_->mutex_);
451     }
452
453     const T* operator->() const {
454       return parent_ ? &parent_->datum_ : nullptr;
455     }
456
457     struct Unsynchronizer {
458       explicit Unsynchronizer(ConstLockedPtr* p) : parent_(p) {
459         using namespace detail;
460         releaseRead(parent_->parent_->mutex_);
461       }
462       Unsynchronizer(const Unsynchronizer&) = delete;
463       Unsynchronizer& operator=(const Unsynchronizer&) = delete;
464       ~Unsynchronizer() {
465         using namespace detail;
466         acquireRead(parent_->parent_->mutex_);
467       }
468       ConstLockedPtr* operator->() const {
469         return parent_;
470       }
471     private:
472       ConstLockedPtr* parent_;
473     };
474     friend struct Unsynchronizer;
475     Unsynchronizer typeHackDoNotUse();
476
477     template <class P1, class P2>
478     friend void lockInOrder(P1& p1, P2& p2);
479
480   private:
481     void acquire() {
482       using namespace detail;
483       if (parent_) acquireRead(parent_->mutex_);
484     }
485
486     const Synchronized* parent_;
487   };
488
489   /**
490    * This accessor offers a LockedPtr. In turn. LockedPtr offers
491    * operator-> returning a pointer to T. The operator-> keeps
492    * expanding until it reaches a pointer, so syncobj->foo() will lock
493    * the object and call foo() against it.
494   */
495   LockedPtr operator->() {
496     return LockedPtr(this);
497   }
498
499   /**
500    * Same, for constant objects. You will be able to invoke only const
501    * methods.
502    */
503   ConstLockedPtr operator->() const {
504     return ConstLockedPtr(this);
505   }
506
507   /**
508    * Attempts to acquire for a given number of milliseconds. If
509    * acquisition is unsuccessful, the returned LockedPtr is NULL.
510    */
511   LockedPtr timedAcquire(unsigned int milliseconds) {
512     return LockedPtr(this, milliseconds);
513   }
514
515   /**
516    * As above, for a constant object.
517    */
518   ConstLockedPtr timedAcquire(unsigned int milliseconds) const {
519     return ConstLockedPtr(this, milliseconds);
520   }
521
522   /**
523    * Used by SYNCHRONIZED_DUAL.
524    */
525   LockedPtr internalDoNotUse() {
526     return LockedPtr(this, detail::InternalDoNotUse());
527   }
528
529   /**
530    * ditto
531    */
532   ConstLockedPtr internalDoNotUse() const {
533     return ConstLockedPtr(this, detail::InternalDoNotUse());
534   }
535
536   /**
537    * Sometimes, although you have a mutable object, you only want to
538    * call a const method against it. The most efficient way to achieve
539    * that is by using a read lock. You get to do so by using
540    * obj.asConst()->method() instead of obj->method().
541    */
542   const Synchronized& asConst() const {
543     return *this;
544   }
545
546   /**
547    * Swaps with another Synchronized. Protected against
548    * self-swap. Only data is swapped. Locks are acquired in increasing
549    * address order.
550    */
551   void swap(Synchronized& rhs) {
552     if (this == &rhs) {
553       return;
554     }
555     if (this > &rhs) {
556       return rhs.swap(*this);
557     }
558     auto guard1 = operator->();
559     auto guard2 = rhs.operator->();
560
561     using std::swap;
562     swap(datum_, rhs.datum_);
563   }
564
565   /**
566    * Swap with another datum. Recommended because it keeps the mutex
567    * held only briefly.
568    */
569   void swap(T& rhs) {
570     LockedPtr guard = operator->();
571
572     using std::swap;
573     swap(datum_, rhs);
574   }
575
576   /**
577    * Copies datum to a given target.
578    */
579   void copy(T* target) const {
580     ConstLockedPtr guard = operator->();
581     *target = datum_;
582   }
583
584   /**
585    * Returns a fresh copy of the datum.
586    */
587   T copy() const {
588     ConstLockedPtr guard = operator->();
589     return datum_;
590   }
591
592 private:
593   T datum_;
594   mutable Mutex mutex_;
595 };
596
597 // Non-member swap primitive
598 template <class T, class M>
599 void swap(Synchronized<T, M>& lhs, Synchronized<T, M>& rhs) {
600   lhs.swap(rhs);
601 }
602
603 /**
604  * SYNCHRONIZED is the main facility that makes Synchronized<T>
605  * helpful. It is a pseudo-statement that introduces a scope where the
606  * object is locked. Inside that scope you get to access the unadorned
607  * datum.
608  *
609  * Example:
610  *
611  * Synchronized<vector<int>> svector;
612  * ...
613  * SYNCHRONIZED (svector) { ... use svector as a vector<int> ... }
614  * or
615  * SYNCHRONIZED (v, svector) { ... use v as a vector<int> ... }
616  *
617  * Refer to folly/docs/Synchronized.md for a detailed explanation and more
618  * examples.
619  */
620 #define SYNCHRONIZED(...)                                       \
621   if (bool SYNCHRONIZED_state = false) {} else                  \
622     for (auto SYNCHRONIZED_lockedPtr =                          \
623            (FB_ARG_2_OR_1(__VA_ARGS__)).operator->();           \
624          !SYNCHRONIZED_state; SYNCHRONIZED_state = true)        \
625       for (auto& FB_ARG_1(__VA_ARGS__) =                        \
626              *SYNCHRONIZED_lockedPtr.operator->();              \
627            !SYNCHRONIZED_state; SYNCHRONIZED_state = true)
628
629 #define TIMED_SYNCHRONIZED(timeout, ...)                           \
630   if (bool SYNCHRONIZED_state = false) {} else                     \
631     for (auto SYNCHRONIZED_lockedPtr =                             \
632            (FB_ARG_2_OR_1(__VA_ARGS__)).timedAcquire(timeout);     \
633          !SYNCHRONIZED_state; SYNCHRONIZED_state = true)           \
634       for (auto FB_ARG_1(__VA_ARGS__) =                            \
635              SYNCHRONIZED_lockedPtr.operator->();                  \
636            !SYNCHRONIZED_state; SYNCHRONIZED_state = true)
637
638 /**
639  * Similar to SYNCHRONIZED, but only uses a read lock.
640  */
641 #define SYNCHRONIZED_CONST(...)                         \
642   SYNCHRONIZED(FB_ARG_1(__VA_ARGS__),                   \
643                (FB_ARG_2_OR_1(__VA_ARGS__)).asConst())
644
645 /**
646  * Similar to TIMED_SYNCHRONIZED, but only uses a read lock.
647  */
648 #define TIMED_SYNCHRONIZED_CONST(timeout, ...)                  \
649   TIMED_SYNCHRONIZED(timeout, FB_ARG_1(__VA_ARGS__),            \
650                      (FB_ARG_2_OR_1(__VA_ARGS__)).asConst())
651
652 /**
653  * Temporarily disables synchronization inside a SYNCHRONIZED block.
654  */
655 #define UNSYNCHRONIZED(name)                                    \
656   for (decltype(SYNCHRONIZED_lockedPtr.typeHackDoNotUse())      \
657          SYNCHRONIZED_state3(&SYNCHRONIZED_lockedPtr);          \
658        !SYNCHRONIZED_state; SYNCHRONIZED_state = true)          \
659     for (auto name = *SYNCHRONIZED_state3.operator->();         \
660          !SYNCHRONIZED_state; SYNCHRONIZED_state = true)
661
662 /**
663  * Locks two objects in increasing order of their addresses.
664  */
665 template <class P1, class P2>
666 void lockInOrder(P1& p1, P2& p2) {
667   if (static_cast<const void*>(p1.operator->()) >
668       static_cast<const void*>(p2.operator->())) {
669     p2.acquire();
670     p1.acquire();
671   } else {
672     p1.acquire();
673     p2.acquire();
674   }
675 }
676
677 /**
678  * Synchronizes two Synchronized objects (they may encapsulate
679  * different data). Synchronization is done in increasing address of
680  * object order, so there is no deadlock risk.
681  */
682 #define SYNCHRONIZED_DUAL(n1, e1, n2, e2)                       \
683   if (bool SYNCHRONIZED_state = false) {} else                  \
684     for (auto SYNCHRONIZED_lp1 = (e1).internalDoNotUse();       \
685          !SYNCHRONIZED_state; SYNCHRONIZED_state = true)        \
686       for (auto& n1 = *SYNCHRONIZED_lp1.operator->();           \
687            !SYNCHRONIZED_state;  SYNCHRONIZED_state = true)     \
688         for (auto SYNCHRONIZED_lp2 = (e2).internalDoNotUse();   \
689              !SYNCHRONIZED_state;  SYNCHRONIZED_state = true)   \
690           for (auto& n2 = *SYNCHRONIZED_lp2.operator->();       \
691                !SYNCHRONIZED_state; SYNCHRONIZED_state = true)  \
692             if ((::folly::lockInOrder(                          \
693                    SYNCHRONIZED_lp1, SYNCHRONIZED_lp2),         \
694                  false)) {}                                     \
695             else
696
697 } /* namespace folly */
698
699 #endif // SYNCHRONIZED_H_