1 module rt.sys.posix.oscondition; 2 3 version (Posix): 4 5 import core.sync.exception; 6 import core.sync.mutex; 7 import core.time; 8 9 import core.exception : AssertError, staticError; 10 11 import core.sync.config; 12 import core.stdc.errno; 13 import core.sys.posix.pthread; 14 import core.sys.posix.time; 15 16 17 struct OsCondition 18 { 19 void create(Mutex m) nothrow @trusted @nogc 20 { 21 static if ( is( typeof( pthread_condattr_setclock ) ) ) 22 { 23 () @trusted 24 { 25 pthread_condattr_t attr = void; 26 int rc = pthread_condattr_init( &attr ); 27 if ( rc ) 28 throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__); 29 rc = pthread_condattr_setclock( &attr, CLOCK_MONOTONIC ); 30 if ( rc ) 31 throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__); 32 rc = pthread_cond_init( cast(pthread_cond_t*) &m_hndl, &attr ); 33 if ( rc ) 34 throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__); 35 rc = pthread_condattr_destroy( &attr ); 36 if ( rc ) 37 throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__); 38 } (); 39 } 40 else 41 { 42 int rc = pthread_cond_init( cast(pthread_cond_t*) &m_hndl, null ); 43 if ( rc ) 44 throw staticError!AssertError("Unable to initialize condition", __FILE__, __LINE__); 45 } 46 m_assocMutex = m; 47 } 48 49 void destroy() @nogc @system 50 { 51 int rc = pthread_cond_destroy( &m_hndl ); 52 assert( !rc, "Unable to destroy condition" ); 53 } 54 55 void wait() @system 56 { 57 int rc = pthread_cond_wait( cast(pthread_cond_t*) &m_hndl, &m_assocMutex.osMutex.m_hndl); 58 if ( rc ) 59 throw staticError!AssertError("Unable to wait for condition", __FILE__, __LINE__); 60 } 61 62 bool wait( Duration val) @system 63 { 64 timespec t = void; 65 mktspec( t, val ); 66 67 int rc = pthread_cond_timedwait(cast(pthread_cond_t*) &m_hndl, 68 &m_assocMutex.osMutex.m_hndl, 69 &t ); 70 if ( !rc ) 71 return true; 72 if ( rc == ETIMEDOUT ) 73 return false; 74 throw staticError!AssertError("Unable to wait for condition", __FILE__, __LINE__); 75 } 76 77 void notify() @system 78 { 79 // Since OS X 10.7 (Lion), pthread_cond_signal returns EAGAIN after retrying 8192 times, 80 // so need to retrying while it returns EAGAIN. 81 // 82 // 10.7.0 (Lion): http://www.opensource.apple.com/source/Libc/Libc-763.11/pthreads/pthread_cond.c 83 // 10.8.0 (Mountain Lion): http://www.opensource.apple.com/source/Libc/Libc-825.24/pthreads/pthread_cond.c 84 // 10.10.0 (Yosemite): http://www.opensource.apple.com/source/libpthread/libpthread-105.1.4/src/pthread_cond.c 85 // 10.11.0 (El Capitan): http://www.opensource.apple.com/source/libpthread/libpthread-137.1.1/src/pthread_cond.c 86 // 10.12.0 (Sierra): http://www.opensource.apple.com/source/libpthread/libpthread-218.1.3/src/pthread_cond.c 87 // 10.13.0 (High Sierra): http://www.opensource.apple.com/source/libpthread/libpthread-301.1.6/src/pthread_cond.c 88 // 10.14.0 (Mojave): http://www.opensource.apple.com/source/libpthread/libpthread-330.201.1/src/pthread_cond.c 89 // 10.14.1 (Mojave): http://www.opensource.apple.com/source/libpthread/libpthread-330.220.2/src/pthread_cond.c 90 91 int rc; 92 do { 93 rc = pthread_cond_signal( cast(pthread_cond_t*) &m_hndl ); 94 } while ( rc == EAGAIN ); 95 if ( rc ) 96 throw staticError!AssertError("Unable to notify condition", __FILE__, __LINE__); 97 } 98 99 void notifyAll() @system 100 { 101 // Since OS X 10.7 (Lion), pthread_cond_broadcast returns EAGAIN after retrying 8192 times, 102 // so need to retrying while it returns EAGAIN. 103 // 104 // 10.7.0 (Lion): http://www.opensource.apple.com/source/Libc/Libc-763.11/pthreads/pthread_cond.c 105 // 10.8.0 (Mountain Lion): http://www.opensource.apple.com/source/Libc/Libc-825.24/pthreads/pthread_cond.c 106 // 10.10.0 (Yosemite): http://www.opensource.apple.com/source/libpthread/libpthread-105.1.4/src/pthread_cond.c 107 // 10.11.0 (El Capitan): http://www.opensource.apple.com/source/libpthread/libpthread-137.1.1/src/pthread_cond.c 108 // 10.12.0 (Sierra): http://www.opensource.apple.com/source/libpthread/libpthread-218.1.3/src/pthread_cond.c 109 // 10.13.0 (High Sierra): http://www.opensource.apple.com/source/libpthread/libpthread-301.1.6/src/pthread_cond.c 110 // 10.14.0 (Mojave): http://www.opensource.apple.com/source/libpthread/libpthread-330.201.1/src/pthread_cond.c 111 // 10.14.1 (Mojave): http://www.opensource.apple.com/source/libpthread/libpthread-330.220.2/src/pthread_cond.c 112 113 int rc; 114 do { 115 rc = pthread_cond_broadcast( cast(pthread_cond_t*) &m_hndl ); 116 } while ( rc == EAGAIN ); 117 if ( rc ) 118 throw staticError!AssertError("Unable to notify condition", __FILE__, __LINE__); 119 } 120 121 @property Mutex mutex() 122 { 123 return m_assocMutex; 124 } 125 126 /// ditto 127 @property shared(Mutex) mutex() shared 128 { 129 import core.atomic : atomicLoad; 130 return atomicLoad(m_assocMutex); 131 } 132 133 // undocumented function for internal use 134 final @property Mutex mutex_nothrow() pure nothrow @safe @nogc 135 { 136 return m_assocMutex; 137 } 138 139 // ditto 140 final @property shared(Mutex) mutex_nothrow() shared pure nothrow @safe @nogc 141 { 142 import core.atomic : atomicLoad; 143 return atomicLoad(m_assocMutex); 144 } 145 146 private: 147 Mutex m_assocMutex; 148 pthread_cond_t m_hndl; 149 }