The OpenD Programming Language

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 }