proxygen
Synchronized.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-present 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  */
25 #pragma once
26 
27 #include <folly/Function.h>
28 #include <folly/Likely.h>
29 #include <folly/LockTraits.h>
30 #include <folly/Preprocessor.h>
31 #include <folly/SharedMutex.h>
32 #include <folly/Traits.h>
33 #include <folly/Utility.h>
36 #include <glog/logging.h>
37 
38 #include <array>
39 #include <mutex>
40 #include <tuple>
41 #include <type_traits>
42 #include <utility>
43 
44 namespace folly {
45 
46 template <class LockedType, class Mutex, class LockPolicy>
48 template <class LockedType, class LockPolicy>
49 class LockedPtr;
50 
62 template <class Mutex>
64  true,
67 
74 template <class Subclass, detail::MutexLevel level>
76 
83 template <class Subclass>
85  public:
87  using ConstWLockedPtr =
90 
92  using ConstTryWLockedPtr =
95 
104  return LockedPtr(static_cast<Subclass*>(this));
105  }
106 
115  return TryWLockedPtr{static_cast<Subclass*>(this)};
116  }
117 
123  return ConstLockedPtr(static_cast<const Subclass*>(this));
124  }
125 
134  return TryRLockedPtr{static_cast<const Subclass*>(this)};
135  }
136 
144  template <class Rep, class Period>
145  LockedPtr wlock(const std::chrono::duration<Rep, Period>& timeout) {
146  return LockedPtr(static_cast<Subclass*>(this), timeout);
147  }
148 
156  template <class Rep, class Period>
158  const std::chrono::duration<Rep, Period>& timeout) const {
159  return ConstLockedPtr(static_cast<const Subclass*>(this), timeout);
160  }
161 
176  template <class Function>
177  auto withWLock(Function&& function) {
178  return function(*wlock());
179  }
180 
190  template <class Function>
191  auto withWLockPtr(Function&& function) {
192  return function(wlock());
193  }
194 
201  template <class Function>
202  auto withRLock(Function&& function) const {
203  return function(*rlock());
204  }
205 
206  template <class Function>
207  auto withRLockPtr(Function&& function) const {
208  return function(rlock());
209  }
210 };
211 
219 template <class Subclass>
221  : public SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
222  public:
224  using ConstUpgradeLockedPtr =
226 
227  using TryUpgradeLockedPtr =
231 
239  return UpgradeLockedPtr(static_cast<Subclass*>(this));
240  }
241 
250  return TryUpgradeLockedPtr{static_cast<Subclass*>(this)};
251  }
252 
259  template <class Rep, class Period>
260  UpgradeLockedPtr ulock(const std::chrono::duration<Rep, Period>& timeout) {
261  return UpgradeLockedPtr(static_cast<Subclass*>(this), timeout);
262  }
263 
284  template <class Function>
285  auto withULock(Function&& function) {
286  return function(*ulock());
287  }
288 
301  template <class Function>
302  auto withULockPtr(Function&& function) {
303  return function(ulock());
304  }
305 };
306 
313 template <class Subclass>
315  public:
317  using ConstLockedPtr =
319 
321  using ConstTryLockedPtr =
323 
329  return LockedPtr(static_cast<Subclass*>(this));
330  }
331 
337  return ConstLockedPtr(static_cast<const Subclass*>(this));
338  }
339 
348  return TryLockedPtr{static_cast<Subclass*>(this)};
349  }
351  return ConstTryLockedPtr{static_cast<const Subclass*>(this)};
352  }
353 
358  template <class Rep, class Period>
359  LockedPtr lock(const std::chrono::duration<Rep, Period>& timeout) {
360  return LockedPtr(static_cast<Subclass*>(this), timeout);
361  }
362 
367  template <class Rep, class Period>
368  ConstLockedPtr lock(const std::chrono::duration<Rep, Period>& timeout) const {
369  return ConstLockedPtr(static_cast<const Subclass*>(this), timeout);
370  }
371 
386  template <class Function>
387  auto withLock(Function&& function) {
388  return function(*lock());
389  }
390  template <class Function>
391  auto withLock(Function&& function) const {
392  return function(*lock());
393  }
394 
404  template <class Function>
405  auto withLockPtr(Function&& function) {
406  return function(lock());
407  }
408  template <class Function>
409  auto withLockPtr(Function&& function) const {
410  return function(lock());
411  }
412 };
413 
437 template <class T, class Mutex = SharedMutex>
439  Synchronized<T, Mutex>,
440  MutexLevelValue<Mutex>::value> {
441  private:
442  using Base =
444  static constexpr bool nxCopyCtor{
446  static constexpr bool nxMoveCtor{
448 
449  // used to disable copy construction and assignment
450  class NonImplementedType;
451 
452  public:
453  using LockedPtr = typename Base::LockedPtr;
454  using ConstLockedPtr = typename Base::ConstLockedPtr;
455  using DataType = T;
456  using MutexType = Mutex;
457 
462  Synchronized() = default;
463 
464  public:
477  /* implicit */ Synchronized(typename std::conditional<
479  const Synchronized&,
480  NonImplementedType>::type rhs) /* may throw */
481  : Synchronized(rhs.copy()) {}
482 
493  : Synchronized(std::move(rhs.datum_)) {}
494 
499  explicit Synchronized(const T& rhs) noexcept(nxCopyCtor) : datum_(rhs) {}
500 
505  explicit Synchronized(T&& rhs) noexcept(nxMoveCtor)
506  : datum_(std::move(rhs)) {}
507 
512  template <typename... Args>
513  explicit Synchronized(in_place_t, Args&&... args)
514  : datum_(std::forward<Args>(args)...) {}
515 
520  template <typename... DatumArgs, typename... MutexArgs>
522  std::piecewise_construct_t,
523  std::tuple<DatumArgs...> datumArgs,
524  std::tuple<MutexArgs...> mutexArgs)
525  : Synchronized{std::piecewise_construct,
526  std::move(datumArgs),
527  std::move(mutexArgs),
528  make_index_sequence<sizeof...(DatumArgs)>{},
529  make_index_sequence<sizeof...(MutexArgs)>{}} {}
530 
545  Synchronized& operator=(typename std::conditional<
548  const Synchronized&,
549  NonImplementedType>::type rhs) {
550  return *this = rhs.copy();
551  }
552 
564  return *this = std::move(rhs.datum_);
565  }
566 
571  if (&datum_ != &rhs) {
572  auto guard = operator->();
573  datum_ = rhs;
574  }
575  return *this;
576  }
577 
582  if (&datum_ != &rhs) {
583  auto guard = operator->();
584  datum_ = std::move(rhs);
585  }
586  return *this;
587  }
588 
602  return LockedPtr(this);
603  }
605  return ConstLockedPtr(this);
606  }
607  template <class Rep, class Period>
608  LockedPtr contextualLock(const std::chrono::duration<Rep, Period>& timeout) {
609  return LockedPtr(this, timeout);
610  }
611  template <class Rep, class Period>
613  const std::chrono::duration<Rep, Period>& timeout) const {
614  return ConstLockedPtr(this, timeout);
615  }
624  return ConstLockedPtr(this);
625  }
626  template <class Rep, class Period>
628  const std::chrono::duration<Rep, Period>& timeout) const {
629  return ConstLockedPtr(this, timeout);
630  }
631 
642  return LockedPtr(this);
643  }
644 
652  return ConstLockedPtr(this);
653  }
654 
663  LockedPtr timedAcquire(unsigned int milliseconds) {
664  return LockedPtr(this, std::chrono::milliseconds(milliseconds));
665  }
666 
675  ConstLockedPtr timedAcquire(unsigned int milliseconds) const {
676  return ConstLockedPtr(this, std::chrono::milliseconds(milliseconds));
677  }
678 
685  if (this == &rhs) {
686  return;
687  }
688  if (this > &rhs) {
689  return rhs.swap(*this);
690  }
691  auto guard1 = operator->();
692  auto guard2 = rhs.operator->();
693 
694  using std::swap;
695  swap(datum_, rhs.datum_);
696  }
697 
702  void swap(T& rhs) {
703  LockedPtr guard(this);
704 
705  using std::swap;
706  swap(datum_, rhs);
707  }
708 
714  swap(rhs);
715  return std::move(rhs);
716  }
717 
721  void copy(T* target) const {
722  ConstLockedPtr guard(this);
723  *target = datum_;
724  }
725 
729  T copy() const {
730  ConstLockedPtr guard(this);
731  return datum_;
732  }
733 
734  private:
735  template <class LockedType, class MutexType, class LockPolicy>
736  friend class folly::LockedPtrBase;
737  template <class LockedType, class LockPolicy>
738  friend class folly::LockedPtr;
739 
747  const Synchronized& rhs,
748  const ConstLockedPtr& /*guard*/) noexcept(nxCopyCtor)
749  : datum_(rhs.datum_) {}
750 
752  nxMoveCtor)
753  : datum_(std::move(rhs.datum_)) {}
754 
755  template <
756  typename... DatumArgs,
757  typename... MutexArgs,
758  std::size_t... IndicesOne,
759  std::size_t... IndicesTwo>
761  std::piecewise_construct_t,
762  std::tuple<DatumArgs...> datumArgs,
763  std::tuple<MutexArgs...> mutexArgs,
766  : datum_{std::get<IndicesOne>(std::move(datumArgs))...},
767  mutex_{std::get<IndicesTwo>(std::move(mutexArgs))...} {}
768 
769  // Synchronized data members
771  mutable Mutex mutex_;
772 };
773 
774 template <class SynchronizedType, class LockPolicy>
776 
777 namespace detail {
778 /*
779  * A helper alias that resolves to "const T" if the template parameter
780  * is a const Synchronized<T>, or "T" if the parameter is not const.
781  */
782 template <class SynchronizedType>
783 using SynchronizedDataType = typename std::conditional<
785  typename SynchronizedType::DataType const,
786  typename SynchronizedType::DataType>::type;
787 /*
788  * A helper alias that resolves to a ConstLockedPtr if the template parameter
789  * is a const Synchronized<T>, or a LockedPtr if the parameter is not const.
790  */
791 template <class SynchronizedType>
792 using LockedPtrType = typename std::conditional<
793  std::is_const<SynchronizedType>::value,
794  typename SynchronizedType::ConstLockedPtr,
795  typename SynchronizedType::LockedPtr>::type;
796 
797 template <
798  typename Synchronized,
799  typename LockFunc,
800  typename TryLockFunc,
801  typename... Args>
803  public:
804  using LockedPtr = invoke_result_t<LockFunc&, Synchronized&, const Args&...>;
805 
806  template <typename LockFuncType, typename TryLockFuncType, typename... As>
808  Synchronized& sync,
809  LockFuncType&& lockFunc,
810  TryLockFuncType tryLockFunc,
811  As&&... as)
812  : synchronized{sync},
813  lockFunc_{std::forward<LockFuncType>(lockFunc)},
814  tryLockFunc_{std::forward<TryLockFuncType>(tryLockFunc)},
815  args_{std::forward<As>(as)...} {}
816 
817  auto lock() const {
818  auto args = std::tuple<const Args&...>{args_};
819  return apply(lockFunc_, std::tuple_cat(std::tie(synchronized), args));
820  }
821  auto tryLock() const {
822  return tryLockFunc_(synchronized);
823  }
824 
825  private:
826  Synchronized& synchronized;
827  LockFunc lockFunc_;
828  TryLockFunc tryLockFunc_;
829  std::tuple<Args...> args_;
830 };
831 
832 template <
833  typename Synchronized,
834  typename LockFunc,
835  typename TryLockFunc,
836  typename... Args>
838  Synchronized& synchronized,
839  LockFunc&& lockFunc,
840  TryLockFunc&& tryLockFunc,
841  Args&&... args) {
842  using LockFuncType = std::decay_t<LockFunc>;
843  using TryLockFuncType = std::decay_t<TryLockFunc>;
844  return SynchronizedLocker<
845  Synchronized,
846  LockFuncType,
847  TryLockFuncType,
848  std::decay_t<Args>...>{synchronized,
849  std::forward<LockFunc>(lockFunc),
850  std::forward<TryLockFunc>(tryLockFunc),
851  std::forward<Args>(args)...};
852 }
853 
870 template <typename... SynchronizedLocker>
871 auto lock(SynchronizedLocker... lockersIn)
872  -> std::tuple<typename SynchronizedLocker::LockedPtr...> {
873  // capture the list of lockers as a tuple
874  auto lockers = std::forward_as_tuple(lockersIn...);
875 
876  // make a list of null LockedPtr instances that we will return to the caller
877  auto lockedPtrs = std::tuple<typename SynchronizedLocker::LockedPtr...>{};
878 
879  // start by locking the first thing in the list
880  std::get<0>(lockedPtrs) = std::get<0>(lockers).lock();
881  auto indexLocked = 0;
882 
883  while (true) {
884  auto couldLockAll = true;
885 
886  for_each(lockers, [&](auto& locker, auto index) {
887  // if we should try_lock on the current locker then do so
888  if (index != indexLocked) {
889  auto lockedPtr = locker.tryLock();
890 
891  // if we were unable to lock this mutex,
892  //
893  // 1. release all the locks,
894  // 2. yield control to another thread to be nice
895  // 3. block on the mutex we failed to lock, acquire the lock
896  // 4. break out and set the index of the current mutex to indicate
897  // which mutex we have locked
898  if (!lockedPtr) {
899  // writing lockedPtrs = decltype(lockedPtrs){} does not compile on
900  // gcc, I believe this is a bug D7676798
901  lockedPtrs = std::tuple<typename SynchronizedLocker::LockedPtr...>{};
902 
904  fetch(lockedPtrs, index) = locker.lock();
905  indexLocked = index;
906  couldLockAll = false;
907 
908  return loop_break;
909  }
910 
911  // else store the locked mutex in the list we return
912  fetch(lockedPtrs, index) = std::move(lockedPtr);
913  }
914 
915  return loop_continue;
916  });
917 
918  if (couldLockAll) {
919  return lockedPtrs;
920  }
921  }
922 }
923 
924 template <typename Synchronized, typename... Args>
925 auto wlock(Synchronized& synchronized, Args&&... args) {
927  synchronized,
928  [](auto& s, auto&&... a) {
929  return s.wlock(std::forward<decltype(a)>(a)...);
930  },
931  [](auto& s) { return s.tryWLock(); },
932  std::forward<Args>(args)...);
933 }
934 template <typename Synchronized, typename... Args>
935 auto rlock(Synchronized& synchronized, Args&&... args) {
937  synchronized,
938  [](auto& s, auto&&... a) {
939  return s.rlock(std::forward<decltype(a)>(a)...);
940  },
941  [](auto& s) { return s.tryRLock(); },
942  std::forward<Args>(args)...);
943 }
944 template <typename Synchronized, typename... Args>
945 auto ulock(Synchronized& synchronized, Args&&... args) {
947  synchronized,
948  [](auto& s, auto&&... a) {
949  return s.ulock(std::forward<decltype(a)>(a)...);
950  },
951  [](auto& s) { return s.tryULock(); },
952  std::forward<Args>(args)...);
953 }
954 template <typename Synchronized, typename... Args>
955 auto lock(Synchronized& synchronized, Args&&... args) {
957  synchronized,
958  [](auto& s, auto&&... a) {
959  return s.lock(std::forward<decltype(a)>(a)...);
960  },
961  [](auto& s) { return s.tryLock(); },
962  std::forward<Args>(args)...);
963 }
964 
965 } // namespace detail
966 
985 template <class SynchronizedType, class Mutex, class LockPolicy>
986 class LockedPtrBase {
987  public:
988  using MutexType = Mutex;
989  friend class folly::ScopedUnlocker<SynchronizedType, LockPolicy>;
990 
994  template <typename S, typename L>
995  friend class folly::LockedPtr;
996  template <typename S, typename M, typename L>
997  friend class LockedPtrBase;
998 
1003  if (parent_) {
1004  LockPolicy::unlock(parent_->mutex_);
1005  }
1006  }
1007 
1016  void unlock() {
1017  DCHECK(parent_ != nullptr);
1018  LockPolicy::unlock(parent_->mutex_);
1019  parent_ = nullptr;
1020  }
1021 
1022  protected:
1024  explicit LockedPtrBase(SynchronizedType* parent) : parent_(parent) {
1025  DCHECK(parent);
1026  if (!LockPolicy::lock(parent_->mutex_)) {
1027  parent_ = nullptr;
1028  }
1029  }
1030  template <class Rep, class Period>
1032  SynchronizedType* parent,
1033  const std::chrono::duration<Rep, Period>& timeout) {
1034  if (LockPolicy::try_lock_for(parent->mutex_, timeout)) {
1035  this->parent_ = parent;
1036  }
1037  }
1039  : parent_{exchange(rhs.parent_, nullptr)} {}
1041  assignImpl(*this, rhs);
1042  return *this;
1043  }
1044 
1057  template <typename LockPolicyType>
1060  : parent_{exchange(rhs.parent_, nullptr)} {}
1061  template <typename LockPolicyType>
1064  assignImpl(*this, rhs);
1065  return *this;
1066  }
1067 
1071  template <typename LockPolicyLhs, typename LockPolicyRhs>
1075  if (lhs.parent_) {
1076  LockPolicy::unlock(lhs.parent_->mutex_);
1077  }
1078 
1079  lhs.parent_ = exchange(rhs.parent_, nullptr);
1080  }
1081 
1082  using UnlockerData = SynchronizedType*;
1083 
1091  static SynchronizedType* getSynchronized(UnlockerData data) {
1092  return data;
1093  }
1094 
1096  DCHECK(parent_ != nullptr);
1097  auto current = parent_;
1098  parent_ = nullptr;
1099  LockPolicy::unlock(current->mutex_);
1100  return current;
1101  }
1103  DCHECK(parent_ == nullptr);
1104  parent_ = data;
1105  LockPolicy::lock(parent_->mutex_);
1106  }
1107 
1108  SynchronizedType* parent_ = nullptr;
1109 };
1110 
1118 template <class SynchronizedType, class LockPolicy>
1119 class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
1120  public:
1122  friend class folly::ScopedUnlocker<SynchronizedType, LockPolicy>;
1123 
1127  template <typename S, typename L>
1128  friend class folly::LockedPtr;
1129  template <typename S, typename M, typename L>
1130  friend class LockedPtrBase;
1131 
1136  // The std::unique_lock will automatically release the lock when it is
1137  // destroyed, so we don't need to do anything extra here.
1138  }
1139 
1141  : lock_{std::move(rhs.lock_)}, parent_{exchange(rhs.parent_, nullptr)} {}
1143  assignImpl(*this, rhs);
1144  return *this;
1145  }
1146 
1153  template <typename LockPolicyType>
1155  other) noexcept
1156  : lock_{std::move(other.lock_)},
1157  parent_{exchange(other.parent_, nullptr)} {}
1158  template <typename LockPolicyType>
1161  rhs) noexcept {
1162  assignImpl(*this, rhs);
1163  return *this;
1164  }
1165 
1169  template <typename LockPolicyLhs, typename LockPolicyRhs>
1173  rhs) noexcept {
1174  lhs.lock_ = std::move(rhs.lock_);
1175  lhs.parent_ = exchange(rhs.parent_, nullptr);
1176  }
1177 
1188  std::unique_lock<std::mutex>& getUniqueLock() {
1189  return lock_;
1190  }
1191 
1200  void unlock() {
1201  DCHECK(parent_ != nullptr);
1202  lock_.unlock();
1203  parent_ = nullptr;
1204  }
1205 
1206  protected:
1208  explicit LockedPtrBase(SynchronizedType* parent)
1209  : lock_{parent->mutex_, std::adopt_lock}, parent_{parent} {
1210  DCHECK(parent);
1211  if (!LockPolicy::lock(parent_->mutex_)) {
1212  parent_ = nullptr;
1213  lock_.release();
1214  }
1215  }
1216 
1217  using UnlockerData =
1218  std::pair<std::unique_lock<std::mutex>, SynchronizedType*>;
1219 
1220  static SynchronizedType* getSynchronized(const UnlockerData& data) {
1221  return data.second;
1222  }
1223 
1225  DCHECK(parent_ != nullptr);
1226  UnlockerData data(std::move(lock_), parent_);
1227  parent_ = nullptr;
1228  data.first.unlock();
1229  return data;
1230  }
1232  lock_ = std::move(data.first);
1233  lock_.lock();
1234  parent_ = data.second;
1235  }
1236 
1237  // The specialization for std::mutex does have to store slightly more
1238  // state than the default implementation.
1239  std::unique_lock<std::mutex> lock_;
1240  SynchronizedType* parent_ = nullptr;
1241 };
1242 
1246 template <class SynchronizedType, class LockPolicy>
1247 class ScopedUnlocker {
1248  public:
1250  : ptr_(p), data_(ptr_->releaseLock()) {}
1251  ScopedUnlocker(const ScopedUnlocker&) = delete;
1252  ScopedUnlocker& operator=(const ScopedUnlocker&) = delete;
1254  : ptr_(exchange(other.ptr_, nullptr)), data_(std::move(other.data_)) {}
1255  ScopedUnlocker& operator=(ScopedUnlocker&& other) = delete;
1256 
1258  if (ptr_) {
1259  ptr_->reacquireLock(std::move(data_));
1260  }
1261  }
1262 
1266  SynchronizedType* getSynchronized() const {
1268  }
1269 
1270  private:
1274 };
1275 
1286 template <class SynchronizedType, class LockPolicy>
1287 class LockedPtr : public LockedPtrBase<
1288  SynchronizedType,
1289  typename SynchronizedType::MutexType,
1290  LockPolicy> {
1291  private:
1292  using Base = LockedPtrBase<
1293  SynchronizedType,
1294  typename SynchronizedType::MutexType,
1295  LockPolicy>;
1297  // CDataType is the DataType with the appropriate const-qualification
1299  // Enable only if the unlock policy of the other LockPolicy is the same as
1300  // ours
1301  template <typename LockPolicyOther>
1302  using EnableIfSameUnlockPolicy = std::enable_if_t<std::is_same<
1303  typename LockPolicy::UnlockPolicy,
1304  typename LockPolicyOther::UnlockPolicy>::value>;
1305 
1306  // friend other LockedPtr types
1307  template <typename SynchronizedTypeOther, typename LockPolicyOther>
1308  friend class LockedPtr;
1309 
1310  public:
1311  using DataType = typename SynchronizedType::DataType;
1312  using MutexType = typename SynchronizedType::MutexType;
1314  friend class ScopedUnlocker<SynchronizedType, LockPolicy>;
1315 
1322 
1326  explicit LockedPtr(SynchronizedType* parent) : Base(parent) {}
1327 
1336  template <class Rep, class Period>
1338  SynchronizedType* parent,
1339  const std::chrono::duration<Rep, Period>& timeout)
1340  : Base(parent, timeout) {}
1341 
1345  LockedPtr(LockedPtr&& rhs) noexcept = default;
1346  template <
1347  typename LockPolicyType,
1350  : Base{std::move(other)} {}
1351 
1355  LockedPtr& operator=(LockedPtr&& rhs) noexcept = default;
1356  template <
1357  typename LockPolicyType,
1358  EnableIfSameUnlockPolicy<LockPolicyType>* = nullptr>
1361  Base::operator=(std::move(other));
1362  return *this;
1363  }
1364 
1365  /*
1366  * Copy constructor and assignment operator are deleted.
1367  */
1368  LockedPtr(const LockedPtr& rhs) = delete;
1369  LockedPtr& operator=(const LockedPtr& rhs) = delete;
1370 
1375 
1386  bool isNull() const {
1387  return this->parent_ == nullptr;
1388  }
1389 
1395  explicit operator bool() const {
1396  return this->parent_ != nullptr;
1397  }
1398 
1405  return &this->parent_->datum_;
1406  }
1407 
1414  return this->parent_->datum_;
1415  }
1416 
1426  }
1427 
1428  /***************************************************************************
1429  * Upgradable lock methods.
1430  * These are disabled via SFINAE when the mutex is not upgradable
1431  **************************************************************************/
1436  template <
1437  typename SyncType = SynchronizedType,
1438  typename = typename std::enable_if<
1443  exchange(this->parent_, nullptr));
1444  }
1445 
1450  template <
1451  typename SyncType = SynchronizedType,
1452  typename = typename std::enable_if<
1457  exchange(this->parent_, nullptr));
1458  }
1459 
1464  template <
1465  typename SyncType = SynchronizedType,
1466  typename = typename std::enable_if<
1471  exchange(this->parent_, nullptr));
1472  }
1473 
1478  template <
1479  typename SyncType = SynchronizedType,
1480  typename = typename std::enable_if<
1485  exchange(this->parent_, nullptr));
1486  }
1487 };
1488 
1518 template <typename D, typename M, typename... Args>
1519 auto wlock(Synchronized<D, M>& synchronized, Args&&... args) {
1520  return detail::wlock(synchronized, std::forward<Args>(args)...);
1521 }
1522 template <typename Data, typename Mutex, typename... Args>
1523 auto rlock(const Synchronized<Data, Mutex>& synchronized, Args&&... args) {
1524  return detail::rlock(synchronized, std::forward<Args>(args)...);
1525 }
1526 template <typename D, typename M, typename... Args>
1527 auto ulock(Synchronized<D, M>& synchronized, Args&&... args) {
1528  return detail::ulock(synchronized, std::forward<Args>(args)...);
1529 }
1530 template <typename D, typename M, typename... Args>
1531 auto lock(Synchronized<D, M>& synchronized, Args&&... args) {
1532  return detail::lock(synchronized, std::forward<Args>(args)...);
1533 }
1534 template <typename D, typename M, typename... Args>
1535 auto lock(const Synchronized<D, M>& synchronized, Args&&... args) {
1536  return detail::lock(synchronized, std::forward<Args>(args)...);
1537 }
1538 
1552 template <typename Func, typename... SynchronizedLockers>
1553 decltype(auto) synchronized(Func&& func, SynchronizedLockers&&... lockers) {
1554  return apply(
1555  std::forward<Func>(func),
1556  lock(std::forward<SynchronizedLockers>(lockers)...));
1557 }
1558 
1591 template <typename LockableOne, typename LockableTwo, typename... Lockables>
1592 void lock(LockableOne& one, LockableTwo& two, Lockables&... lockables) {
1593  auto locker = [](auto& lockable) {
1594  using Lockable = std::remove_reference_t<decltype(lockable)>;
1596  lockable,
1597  [](auto& l) { return std::unique_lock<Lockable>{l}; },
1598  [](auto& l) {
1599  auto lock = std::unique_lock<Lockable>{l, std::defer_lock};
1600  lock.try_lock();
1601  return lock;
1602  });
1603  };
1604  auto locks = lock(locker(one), locker(two), locker(lockables)...);
1605 
1606  // release ownership of the locks from the RAII lock wrapper returned by the
1607  // function above
1608  for_each(locks, [&](auto& lock) { lock.release(); });
1609 }
1610 
1624 template <class Sync1, class Sync2>
1625 std::tuple<detail::LockedPtrType<Sync1>, detail::LockedPtrType<Sync2>>
1626 acquireLocked(Sync1& l1, Sync2& l2) {
1627  if (static_cast<const void*>(&l1) < static_cast<const void*>(&l2)) {
1628  auto p1 = l1.contextualLock();
1629  auto p2 = l2.contextualLock();
1630  return std::make_tuple(std::move(p1), std::move(p2));
1631  } else {
1632  auto p2 = l2.contextualLock();
1633  auto p1 = l1.contextualLock();
1634  return std::make_tuple(std::move(p1), std::move(p2));
1635  }
1636 }
1637 
1642 template <class Sync1, class Sync2>
1643 std::pair<detail::LockedPtrType<Sync1>, detail::LockedPtrType<Sync2>>
1644 acquireLockedPair(Sync1& l1, Sync2& l2) {
1645  auto lockedPtrs = acquireLocked(l1, l2);
1646  return {std::move(std::get<0>(lockedPtrs)),
1647  std::move(std::get<1>(lockedPtrs))};
1648 }
1649 
1650 /************************************************************************
1651  * NOTE: All APIs below this line will be deprecated in upcoming diffs.
1652  ************************************************************************/
1653 
1654 // Non-member swap primitive
1655 template <class T, class M>
1657  lhs.swap(rhs);
1658 }
1659 
1667 #define SYNCHRONIZED_VAR(var) FB_CONCATENATE(SYNCHRONIZED_##var##_, __LINE__)
1668 
1686 #define SYNCHRONIZED(...) \
1687  FOLLY_PUSH_WARNING \
1688  FOLLY_GNU_DISABLE_WARNING("-Wshadow") \
1689  FOLLY_MSVC_DISABLE_WARNING(4189) /* initialized but unreferenced */ \
1690  FOLLY_MSVC_DISABLE_WARNING(4456) /* declaration hides local */ \
1691  FOLLY_MSVC_DISABLE_WARNING(4457) /* declaration hides parameter */ \
1692  FOLLY_MSVC_DISABLE_WARNING(4458) /* declaration hides member */ \
1693  FOLLY_MSVC_DISABLE_WARNING(4459) /* declaration hides global */ \
1694  FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS \
1695  if (bool SYNCHRONIZED_VAR(state) = false) { \
1696  } else \
1697  for (auto SYNCHRONIZED_VAR(lockedPtr) = \
1698  (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).operator->(); \
1699  !SYNCHRONIZED_VAR(state); \
1700  SYNCHRONIZED_VAR(state) = true) \
1701  for (auto& FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \
1702  *SYNCHRONIZED_VAR(lockedPtr).operator->(); \
1703  !SYNCHRONIZED_VAR(state); \
1704  SYNCHRONIZED_VAR(state) = true) \
1705  FOLLY_POP_WARNING
1706 
1707 #define TIMED_SYNCHRONIZED(timeout, ...) \
1708  if (bool SYNCHRONIZED_VAR(state) = false) { \
1709  } else \
1710  for (auto SYNCHRONIZED_VAR(lockedPtr) = \
1711  (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).timedAcquire(timeout); \
1712  !SYNCHRONIZED_VAR(state); \
1713  SYNCHRONIZED_VAR(state) = true) \
1714  for (auto FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \
1715  (!SYNCHRONIZED_VAR(lockedPtr) \
1716  ? nullptr \
1717  : SYNCHRONIZED_VAR(lockedPtr).operator->()); \
1718  !SYNCHRONIZED_VAR(state); \
1719  SYNCHRONIZED_VAR(state) = true)
1720 
1724 #define SYNCHRONIZED_CONST(...) \
1725  SYNCHRONIZED( \
1726  FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \
1727  as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))))
1728 
1732 #define TIMED_SYNCHRONIZED_CONST(timeout, ...) \
1733  TIMED_SYNCHRONIZED( \
1734  timeout, \
1735  FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \
1736  as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))))
1737 
1743 #define SYNCHRONIZED_DUAL(n1, e1, n2, e2) \
1744  if (bool SYNCHRONIZED_VAR(state) = false) { \
1745  } else \
1746  for (auto SYNCHRONIZED_VAR(ptrs) = acquireLockedPair(e1, e2); \
1747  !SYNCHRONIZED_VAR(state); \
1748  SYNCHRONIZED_VAR(state) = true) \
1749  for (auto& n1 = *SYNCHRONIZED_VAR(ptrs).first; !SYNCHRONIZED_VAR(state); \
1750  SYNCHRONIZED_VAR(state) = true) \
1751  for (auto& n2 = *SYNCHRONIZED_VAR(ptrs).second; \
1752  !SYNCHRONIZED_VAR(state); \
1753  SYNCHRONIZED_VAR(state) = true)
1754 
1755 } /* namespace folly */
ConstLockedPtr lock(const std::chrono::duration< Rep, Period > &timeout) const
Definition: Synchronized.h:368
UpgradeLockedPtr ulock(const std::chrono::duration< Rep, Period > &timeout)
Definition: Synchronized.h:260
LockedPtrBase(LockedPtrBase< SynchronizedType, Mutex, LockPolicyType > &&rhs) noexcept
ConstLockedPtr contextualRLock(const std::chrono::duration< Rep, Period > &timeout) const
Definition: Synchronized.h:627
Synchronized(Synchronized &&rhs) noexcept(nxMoveCtor)
Definition: Synchronized.h:492
void swap(T &rhs)
Definition: Synchronized.h:702
LockedPtrBase(LockedPtrBase &&rhs) noexcept
LockedPtr(SynchronizedType *parent)
void lock(LockableOne &one, LockableTwo &two, Lockables &...lockables)
SynchronizedType * getSynchronized() const
auto wlock(Synchronized< D, M > &synchronized, Args &&...args)
static std::unique_ptr< SSLLock[]> & locks()
Synchronized(const Synchronized &rhs, const ConstLockedPtr &) noexcept(nxCopyCtor)
Definition: Synchronized.h:746
typename Base::UnlockerData UnlockerData
typename invoke_result< F, Args... >::type invoke_result_t
Definition: Invoke.h:142
auto wlock(Synchronized &synchronized, Args &&...args)
Definition: Synchronized.h:925
LockedPtrBase & operator=(LockedPtrBase< SynchronizedType, Mutex, LockPolicyType > &&rhs) noexcept
ScopedUnlocker(LockedPtr< SynchronizedType, LockPolicy > *p)
LockedPtrBase(SynchronizedType *parent)
Synchronized(T &&rhs) noexcept(nxMoveCtor)
Definition: Synchronized.h:505
void swap(Synchronized &rhs)
Definition: Synchronized.h:684
constexpr auto loop_continue
Definition: Foreach.h:98
LockedPtr(LockedPtr< SynchronizedType, LockPolicyType > &&other) noexcept
PskType type
void assignImpl(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyLhs > &lhs, LockedPtrBase< SynchronizedType, std::mutex, LockPolicyRhs > &rhs) noexcept
ConstLockedPtr operator->() const
Definition: Synchronized.h:651
ConstLockedPtr contextualLock() const
Definition: Synchronized.h:604
LockedPtrBase & operator=(LockedPtrBase &&rhs) noexcept
LockedPtr wlock(const std::chrono::duration< Rep, Period > &timeout)
Definition: Synchronized.h:145
LockedPtr lock(const std::chrono::duration< Rep, Period > &timeout)
Definition: Synchronized.h:359
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
LockedPtr< SynchronizedType, LockPolicyFromUpgradeToExclusive > moveFromUpgradeToWrite()
LockedPtr contextualLock()
Definition: Synchronized.h:601
LockedPtr< SynchronizedType, LockPolicyFromExclusiveToUpgrade > moveFromWriteToUpgrade()
#define Mutex
STL namespace.
typename std::conditional< std::is_const< SynchronizedType >::value, typename SynchronizedType::DataType const, typename SynchronizedType::DataType >::type SynchronizedDataType
Definition: Synchronized.h:786
UnlockerData releaseLock()
typename std::remove_const< SynchronizedType >::type Synchronized
CDataType * operator->() const
auto rlock(Synchronized &synchronized, Args &&...args)
Definition: Synchronized.h:935
folly::std T
ConstLockedPtr contextualRLock() const
Definition: Synchronized.h:623
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
LockedPtrBase(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyType > &&other) noexcept
requires E e noexcept(noexcept(s.error(std::move(e))))
in_place_tag(&)(in_place_tag) in_place_t
Definition: Utility.h:229
tuple make_tuple()
Definition: gtest-tuple.h:675
Synchronized(std::piecewise_construct_t, std::tuple< DatumArgs... > datumArgs, std::tuple< MutexArgs... > mutexArgs)
Definition: Synchronized.h:521
LockedPtr operator->()
Definition: Synchronized.h:641
std::mutex mutex_
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
auto makeSynchronizedLocker(Synchronized &synchronized, LockFunc &&lockFunc, TryLockFunc &&tryLockFunc, Args &&...args)
Definition: Synchronized.h:837
auto rlock(const Synchronized< Data, Mutex > &synchronized, Args &&...args)
std::tuple< detail::LockedPtrType< Sync1 >, detail::LockedPtrType< Sync2 > > acquireLocked(Sync1 &l1, Sync2 &l2)
bool isNull() const
int current
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
void assignImpl(LockedPtrBase< SynchronizedType, Mutex, LockPolicyLhs > &lhs, LockedPtrBase< SynchronizedType, Mutex, LockPolicyRhs > &rhs) noexcept
Synchronized(const T &rhs) noexcept(nxCopyCtor)
Definition: Synchronized.h:499
Function< void()> Func
Definition: Executor.h:27
std::pair< detail::LockedPtrType< Sync1 >, detail::LockedPtrType< Sync2 > > acquireLockedPair(Sync1 &l1, Sync2 &l2)
Synchronized(typename std::conditional< std::is_copy_constructible< T >::value, const Synchronized &, NonImplementedType >::type rhs)
Definition: Synchronized.h:477
ScopedUnlocker< SynchronizedType, LockPolicy > scopedUnlock()
LockedPtr< SynchronizedType, LockPolicyFromUpgradeToShared > moveFromUpgradeToRead()
#define D(name, bit)
Definition: CpuId.h:145
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
Definition: Synchronized.h:871
ConstLockedPtr timedAcquire(unsigned int milliseconds) const
Definition: Synchronized.h:675
Synchronized & operator=(const T &rhs)
Definition: Synchronized.h:570
std::enable_if_t< std::is_same< typename LockPolicy::UnlockPolicy, typename LockPolicyOther::UnlockPolicy >::value > EnableIfSameUnlockPolicy
LockedPtr contextualLock(const std::chrono::duration< Rep, Period > &timeout)
Definition: Synchronized.h:608
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
decltype(auto) synchronized(Func &&func, SynchronizedLockers &&...lockers)
typename std::conditional< std::is_const< SynchronizedType >::value, typename SynchronizedType::ConstLockedPtr, typename SynchronizedType::LockedPtr >::type LockedPtrType
Definition: Synchronized.h:795
GuardImpl guard(ErrorHandler &&handler)
Definition: Base.h:840
void reacquireLock(UnlockerData &&data)
Synchronized(Synchronized &&rhs, const LockedPtr &) noexcept(nxMoveCtor)
Definition: Synchronized.h:751
make_integer_sequence< std::size_t, Size > make_index_sequence
Definition: Utility.h:209
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
auto ulock(Synchronized &synchronized, Args &&...args)
Definition: Synchronized.h:945
Synchronized & operator=(T &&rhs)
Definition: Synchronized.h:581
LockedPtr & operator=(LockedPtr< SynchronizedType, LockPolicyType > &&other) noexcept
AtomicCounter< T, DeterministicAtomic > Base
LockedPtrBase & operator=(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyType > &&rhs) noexcept
char a
static SynchronizedType * getSynchronized(const UnlockerData &data)
LockedPtr(SynchronizedType *parent, const std::chrono::duration< Rep, Period > &timeout)
Synchronized(std::piecewise_construct_t, std::tuple< DatumArgs... > datumArgs, std::tuple< MutexArgs... > mutexArgs, index_sequence< IndicesOne... >, index_sequence< IndicesTwo... >)
Definition: Synchronized.h:760
static const char *const value
Definition: Conv.cpp:50
ConstLockedPtr rlock(const std::chrono::duration< Rep, Period > &timeout) const
Definition: Synchronized.h:157
invoke_result_t< LockFunc &, Synchronized &, const Args &... > LockedPtr
Definition: Synchronized.h:804
Synchronized & operator=(Synchronized &&rhs)
Definition: Synchronized.h:563
LockedPtr timedAcquire(unsigned int milliseconds)
Definition: Synchronized.h:663
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
LockedPtrBase(SynchronizedType *parent, const std::chrono::duration< Rep, Period > &timeout)
CDataType & operator*() const
typename SynchronizedType::DataType DataType
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
SynchronizedLocker(Synchronized &sync, LockFuncType &&lockFunc, TryLockFuncType tryLockFunc, As &&...as)
Definition: Synchronized.h:807
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
std::mutex mutex
static SynchronizedType * getSynchronized(UnlockerData data)
detail::SynchronizedDataType< SynchronizedType > CDataType
Synchronized & operator=(typename std::conditional< std::is_copy_constructible< T >::value &&std::is_move_assignable< T >::value, const Synchronized &, NonImplementedType >::type rhs)
Definition: Synchronized.h:545
static set< string > s
LockedPtr< SynchronizedType, LockPolicyFromExclusiveToShared > moveFromWriteToRead()
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
auto ulock(Synchronized< D, M > &synchronized, Args &&...args)
ScopedUnlocker(ScopedUnlocker &&other) noexcept
std::tuple< Args... > args_
Definition: Synchronized.h:829
void swap(Synchronized< T, M > &lhs, Synchronized< T, M > &rhs)
decltype(auto) FOLLY_CPP14_CONSTEXPR fetch(Sequence &&sequence, Index &&index)
Definition: Foreach-inl.h:322
Collect as()
Definition: Base.h:811
ConstLockedPtr contextualLock(const std::chrono::duration< Rep, Period > &timeout) const
Definition: Synchronized.h:612
decltype(auto) constexpr apply(F &&func, Tuple &&tuple)
Definition: ApplyTuple.h:87
Synchronized(in_place_t, Args &&...args)
Definition: Synchronized.h:513
constexpr auto loop_break
Definition: Foreach.h:97
FOLLY_CPP14_CONSTEXPR Func for_each(Sequence &&sequence, Func func)
Definition: Foreach-inl.h:314
StringPiece data_
LockedPtrBase & operator=(LockedPtrBase &&rhs) noexcept
std::pair< std::unique_lock< std::mutex >, SynchronizedType * > UnlockerData
void copy(T *target) const
Definition: Synchronized.h:721
folly::Function< void()> parent
Definition: AtFork.cpp:34
typename SynchronizedType::MutexType MutexType
unsigned char * ptr_
Definition: Random.cpp:106