- Formatting fixes
[reactos.git] / irc / ArchBlackmann / ReliMT.cpp
1 // ReliMT.cpp
2 // lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
3 // The rest is (C) 2002-2004 Royce Mitchell III
4 // and released under the LGPL & BSD licenses
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #ifdef WIN32
9 # define WIN32_LEAN_AND_MEAN
10 # include <windows.h>
11 # define snprintf _snprintf
12 #elif defined(UNIX)
13 # include <errno.h>
14 # include <sys/sem.h>
15 #else
16 # error unrecognized target
17 #endif//WIN32|UNIX
18 #include "verify.h"
19 #include "ReliMT.h"
20
21 ////////////////////////////////////////////////////////////////////////////////
22 // Assert
23
24 void _wassert ( char* szExpr, char* szFile, int line )
25 {
26 fprintf ( stderr, "Assertion Failure: \"%s\" in file %s, line %d", szExpr, szFile, line );
27 exit (-1);
28 }
29
30
31 ////////////////////////////////////////////////////////////////////////////////
32 // Thread
33
34 Thread::Thread ( long (THREADAPI * pFun) (void* arg), void* pArg )
35 {
36 #ifdef WIN32
37 verify ( _handle = CreateThread (
38 0, // Security attributes
39 0, // Stack size
40 (DWORD (WINAPI*)(void*))pFun,
41 pArg,
42 0, // don't create suspended.
43 &_tid ));
44 #elif defined(UNIX)
45 // set up the thread attribute: right now, we do nothing with it.
46 pthread_attr_t attr;
47 pthread_attr_init(&attr);
48
49 // this will make the threads created by this process really concurrent
50 verify ( !pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) );
51
52 // create the new OS thread object
53 verify ( !pthread_create ( &_threadId, &attr, (void* (*) (void*))pFun, pArg ) );
54
55 verify ( !pthread_attr_destroy(&attr) );
56 #else
57 # error unrecognized target
58 #endif//WIN32|UNIX
59 }
60
61 Thread::~Thread()
62 {
63 #ifdef WIN32
64 verify ( CloseHandle ( _handle ) );
65 #elif defined(UNIX)
66 verify ( !pthread_cancel ( _threadId ) );
67 #else
68 # error unrecognized target
69 #endif//WIN32|UNIX
70 }
71
72 /*void Thread::Resume()
73 {
74 #ifdef WIN32
75 ResumeThread (_handle);
76 #elif defined(UNIX)
77 # error how to resume thread in unix?
78 #else
79 # error unrecognized target
80 #endif//WIN32|UNIX
81 }*/
82
83 void Thread::WaitForDeath()
84 {
85 #ifdef WIN32
86 DWORD dw = WaitForSingleObject ( _handle, 2000 );
87 ASSERT ( dw != WAIT_FAILED );
88 #elif defined(UNIX)
89 verify ( !pthread_join ( _threadId, (void**)NULL ) );
90 #else
91 # error unrecognized target
92 #endif//WIN32|UNIX
93 }
94
95
96 ////////////////////////////////////////////////////////////////////////////////
97 // ActiveObject
98
99 // The constructor of the derived class
100 // should call
101 // _thread.Resume();
102 // at the end of construction
103
104 ActiveObject::ActiveObject() : _isDying (0), _thread (0)
105 {
106 }
107
108 ActiveObject::~ActiveObject()
109 {
110 ASSERT ( !_thread ); // call Kill() from subclass's dtor
111 // Kill() - // You can't call a virtual function from a dtor, EVEN INDIRECTLY
112 // so, you must call Kill() in the subclass's dtor
113 }
114
115 // FlushThread must reset all the events on which the thread might be waiting.
116 void ActiveObject::Kill()
117 {
118 if ( _thread )
119 {
120 _isDying++;
121 FlushThread();
122 // Let's make sure it's gone
123 _thread->WaitForDeath();
124 delete _thread;
125 _thread = 0;
126 }
127 }
128
129 void ActiveObject::Start()
130 {
131 ASSERT ( !_thread );
132 _thread = new Thread ( ThreadEntry, this );
133 }
134
135 long THREADAPI ActiveObject::ThreadEntry ( void* pArg )
136 {
137 ActiveObject * pActive = (ActiveObject*)pArg;
138 pActive->InitThread();
139 pActive->Run();
140 pActive->Kill();
141 return 0;
142 }
143
144
145 ///////////////////////////////////////////////////////////////////////////////
146 // Mutex
147
148 Mutex::Mutex()
149 {
150 #ifdef WIN32
151 verify ( _h = CreateMutex ( NULL, FALSE, NULL ) );
152 #elif defined(UNIX)
153 pthread_mutexattr_t attrib;
154 verify ( !pthread_mutexattr_init( &attrib ) );
155 // allow recursive locks
156 verify ( !pthread_mutexattr_settype( &attrib, PTHREAD_MUTEX_RECURSIVE ) );
157 verify ( !pthread_mutex_init ( &_mutex, &attrib ) );
158 #else
159 # error unrecognized target
160 #endif
161 }
162
163 Mutex::~Mutex()
164 {
165 #ifdef WIN32
166 verify ( CloseHandle ( _h ) );
167 #elif defined(UNIX)
168 verify ( !pthread_mutex_destroy(&_mutex) );
169 #else
170 # error unrecognized target
171 #endif
172 }
173
174 void Mutex::Acquire()
175 {
176 #ifdef WIN32
177 DWORD dw = WaitForSingleObject ( _h, INFINITE );
178 ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
179 #elif defined(UNIX)
180 verify ( !pthread_mutex_lock(&_mutex) );
181 #else
182 # error unrecognized target
183 #endif
184 }
185
186 bool Mutex::TryAcquire()
187 {
188 #ifdef WIN32
189 DWORD dw = WaitForSingleObject ( _h, 1 );
190 ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_TIMEOUT || dw == WAIT_ABANDONED );
191 return (dw != WAIT_TIMEOUT);
192 #elif defined(UNIX)
193 int err = pthread_mutex_trylock(&_mutex);
194 ASSERT ( err == EBUSY || err == 0 );
195 return (err == 0);
196 #else
197 # error unrecognized target
198 #endif
199 }
200
201 void Mutex::Release()
202 {
203 #ifdef WIN32
204 verify ( ReleaseMutex ( _h ) );
205 #elif defined(UNIX)
206 verify ( !pthread_mutex_unlock(&_mutex) );
207 // we could allow EPERM return value too, but we are forcing user into RIIA
208 #else
209 # error unrecognized target
210 #endif
211 }
212
213 Mutex::Lock::Lock ( Mutex& m ) : _m(m)
214 {
215 _m.Acquire();
216 }
217
218 Mutex::Lock::~Lock()
219 {
220 _m.Release();
221 }
222
223 Mutex::TryLock::TryLock ( Mutex& m ) : _m(m)
224 {
225 _bLocked = _m.TryAcquire();
226 }
227
228 Mutex::TryLock::~TryLock()
229 {
230 if ( _bLocked )
231 _m.Release();
232 }
233
234 ///////////////////////////////////////////////////////////////////////////////
235 // Event
236
237 Event::Event()
238 {
239 #ifdef WIN32
240 // start in non-signaled state (red light)
241 // auto reset after every Wait
242 verify ( _handle = CreateEvent ( 0, FALSE, FALSE, 0 ) );
243 #elif defined(UNIX)
244 //verify ( !pthread_cond_init ( &_cond, NULL /* default attributes */) );
245 sem_init();
246 //verify(sem_init());
247 #else
248 # error unrecognized target
249 #endif
250 }
251
252 Event::~Event()
253 {
254 #ifdef WIN32
255 verify ( CloseHandle ( _handle ) );
256 #elif defined(UNIX)
257 //verify ( !pthread_cond_destroy ( &_cond ) );
258 sem_destroy();
259 #else
260 # error unrecognized target
261 #endif
262 }
263
264 void Event::Release() // put into signaled state
265 {
266 #ifdef WIN32
267 verify ( SetEvent ( _handle ) );
268 #elif defined(UNIX)
269 //verify ( !pthread_cond_signal ( &_cond ) );
270 verify(!sem_V());
271 #else
272 # error unrecognized target
273 #endif
274 }
275
276 void Event::Wait()
277 {
278 #ifdef WIN32
279 // Wait until event is in signaled (green) state
280 DWORD dw = WaitForSingleObject ( _handle, INFINITE );
281 ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
282 #elif defined(UNIX)
283 // According to docs: The pthread_cond_wait() and pthread_cond_timedwait()
284 // functions are used to block on a condition variable. They are called
285 // with mutex locked by the calling thread or undefined behaviour will
286 // result.
287 //Mutex::Lock lock ( _mutex );
288 //verify ( !pthread_cond_wait ( &_cond, _mutex ) );
289 verify(!sem_P());
290 #else
291 # error unrecognized target
292 #endif
293 }
294
295 #ifdef UNIX
296 void Event::sem_init()
297 {
298 sem_id = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
299 ASSERT(sem_id != -1);
300 }
301
302 int Event::sem_P()
303 {
304 struct sembuf sb;
305 sb.sem_num = 0;
306 sb.sem_op = -1;
307 sb.sem_flg = 0;
308 return semop(sem_id, &sb, 1);
309 }
310
311 int Event::sem_V()
312 {
313 struct sembuf sb;
314 sb.sem_num = 0;
315 sb.sem_op = 1;
316 sb.sem_flg = 0;
317 return semop(sem_id, &sb, 1);
318 }
319
320 void Event::sem_destroy()
321 {
322 #ifdef MACOSX
323 semun mactmp;
324 mactmp.val = 0;
325 semctl(sem_id, 0, IPC_RMID, mactmp);
326 #else
327 semctl(sem_id, 0, IPC_RMID, 0);
328 #endif
329 }
330 #endif
331