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