condTimedWait fixed
[public/netxms.git] / include / nms_threads.h
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** $module: nms_threads.h
20 **
21 **/
22
23 #ifndef _nms_threads_h_
24 #define _nms_threads_h_
25
26 #ifdef _WIN32
27
28 #ifndef UNDER_CE
29 # include <process.h>
30 #endif
31
32 //
33 // Related datatypes and constants
34 //
35
36 typedef HANDLE MUTEX;
37 typedef HANDLE THREAD;
38 typedef HANDLE CONDITION;
39
40 #define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
41 #define INVALID_CONDITION_HANDLE INVALID_HANDLE_VALUE
42 #define INVALID_THREAD_HANDLE (NULL)
43
44 #ifdef UNDER_CE
45 typedef DWORD THREAD_RESULT;
46 typedef DWORD THREAD_ID;
47 #else
48 typedef unsigned int THREAD_RESULT;
49 typedef unsigned int THREAD_ID;
50 #endif
51
52 #define THREAD_OK 0
53
54 #ifdef UNDER_CE
55 #define THREAD_CALL
56 #else
57 #define THREAD_CALL __stdcall
58 #endif
59
60
61 //
62 // Inline functions
63 //
64
65 inline void ThreadSleep(int iSeconds)
66 {
67 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
68 }
69
70 inline void ThreadSleepMs(DWORD dwMilliseconds)
71 {
72 Sleep(dwMilliseconds);
73 }
74
75 inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
76 {
77 HANDLE hThread;
78 THREAD_ID dwThreadId;
79
80 #ifdef UNDER_CE
81 hThread = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
82 #else
83 hThread = (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
84 #endif
85 if (hThread != NULL)
86 CloseHandle(hThread);
87 return (hThread != NULL);
88 }
89
90 inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
91 {
92 THREAD_ID dwThreadId;
93
94 #ifdef UNDER_CE
95 return CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
96 #else
97 return (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
98 #endif
99 }
100
101 inline void ThreadExit(void)
102 {
103 #ifdef UNDER_CE
104 ExitThread(0);
105 #else
106 _endthreadex(0);
107 #endif
108 }
109
110 inline void ThreadJoin(THREAD hThread)
111 {
112 if (hThread != INVALID_THREAD_HANDLE)
113 {
114 WaitForSingleObject(hThread, INFINITE);
115 CloseHandle(hThread);
116 }
117 }
118
119 inline MUTEX MutexCreate(void)
120 {
121 return CreateMutex(NULL, FALSE, NULL);
122 }
123
124 inline void MutexDestroy(MUTEX mutex)
125 {
126 CloseHandle(mutex);
127 }
128
129 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
130 {
131 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
132 }
133
134 inline void MutexUnlock(MUTEX mutex)
135 {
136 ReleaseMutex(mutex);
137 }
138
139 inline CONDITION ConditionCreate(BOOL bBroadcast)
140 {
141 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
142 }
143
144 inline void ConditionDestroy(CONDITION hCond)
145 {
146 CloseHandle(hCond);
147 }
148
149 inline void ConditionSet(CONDITION hCond)
150 {
151 PulseEvent(hCond);
152 }
153
154 inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
155 {
156 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
157 }
158
159 #else /* _WIN32 */
160
161 /****************************************************************************/
162 /* unix part */
163 /****************************************************************************/
164
165 #include <pthread.h>
166 #include <errno.h>
167 #include <sys/time.h>
168
169 //
170 // Related datatypes and constants
171 //
172
173 typedef pthread_t THREAD;
174 typedef pthread_mutex_t * MUTEX;
175 struct condition_t
176 {
177 pthread_cond_t cond;
178 pthread_mutex_t mutex;
179 BOOL broadcast;
180 };
181 typedef struct condition_t * CONDITION;
182
183 #define INVALID_MUTEX_HANDLE (NULL)
184 #define INVALID_CONDITION_HANDLE (NULL)
185 #define INVALID_THREAD_HANDLE 0
186
187 #ifndef INFINITE
188 # define INFINITE 0
189 #endif
190
191 typedef void *THREAD_RESULT;
192
193 #define THREAD_OK ((void *)0)
194 #define THREAD_CALL
195
196
197 //
198 // Inline functions
199 //
200
201 inline void ThreadSleep(int nSeconds)
202 {
203 #ifdef _NETWARE
204 sleep(nSeconds);
205 #else
206 struct timeval tv;
207
208 tv.tv_sec = nSeconds;
209 tv.tv_usec = 0;
210
211 select(1, NULL, NULL, NULL, &tv);
212 #endif
213 }
214
215 inline void ThreadSleepMs(DWORD dwMilliseconds)
216 {
217 // select is a sort of overkill
218 usleep(dwMilliseconds * 1000); // Convert to microseconds
219 }
220
221 inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
222 {
223 THREAD id;
224
225 if (pthread_create(&id, NULL, start_address, args) == 0)
226 {
227 pthread_detach(id);
228 return TRUE;
229 }
230 else
231 {
232 return FALSE;
233 }
234 }
235
236 inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
237 {
238 THREAD id;
239
240 if (pthread_create(&id, NULL, start_address, args) == 0)
241 {
242 return id;
243 }
244 else
245 {
246 return INVALID_THREAD_HANDLE;
247 }
248 }
249
250 inline void ThreadExit(void)
251 {
252 pthread_exit(NULL);
253 }
254
255 inline void ThreadJoin(THREAD hThread)
256 {
257 if (hThread != INVALID_THREAD_HANDLE)
258 pthread_join(hThread, NULL);
259 }
260
261 inline MUTEX MutexCreate(void)
262 {
263 MUTEX mutex;
264
265 mutex = (MUTEX)malloc(sizeof(pthread_mutex_t));
266 if (mutex != NULL)
267 pthread_mutex_init(mutex, NULL);
268 return mutex;
269 }
270
271 inline void MutexDestroy(MUTEX mutex)
272 {
273 if (mutex != NULL) {
274 pthread_mutex_destroy(mutex);
275 free(mutex);
276 }
277 }
278
279 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
280 {
281 int i;
282 int ret = FALSE;
283
284 if (mutex != NULL) {
285 if (dwTimeOut == INFINITE)
286 {
287 if (pthread_mutex_lock(mutex) == 0) {
288 ret = TRUE;
289 }
290 }
291 else
292 {
293 for (i = (dwTimeOut / 50) + 1; i > 0; i--) {
294 if (pthread_mutex_trylock(mutex) == 0)
295 {
296 ret = TRUE;
297 break;
298 }
299 ThreadSleepMs(50);
300 }
301 }
302 }
303 return ret;
304 }
305
306 inline void MutexUnlock(MUTEX mutex)
307 {
308 if (mutex != NULL)
309 {
310 pthread_mutex_unlock(mutex);
311 }
312 }
313
314 inline CONDITION ConditionCreate(BOOL bBroadcast)
315 {
316 CONDITION cond;
317
318 cond = (CONDITION)malloc(sizeof(struct condition_t));
319 if (cond != NULL)
320 {
321 pthread_cond_init(&cond->cond, NULL);
322 pthread_mutex_init(&cond->mutex, NULL);
323 cond->broadcast = bBroadcast;
324 }
325
326 return cond;
327 }
328
329 inline void ConditionDestroy(CONDITION cond)
330 {
331 if (cond != NULL)
332 {
333 pthread_cond_destroy(&cond->cond);
334 pthread_mutex_destroy(&cond->mutex);
335 free(cond);
336 }
337 }
338
339 inline void ConditionSet(CONDITION cond)
340 {
341 if (cond != NULL)
342 {
343 pthread_mutex_lock(&cond->mutex);
344 if (cond->broadcast)
345 {
346 pthread_cond_broadcast(&cond->cond);
347 }
348 else
349 {
350 pthread_cond_signal(&cond->cond);
351 }
352 pthread_mutex_unlock(&cond->mutex);
353 }
354 }
355
356 inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
357 {
358 BOOL ret = FALSE;
359
360 if (cond != NULL)
361 {
362 int retcode;
363
364 pthread_mutex_lock(&cond->mutex);
365
366 if (dwTimeOut != INFINITE)
367 {
368 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
369 struct timespec timeout;
370
371 timeout.tv_sec = dwTimeOut / 1000;
372 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
373 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
374 #else
375 struct timeval now;
376 struct timespec timeout;
377
378 // FIXME there should be more accurate way
379 gettimeofday(&now, NULL);
380 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
381
382 timeout.tv_nsec = now.tv_usec * 1000;
383 timeout.tv_nsec += (dwTimeOut % 1000) * 1000;
384 if (timeout.tv_nsec >= 6000000)
385 {
386 timeout.tv_sec += timeout.tv_nsec / 6000000;
387 timeout.tv_nsec = timeout.tv_nsec % 6000000;
388 }
389 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
390 #endif
391 }
392 else
393 {
394 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
395 }
396
397 pthread_mutex_unlock(&cond->mutex);
398
399 if (retcode == 0)
400 {
401 ret = TRUE;
402 }
403 }
404
405 return ret;
406 }
407
408 #endif /* _WIN32 */
409
410 #endif /* _nms_threads_h_ */