sync.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. /*
  2. * SRT - Secure, Reliable, Transport
  3. * Copyright (c) 2019 Haivision Systems Inc.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. */
  10. #pragma once
  11. #ifndef INC_SRT_SYNC_H
  12. #define INC_SRT_SYNC_H
  13. #include "platform_sys.h"
  14. #include <cstdlib>
  15. #include <limits>
  16. #ifdef ENABLE_STDCXX_SYNC
  17. #include <chrono>
  18. #include <thread>
  19. #include <mutex>
  20. #include <condition_variable>
  21. #include <atomic>
  22. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_STDCXX_STEADY
  23. #define SRT_SYNC_CLOCK_STR "STDCXX_STEADY"
  24. #else
  25. #include <pthread.h>
  26. // Defile clock type to use
  27. #ifdef IA32
  28. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_IA32_RDTSC
  29. #define SRT_SYNC_CLOCK_STR "IA32_RDTSC"
  30. #elif defined(IA64)
  31. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_IA64_ITC
  32. #define SRT_SYNC_CLOCK_STR "IA64_ITC"
  33. #elif defined(AMD64)
  34. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_AMD64_RDTSC
  35. #define SRT_SYNC_CLOCK_STR "AMD64_RDTSC"
  36. #elif defined(_WIN32)
  37. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_WINQPC
  38. #define SRT_SYNC_CLOCK_STR "WINQPC"
  39. #elif TARGET_OS_MAC
  40. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_MACH_ABSTIME
  41. #define SRT_SYNC_CLOCK_STR "MACH_ABSTIME"
  42. #elif defined(ENABLE_MONOTONIC_CLOCK)
  43. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_GETTIME_MONOTONIC
  44. #define SRT_SYNC_CLOCK_STR "GETTIME_MONOTONIC"
  45. #else
  46. #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY
  47. #define SRT_SYNC_CLOCK_STR "POSIX_GETTIMEOFDAY"
  48. #endif
  49. #endif // ENABLE_STDCXX_SYNC
  50. #include "srt.h"
  51. #include "utilities.h"
  52. #include "srt_attr_defs.h"
  53. namespace srt
  54. {
  55. class CUDTException; // defined in common.h
  56. namespace sync
  57. {
  58. ///////////////////////////////////////////////////////////////////////////////
  59. //
  60. // Duration class
  61. //
  62. ///////////////////////////////////////////////////////////////////////////////
  63. #if ENABLE_STDCXX_SYNC
  64. template <class Clock>
  65. using Duration = std::chrono::duration<Clock>;
  66. #else
  67. /// Class template srt::sync::Duration represents a time interval.
  68. /// It consists of a count of ticks of _Clock.
  69. /// It is a wrapper of system timers in case of non-C++11 chrono build.
  70. template <class Clock>
  71. class Duration
  72. {
  73. public:
  74. Duration()
  75. : m_duration(0)
  76. {
  77. }
  78. explicit Duration(int64_t d)
  79. : m_duration(d)
  80. {
  81. }
  82. public:
  83. inline int64_t count() const { return m_duration; }
  84. static Duration zero() { return Duration(); }
  85. public: // Relational operators
  86. inline bool operator>=(const Duration& rhs) const { return m_duration >= rhs.m_duration; }
  87. inline bool operator>(const Duration& rhs) const { return m_duration > rhs.m_duration; }
  88. inline bool operator==(const Duration& rhs) const { return m_duration == rhs.m_duration; }
  89. inline bool operator!=(const Duration& rhs) const { return m_duration != rhs.m_duration; }
  90. inline bool operator<=(const Duration& rhs) const { return m_duration <= rhs.m_duration; }
  91. inline bool operator<(const Duration& rhs) const { return m_duration < rhs.m_duration; }
  92. public: // Assignment operators
  93. inline void operator*=(const int64_t mult) { m_duration = static_cast<int64_t>(m_duration * mult); }
  94. inline void operator+=(const Duration& rhs) { m_duration += rhs.m_duration; }
  95. inline void operator-=(const Duration& rhs) { m_duration -= rhs.m_duration; }
  96. inline Duration operator+(const Duration& rhs) const { return Duration(m_duration + rhs.m_duration); }
  97. inline Duration operator-(const Duration& rhs) const { return Duration(m_duration - rhs.m_duration); }
  98. inline Duration operator*(const int64_t& rhs) const { return Duration(m_duration * rhs); }
  99. inline Duration operator/(const int64_t& rhs) const { return Duration(m_duration / rhs); }
  100. private:
  101. // int64_t range is from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
  102. int64_t m_duration;
  103. };
  104. #endif // ENABLE_STDCXX_SYNC
  105. ///////////////////////////////////////////////////////////////////////////////
  106. //
  107. // TimePoint and steadt_clock classes
  108. //
  109. ///////////////////////////////////////////////////////////////////////////////
  110. #if ENABLE_STDCXX_SYNC
  111. using steady_clock = std::chrono::steady_clock;
  112. template <class Clock, class Duration = typename Clock::duration>
  113. using time_point = std::chrono::time_point<Clock, Duration>;
  114. template <class Clock>
  115. using TimePoint = std::chrono::time_point<Clock>;
  116. template <class Clock, class Duration = typename Clock::duration>
  117. inline bool is_zero(const time_point<Clock, Duration> &tp)
  118. {
  119. return tp.time_since_epoch() == Clock::duration::zero();
  120. }
  121. inline bool is_zero(const steady_clock::time_point& t)
  122. {
  123. return t == steady_clock::time_point();
  124. }
  125. #else
  126. template <class Clock>
  127. class TimePoint;
  128. class steady_clock
  129. {
  130. public:
  131. typedef Duration<steady_clock> duration;
  132. typedef TimePoint<steady_clock> time_point;
  133. public:
  134. static time_point now();
  135. };
  136. /// Represents a point in time
  137. template <class Clock>
  138. class TimePoint
  139. {
  140. public:
  141. TimePoint()
  142. : m_timestamp(0)
  143. {
  144. }
  145. explicit TimePoint(uint64_t tp)
  146. : m_timestamp(tp)
  147. {
  148. }
  149. TimePoint(const TimePoint<Clock>& other)
  150. : m_timestamp(other.m_timestamp)
  151. {
  152. }
  153. TimePoint(const Duration<Clock>& duration_since_epoch)
  154. : m_timestamp(duration_since_epoch.count())
  155. {
  156. }
  157. ~TimePoint() {}
  158. public: // Relational operators
  159. inline bool operator<(const TimePoint<Clock>& rhs) const { return m_timestamp < rhs.m_timestamp; }
  160. inline bool operator<=(const TimePoint<Clock>& rhs) const { return m_timestamp <= rhs.m_timestamp; }
  161. inline bool operator==(const TimePoint<Clock>& rhs) const { return m_timestamp == rhs.m_timestamp; }
  162. inline bool operator!=(const TimePoint<Clock>& rhs) const { return m_timestamp != rhs.m_timestamp; }
  163. inline bool operator>=(const TimePoint<Clock>& rhs) const { return m_timestamp >= rhs.m_timestamp; }
  164. inline bool operator>(const TimePoint<Clock>& rhs) const { return m_timestamp > rhs.m_timestamp; }
  165. public: // Arithmetic operators
  166. inline Duration<Clock> operator-(const TimePoint<Clock>& rhs) const
  167. {
  168. return Duration<Clock>(m_timestamp - rhs.m_timestamp);
  169. }
  170. inline TimePoint operator+(const Duration<Clock>& rhs) const { return TimePoint(m_timestamp + rhs.count()); }
  171. inline TimePoint operator-(const Duration<Clock>& rhs) const { return TimePoint(m_timestamp - rhs.count()); }
  172. public: // Assignment operators
  173. inline void operator=(const TimePoint<Clock>& rhs) { m_timestamp = rhs.m_timestamp; }
  174. inline void operator+=(const Duration<Clock>& rhs) { m_timestamp += rhs.count(); }
  175. inline void operator-=(const Duration<Clock>& rhs) { m_timestamp -= rhs.count(); }
  176. public: //
  177. static inline ATR_CONSTEXPR TimePoint min() { return TimePoint(std::numeric_limits<uint64_t>::min()); }
  178. static inline ATR_CONSTEXPR TimePoint max() { return TimePoint(std::numeric_limits<uint64_t>::max()); }
  179. public:
  180. Duration<Clock> time_since_epoch() const;
  181. private:
  182. uint64_t m_timestamp;
  183. };
  184. template <>
  185. srt::sync::Duration<srt::sync::steady_clock> srt::sync::TimePoint<srt::sync::steady_clock>::time_since_epoch() const;
  186. inline Duration<steady_clock> operator*(const int& lhs, const Duration<steady_clock>& rhs)
  187. {
  188. return rhs * lhs;
  189. }
  190. #endif // ENABLE_STDCXX_SYNC
  191. // NOTE: Moved the following class definitions to "atomic_clock.h"
  192. // template <class Clock>
  193. // class AtomicDuration;
  194. // template <class Clock>
  195. // class AtomicClock;
  196. ///////////////////////////////////////////////////////////////////////////////
  197. //
  198. // Duration and timepoint conversions
  199. //
  200. ///////////////////////////////////////////////////////////////////////////////
  201. /// Function return number of decimals in a subsecond precision.
  202. /// E.g. for a microsecond accuracy of steady_clock the return would be 6.
  203. /// For a nanosecond accuracy of the steady_clock the return value would be 9.
  204. int clockSubsecondPrecision();
  205. #if ENABLE_STDCXX_SYNC
  206. inline long long count_microseconds(const steady_clock::duration &t)
  207. {
  208. return std::chrono::duration_cast<std::chrono::microseconds>(t).count();
  209. }
  210. inline long long count_microseconds(const steady_clock::time_point tp)
  211. {
  212. return std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count();
  213. }
  214. inline long long count_milliseconds(const steady_clock::duration &t)
  215. {
  216. return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
  217. }
  218. inline long long count_seconds(const steady_clock::duration &t)
  219. {
  220. return std::chrono::duration_cast<std::chrono::seconds>(t).count();
  221. }
  222. inline steady_clock::duration microseconds_from(int64_t t_us)
  223. {
  224. return std::chrono::microseconds(t_us);
  225. }
  226. inline steady_clock::duration milliseconds_from(int64_t t_ms)
  227. {
  228. return std::chrono::milliseconds(t_ms);
  229. }
  230. inline steady_clock::duration seconds_from(int64_t t_s)
  231. {
  232. return std::chrono::seconds(t_s);
  233. }
  234. #else
  235. int64_t count_microseconds(const steady_clock::duration& t);
  236. int64_t count_milliseconds(const steady_clock::duration& t);
  237. int64_t count_seconds(const steady_clock::duration& t);
  238. Duration<steady_clock> microseconds_from(int64_t t_us);
  239. Duration<steady_clock> milliseconds_from(int64_t t_ms);
  240. Duration<steady_clock> seconds_from(int64_t t_s);
  241. inline bool is_zero(const TimePoint<steady_clock>& t)
  242. {
  243. return t == TimePoint<steady_clock>();
  244. }
  245. #endif // ENABLE_STDCXX_SYNC
  246. ///////////////////////////////////////////////////////////////////////////////
  247. //
  248. // Mutex section
  249. //
  250. ///////////////////////////////////////////////////////////////////////////////
  251. #if ENABLE_STDCXX_SYNC
  252. using Mutex = std::mutex;
  253. using UniqueLock = std::unique_lock<std::mutex>;
  254. using ScopedLock = std::lock_guard<std::mutex>;
  255. #else
  256. /// Mutex is a class wrapper, that should mimic the std::chrono::mutex class.
  257. /// At the moment the extra function ref() is temporally added to allow calls
  258. /// to pthread_cond_timedwait(). Will be removed by introducing CEvent.
  259. class SRT_ATTR_CAPABILITY("mutex") Mutex
  260. {
  261. friend class SyncEvent;
  262. public:
  263. Mutex();
  264. ~Mutex();
  265. public:
  266. int lock() SRT_ATTR_ACQUIRE();
  267. int unlock() SRT_ATTR_RELEASE();
  268. /// @return true if the lock was acquired successfully, otherwise false
  269. bool try_lock() SRT_ATTR_TRY_ACQUIRE(true);
  270. // TODO: To be removed with introduction of the CEvent.
  271. pthread_mutex_t& ref() { return m_mutex; }
  272. private:
  273. pthread_mutex_t m_mutex;
  274. };
  275. /// A pthread version of std::chrono::scoped_lock<mutex> (or lock_guard for C++11)
  276. class SRT_ATTR_SCOPED_CAPABILITY ScopedLock
  277. {
  278. public:
  279. SRT_ATTR_ACQUIRE(m)
  280. explicit ScopedLock(Mutex& m);
  281. SRT_ATTR_RELEASE()
  282. ~ScopedLock();
  283. private:
  284. Mutex& m_mutex;
  285. };
  286. /// A pthread version of std::chrono::unique_lock<mutex>
  287. class SRT_ATTR_SCOPED_CAPABILITY UniqueLock
  288. {
  289. friend class SyncEvent;
  290. int m_iLocked;
  291. Mutex& m_Mutex;
  292. public:
  293. SRT_ATTR_ACQUIRE(m)
  294. explicit UniqueLock(Mutex &m);
  295. SRT_ATTR_RELEASE()
  296. ~UniqueLock();
  297. public:
  298. SRT_ATTR_ACQUIRE()
  299. void lock();
  300. SRT_ATTR_RELEASE()
  301. void unlock();
  302. SRT_ATTR_RETURN_CAPABILITY(m_Mutex)
  303. Mutex* mutex(); // reflects C++11 unique_lock::mutex()
  304. };
  305. #endif // ENABLE_STDCXX_SYNC
  306. inline void enterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) { m.lock(); }
  307. inline bool tryEnterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); }
  308. inline void leaveCS(Mutex& m) SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) { m.unlock(); }
  309. class InvertedLock
  310. {
  311. Mutex& m_mtx;
  312. public:
  313. SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m)
  314. InvertedLock(Mutex& m)
  315. : m_mtx(m)
  316. {
  317. m_mtx.unlock();
  318. }
  319. SRT_ATTR_ACQUIRE(m_mtx)
  320. ~InvertedLock()
  321. {
  322. m_mtx.lock();
  323. }
  324. };
  325. inline void setupMutex(Mutex&, const char*) {}
  326. inline void releaseMutex(Mutex&) {}
  327. ////////////////////////////////////////////////////////////////////////////////
  328. //
  329. // Condition section
  330. //
  331. ////////////////////////////////////////////////////////////////////////////////
  332. class Condition
  333. {
  334. public:
  335. Condition();
  336. ~Condition();
  337. public:
  338. /// These functions do not align with C++11 version. They are here hopefully as a temporal solution
  339. /// to avoud issues with static initialization of CV on windows.
  340. void init();
  341. void destroy();
  342. public:
  343. /// Causes the current thread to block until the condition variable is notified
  344. /// or a spurious wakeup occurs.
  345. ///
  346. /// @param lock Corresponding mutex locked by UniqueLock
  347. void wait(UniqueLock& lock);
  348. /// Atomically releases lock, blocks the current executing thread,
  349. /// and adds it to the list of threads waiting on *this.
  350. /// The thread will be unblocked when notify_all() or notify_one() is executed,
  351. /// or when the relative timeout rel_time expires.
  352. /// It may also be unblocked spuriously. When unblocked, regardless of the reason,
  353. /// lock is reacquired and wait_for() exits.
  354. ///
  355. /// @returns false if the relative timeout specified by rel_time expired,
  356. /// true otherwise (signal or spurious wake up).
  357. ///
  358. /// @note Calling this function if lock.mutex()
  359. /// is not locked by the current thread is undefined behavior.
  360. /// Calling this function if lock.mutex() is not the same mutex as the one
  361. /// used by all other threads that are currently waiting on the same
  362. /// condition variable is undefined behavior.
  363. bool wait_for(UniqueLock& lock, const steady_clock::duration& rel_time);
  364. /// Causes the current thread to block until the condition variable is notified,
  365. /// a specific time is reached, or a spurious wakeup occurs.
  366. ///
  367. /// @param[in] lock an object of type UniqueLock, which must be locked by the current thread
  368. /// @param[in] timeout_time an object of type time_point representing the time when to stop waiting
  369. ///
  370. /// @returns false if the relative timeout specified by timeout_time expired,
  371. /// true otherwise (signal or spurious wake up).
  372. bool wait_until(UniqueLock& lock, const steady_clock::time_point& timeout_time);
  373. /// Calling notify_one() unblocks one of the waiting threads,
  374. /// if any threads are waiting on this CV.
  375. void notify_one();
  376. /// Unblocks all threads currently waiting for this CV.
  377. void notify_all();
  378. private:
  379. #if ENABLE_STDCXX_SYNC
  380. std::condition_variable m_cv;
  381. #else
  382. pthread_cond_t m_cv;
  383. #endif
  384. };
  385. inline void setupCond(Condition& cv, const char*) { cv.init(); }
  386. inline void releaseCond(Condition& cv) { cv.destroy(); }
  387. ///////////////////////////////////////////////////////////////////////////////
  388. //
  389. // Event (CV) section
  390. //
  391. ///////////////////////////////////////////////////////////////////////////////
  392. // This class is used for condition variable combined with mutex by different ways.
  393. // This should provide a cleaner API around locking with debug-logging inside.
  394. class CSync
  395. {
  396. protected:
  397. Condition* m_cond;
  398. UniqueLock* m_locker;
  399. public:
  400. // Locked version: must be declared only after the declaration of UniqueLock,
  401. // which has locked the mutex. On this delegate you should call only
  402. // signal_locked() and pass the UniqueLock variable that should remain locked.
  403. // Also wait() and wait_for() can be used only with this socket.
  404. CSync(Condition& cond, UniqueLock& g)
  405. : m_cond(&cond), m_locker(&g)
  406. {
  407. // XXX it would be nice to check whether the owner is also current thread
  408. // but this can't be done portable way.
  409. // When constructed by this constructor, the user is expected
  410. // to only call signal_locked() function. You should pass the same guard
  411. // variable that you have used for construction as its argument.
  412. }
  413. // COPY CONSTRUCTOR: DEFAULT!
  414. // Wait indefinitely, until getting a signal on CV.
  415. void wait()
  416. {
  417. m_cond->wait(*m_locker);
  418. }
  419. /// Block the call until either @a timestamp time achieved
  420. /// or the conditional is signaled.
  421. /// @param [in] delay Maximum time to wait since the moment of the call
  422. /// @retval false if the relative timeout specified by rel_time expired,
  423. /// @retval true if condition is signaled or spurious wake up.
  424. bool wait_for(const steady_clock::duration& delay)
  425. {
  426. return m_cond->wait_for(*m_locker, delay);
  427. }
  428. // Wait until the given time is achieved.
  429. /// @param [in] exptime The target time to wait until.
  430. /// @retval false if the target wait time is reached.
  431. /// @retval true if condition is signal or spurious wake up.
  432. bool wait_until(const steady_clock::time_point& exptime)
  433. {
  434. return m_cond->wait_until(*m_locker, exptime);
  435. }
  436. // Static ad-hoc version
  437. static void lock_notify_one(Condition& cond, Mutex& m)
  438. {
  439. ScopedLock lk(m); // XXX with thread logging, don't use ScopedLock directly!
  440. cond.notify_one();
  441. }
  442. static void lock_notify_all(Condition& cond, Mutex& m)
  443. {
  444. ScopedLock lk(m); // XXX with thread logging, don't use ScopedLock directly!
  445. cond.notify_all();
  446. }
  447. void notify_one_locked(UniqueLock& lk SRT_ATR_UNUSED)
  448. {
  449. // EXPECTED: lk.mutex() is LOCKED.
  450. m_cond->notify_one();
  451. }
  452. void notify_all_locked(UniqueLock& lk SRT_ATR_UNUSED)
  453. {
  454. // EXPECTED: lk.mutex() is LOCKED.
  455. m_cond->notify_all();
  456. }
  457. // The *_relaxed functions are to be used in case when you don't care
  458. // whether the associated mutex is locked or not (you accept the case that
  459. // a mutex isn't locked and the condition notification gets effectively
  460. // missed), or you somehow know that the mutex is locked, but you don't
  461. // have access to the associated UniqueLock object. This function, although
  462. // it does the same thing as CSync::notify_one_locked etc. here for the
  463. // user to declare explicitly that notifying is done without being
  464. // prematurely certain that the associated mutex is locked.
  465. //
  466. // It is then expected that whenever these functions are used, an extra
  467. // comment is provided to explain, why the use of the relaxed notification
  468. // is correctly used.
  469. void notify_one_relaxed() { notify_one_relaxed(*m_cond); }
  470. static void notify_one_relaxed(Condition& cond) { cond.notify_one(); }
  471. static void notify_all_relaxed(Condition& cond) { cond.notify_all(); }
  472. };
  473. ////////////////////////////////////////////////////////////////////////////////
  474. //
  475. // CEvent class
  476. //
  477. ////////////////////////////////////////////////////////////////////////////////
  478. // XXX Do not use this class now, there's an unknown issue
  479. // connected to object management with the use of release* functions.
  480. // Until this is solved, stay with separate *Cond and *Lock fields.
  481. class CEvent
  482. {
  483. public:
  484. CEvent();
  485. ~CEvent();
  486. public:
  487. Mutex& mutex() { return m_lock; }
  488. Condition& cond() { return m_cond; }
  489. public:
  490. /// Causes the current thread to block until
  491. /// a specific time is reached.
  492. ///
  493. /// @return true if condition occurred or spuriously woken up
  494. /// false on timeout
  495. bool lock_wait_until(const steady_clock::time_point& tp);
  496. /// Blocks the current executing thread,
  497. /// and adds it to the list of threads waiting on* this.
  498. /// The thread will be unblocked when notify_all() or notify_one() is executed,
  499. /// or when the relative timeout rel_time expires.
  500. /// It may also be unblocked spuriously.
  501. /// Uses internal mutex to lock.
  502. ///
  503. /// @return true if condition occurred or spuriously woken up
  504. /// false on timeout
  505. bool lock_wait_for(const steady_clock::duration& rel_time);
  506. /// Atomically releases lock, blocks the current executing thread,
  507. /// and adds it to the list of threads waiting on* this.
  508. /// The thread will be unblocked when notify_all() or notify_one() is executed,
  509. /// or when the relative timeout rel_time expires.
  510. /// It may also be unblocked spuriously.
  511. /// When unblocked, regardless of the reason, lock is reacquiredand wait_for() exits.
  512. ///
  513. /// @return true if condition occurred or spuriously woken up
  514. /// false on timeout
  515. bool wait_for(UniqueLock& lk, const steady_clock::duration& rel_time);
  516. void lock_wait();
  517. void wait(UniqueLock& lk);
  518. void notify_one();
  519. void notify_all();
  520. void lock_notify_one()
  521. {
  522. ScopedLock lk(m_lock); // XXX with thread logging, don't use ScopedLock directly!
  523. m_cond.notify_one();
  524. }
  525. void lock_notify_all()
  526. {
  527. ScopedLock lk(m_lock); // XXX with thread logging, don't use ScopedLock directly!
  528. m_cond.notify_all();
  529. }
  530. private:
  531. Mutex m_lock;
  532. Condition m_cond;
  533. };
  534. // This class binds together the functionality of
  535. // UniqueLock and CSync. It provides a simple interface of CSync
  536. // while having already the UniqueLock applied in the scope,
  537. // so a safe statement can be made about the mutex being locked
  538. // when signalling or waiting.
  539. class CUniqueSync: public CSync
  540. {
  541. UniqueLock m_ulock;
  542. public:
  543. UniqueLock& locker() { return m_ulock; }
  544. CUniqueSync(Mutex& mut, Condition& cnd)
  545. : CSync(cnd, m_ulock)
  546. , m_ulock(mut)
  547. {
  548. }
  549. CUniqueSync(CEvent& event)
  550. : CSync(event.cond(), m_ulock)
  551. , m_ulock(event.mutex())
  552. {
  553. }
  554. // These functions can be used safely because
  555. // this whole class guarantees that whatever happens
  556. // while its object exists is that the mutex is locked.
  557. void notify_one()
  558. {
  559. m_cond->notify_one();
  560. }
  561. void notify_all()
  562. {
  563. m_cond->notify_all();
  564. }
  565. };
  566. class CTimer
  567. {
  568. public:
  569. CTimer();
  570. ~CTimer();
  571. public:
  572. /// Causes the current thread to block until
  573. /// the specified time is reached.
  574. /// Sleep can be interrupted by calling interrupt()
  575. /// or woken up to recheck the scheduled time by tick()
  576. /// @param tp target time to sleep until
  577. ///
  578. /// @return true if the specified time was reached
  579. /// false should never happen
  580. bool sleep_until(steady_clock::time_point tp);
  581. /// Resets target wait time and interrupts waiting
  582. /// in sleep_until(..)
  583. void interrupt();
  584. /// Wakes up waiting thread (sleep_until(..)) without
  585. /// changing the target waiting time to force a recheck
  586. /// of the current time in comparisson to the target time.
  587. void tick();
  588. private:
  589. CEvent m_event;
  590. steady_clock::time_point m_tsSchedTime;
  591. };
  592. /// Print steady clock timepoint in a human readable way.
  593. /// days HH:MM:SS.us [STD]
  594. /// Example: 1D 02:12:56.123456
  595. ///
  596. /// @param [in] steady clock timepoint
  597. /// @returns a string with a formatted time representation
  598. std::string FormatTime(const steady_clock::time_point& time);
  599. /// Print steady clock timepoint relative to the current system time
  600. /// Date HH:MM:SS.us [SYS]
  601. /// @param [in] steady clock timepoint
  602. /// @returns a string with a formatted time representation
  603. std::string FormatTimeSys(const steady_clock::time_point& time);
  604. enum eDurationUnit {DUNIT_S, DUNIT_MS, DUNIT_US};
  605. template <eDurationUnit u>
  606. struct DurationUnitName;
  607. template<>
  608. struct DurationUnitName<DUNIT_US>
  609. {
  610. static const char* name() { return "us"; }
  611. static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur)); }
  612. };
  613. template<>
  614. struct DurationUnitName<DUNIT_MS>
  615. {
  616. static const char* name() { return "ms"; }
  617. static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur))/1000.0; }
  618. };
  619. template<>
  620. struct DurationUnitName<DUNIT_S>
  621. {
  622. static const char* name() { return "s"; }
  623. static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur))/1000000.0; }
  624. };
  625. template<eDurationUnit UNIT>
  626. inline std::string FormatDuration(const steady_clock::duration& dur)
  627. {
  628. return Sprint(DurationUnitName<UNIT>::count(dur)) + DurationUnitName<UNIT>::name();
  629. }
  630. inline std::string FormatDuration(const steady_clock::duration& dur)
  631. {
  632. return FormatDuration<DUNIT_US>(dur);
  633. }
  634. ////////////////////////////////////////////////////////////////////////////////
  635. //
  636. // CGlobEvent class
  637. //
  638. ////////////////////////////////////////////////////////////////////////////////
  639. class CGlobEvent
  640. {
  641. public:
  642. /// Triggers the event and notifies waiting threads.
  643. /// Simply calls notify_one().
  644. static void triggerEvent();
  645. /// Waits for the event to be triggered with 10ms timeout.
  646. /// Simply calls wait_for().
  647. static bool waitForEvent();
  648. };
  649. ////////////////////////////////////////////////////////////////////////////////
  650. //
  651. // CThread class
  652. //
  653. ////////////////////////////////////////////////////////////////////////////////
  654. #ifdef ENABLE_STDCXX_SYNC
  655. typedef std::system_error CThreadException;
  656. using CThread = std::thread;
  657. namespace this_thread = std::this_thread;
  658. #else // pthreads wrapper version
  659. typedef CUDTException CThreadException;
  660. class CThread
  661. {
  662. public:
  663. CThread();
  664. /// @throws std::system_error if the thread could not be started.
  665. CThread(void *(*start_routine) (void *), void *arg);
  666. #if HAVE_FULL_CXX11
  667. CThread& operator=(CThread &other) = delete;
  668. CThread& operator=(CThread &&other);
  669. #else
  670. CThread& operator=(CThread &other);
  671. /// To be used only in StartThread function.
  672. /// Creates a new stread and assigns to this.
  673. /// @throw CThreadException
  674. void create_thread(void *(*start_routine) (void *), void *arg);
  675. #endif
  676. public: // Observers
  677. /// Checks if the CThread object identifies an active thread of execution.
  678. /// A default constructed thread is not joinable.
  679. /// A thread that has finished executing code, but has not yet been joined
  680. /// is still considered an active thread of execution and is therefore joinable.
  681. bool joinable() const;
  682. struct id
  683. {
  684. explicit id(const pthread_t t)
  685. : value(t)
  686. {}
  687. const pthread_t value;
  688. inline bool operator==(const id& second) const
  689. {
  690. return pthread_equal(value, second.value) != 0;
  691. }
  692. };
  693. /// Returns the id of the current thread.
  694. /// In this implementation the ID is the pthread_t.
  695. const id get_id() const { return id(m_thread); }
  696. public:
  697. /// Blocks the current thread until the thread identified by *this finishes its execution.
  698. /// If that thread has already terminated, then join() returns immediately.
  699. ///
  700. /// @throws std::system_error if an error occurs
  701. void join();
  702. public: // Internal
  703. /// Calls pthread_create, throws exception on failure.
  704. /// @throw CThreadException
  705. void create(void *(*start_routine) (void *), void *arg);
  706. private:
  707. pthread_t m_thread;
  708. };
  709. template <class Stream>
  710. inline Stream& operator<<(Stream& str, const CThread::id& cid)
  711. {
  712. #if defined(_WIN32) && (defined(PTW32_VERSION) || defined (__PTW32_VERSION))
  713. // This is a version specific for pthread-win32 implementation
  714. // Here pthread_t type is a structure that is not convertible
  715. // to a number at all.
  716. return str << pthread_getw32threadid_np(cid.value);
  717. #else
  718. return str << cid.value;
  719. #endif
  720. }
  721. namespace this_thread
  722. {
  723. const inline CThread::id get_id() { return CThread::id (pthread_self()); }
  724. inline void sleep_for(const steady_clock::duration& t)
  725. {
  726. #if !defined(_WIN32)
  727. usleep(count_microseconds(t)); // microseconds
  728. #else
  729. Sleep((DWORD) count_milliseconds(t));
  730. #endif
  731. }
  732. }
  733. #endif
  734. /// StartThread function should be used to do CThread assignments:
  735. /// @code
  736. /// CThread a();
  737. /// a = CThread(func, args);
  738. /// @endcode
  739. ///
  740. /// @returns true if thread was started successfully,
  741. /// false on failure
  742. ///
  743. #ifdef ENABLE_STDCXX_SYNC
  744. typedef void* (&ThreadFunc) (void*);
  745. bool StartThread(CThread& th, ThreadFunc&& f, void* args, const std::string& name);
  746. #else
  747. bool StartThread(CThread& th, void* (*f) (void*), void* args, const std::string& name);
  748. #endif
  749. ////////////////////////////////////////////////////////////////////////////////
  750. //
  751. // CThreadError class - thread local storage wrapper
  752. //
  753. ////////////////////////////////////////////////////////////////////////////////
  754. /// Set thread local error
  755. /// @param e new CUDTException
  756. void SetThreadLocalError(const CUDTException& e);
  757. /// Get thread local error
  758. /// @returns CUDTException pointer
  759. CUDTException& GetThreadLocalError();
  760. ////////////////////////////////////////////////////////////////////////////////
  761. //
  762. // Random distribution functions.
  763. //
  764. ////////////////////////////////////////////////////////////////////////////////
  765. /// Generate a uniform-distributed random integer from [minVal; maxVal].
  766. /// If HAVE_CXX11, uses std::uniform_distribution(std::random_device).
  767. /// @param[in] minVal minimum allowed value of the resulting random number.
  768. /// @param[in] maxVal maximum allowed value of the resulting random number.
  769. int genRandomInt(int minVal, int maxVal);
  770. } // namespace sync
  771. } // namespace srt
  772. #include "atomic_clock.h"
  773. #endif // INC_SRT_SYNC_H