Preparation for libpth support
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
54481027
VK
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
b71bff93
VK
26#ifdef __cplusplus
27
28#define NMS_THREADS_H_INCLUDED
29
9b2bfc05 30#if defined(_WIN32)
54481027 31
018fda4d 32#ifndef UNDER_CE
df7156b3 33#include <process.h>
018fda4d 34#endif
54481027
VK
35
36//
37// Related datatypes and constants
38//
39
dbe67493
VK
40typedef HANDLE MUTEX;
41typedef HANDLE THREAD;
42typedef HANDLE CONDITION;
54481027 43
449e3da9
VK
44#define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
45#define INVALID_CONDITION_HANDLE INVALID_HANDLE_VALUE
ccdbbb52
VK
46#define INVALID_THREAD_HANDLE (NULL)
47
288ddda4
VK
48#ifdef UNDER_CE
49typedef DWORD THREAD_RESULT;
50typedef DWORD THREAD_ID;
51#else
ccdbbb52 52typedef unsigned int THREAD_RESULT;
288ddda4
VK
53typedef unsigned int THREAD_ID;
54#endif
ccdbbb52
VK
55
56#define THREAD_OK 0
288ddda4
VK
57
58#ifdef UNDER_CE
59#define THREAD_CALL
60#else
ccdbbb52 61#define THREAD_CALL __stdcall
288ddda4 62#endif
54481027
VK
63
64
65//
66// Inline functions
67//
68
69inline void ThreadSleep(int iSeconds)
70{
71 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
72}
73
74inline void ThreadSleepMs(DWORD dwMilliseconds)
75{
76 Sleep(dwMilliseconds);
77}
78
ccdbbb52 79inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
54481027 80{
ccdbbb52 81 HANDLE hThread;
288ddda4 82 THREAD_ID dwThreadId;
ccdbbb52 83
f2fdf1b5 84#ifdef UNDER_CE
288ddda4 85 hThread = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
f2fdf1b5 86#else
ccdbbb52 87 hThread = (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
f2fdf1b5 88#endif
ccdbbb52
VK
89 if (hThread != NULL)
90 CloseHandle(hThread);
91 return (hThread != NULL);
92}
93
94inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
95{
288ddda4 96 THREAD_ID dwThreadId;
ccdbbb52 97
288ddda4
VK
98#ifdef UNDER_CE
99 return CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
631ec742 100#else
288ddda4 101 return (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
631ec742 102#endif
54481027
VK
103}
104
105inline void ThreadExit(void)
106{
f2fdf1b5 107#ifdef UNDER_CE
018fda4d 108 ExitThread(0);
f2fdf1b5
VK
109#else
110 _endthreadex(0);
018fda4d 111#endif
54481027
VK
112}
113
ccdbbb52
VK
114inline void ThreadJoin(THREAD hThread)
115{
116 if (hThread != INVALID_THREAD_HANDLE)
117 {
118 WaitForSingleObject(hThread, INFINITE);
119 CloseHandle(hThread);
120 }
121}
122
54481027
VK
123inline MUTEX MutexCreate(void)
124{
125 return CreateMutex(NULL, FALSE, NULL);
126}
127
a3c76aba
VK
128inline MUTEX MutexCreateRecursive(void)
129{
130 return CreateMutex(NULL, FALSE, NULL);
131}
132
54481027
VK
133inline void MutexDestroy(MUTEX mutex)
134{
135 CloseHandle(mutex);
136}
137
138inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
139{
140 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
141}
142
143inline void MutexUnlock(MUTEX mutex)
144{
145 ReleaseMutex(mutex);
146}
147
d16cf8a5 148inline CONDITION ConditionCreate(BOOL bBroadcast)
54481027 149{
646d58de 150 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
54481027
VK
151}
152
153inline void ConditionDestroy(CONDITION hCond)
154{
155 CloseHandle(hCond);
156}
157
158inline void ConditionSet(CONDITION hCond)
159{
5f743326
VK
160 SetEvent(hCond);
161}
162
163inline void ConditionReset(CONDITION hCond)
164{
165 ResetEvent(hCond);
166}
167
168inline void ConditionPulse(CONDITION hCond)
169{
39d7a7ed 170 PulseEvent(hCond);
54481027
VK
171}
172
c7f4f5a9 173inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
54481027 174{
c7f4f5a9 175 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
54481027
VK
176}
177
9b2bfc05
VK
178#elif defined(_USE_GNU_PTH)
179
180/****************************************************************************/
181/* GNU Pth */
182/****************************************************************************/
183
54481027
VK
184#else /* _WIN32 */
185
d16cf8a5 186/****************************************************************************/
9b2bfc05 187/* pthreads */
d16cf8a5
AK
188/****************************************************************************/
189
54481027 190#include <pthread.h>
d16cf8a5
AK
191#include <errno.h>
192#include <sys/time.h>
54481027 193
9b2bfc05 194#if HAVE_PTHREAD_NP_H && !defined(_IPSO)
6cd41ceb
VK
195#include <pthread_np.h>
196#endif
197
a0537937 198#if (HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) && \
6cd41ceb
VK
199 (HAVE_DECL_PTHREAD_MUTEX_RECURSIVE || \
200 HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP || \
201 HAVE_DECL_MUTEX_TYPE_COUNTING_FAST)
a0537937
VK
202
203#define HAVE_RECURSIVE_MUTEXES 1
204
205#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
206#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE
6cd41ceb 207#elif HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP
a0537937 208#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE_NP
6cd41ceb
VK
209#elif HAVE_DECL_MUTEX_TYPE_COUNTING_FAST
210#define MUTEX_RECURSIVE_FLAG MUTEX_TYPE_COUNTING_FAST
211#else
212#error Constant used to declare recursive mutex is not known
a0537937
VK
213#endif
214
215#if HAVE_PTHREAD_MUTEXATTR_SETTYPE
216#define MUTEXATTR_SETTYPE pthread_mutexattr_settype
217#else
218#define MUTEXATTR_SETTYPE pthread_mutexattr_setkind_np
219#endif
220
221#endif
222
54481027
VK
223//
224// Related datatypes and constants
225//
226
7e679c4b 227typedef pthread_t THREAD;
a3c76aba
VK
228struct netxms_mutex_t
229{
230 pthread_mutex_t mutex;
231#ifndef HAVE_RECURSIVE_MUTEXES
232 BOOL isRecursive;
233 pthread_t owner;
234#endif
235};
236typedef netxms_mutex_t * MUTEX;
237struct netxms_condition_t
d16cf8a5
AK
238{
239 pthread_cond_t cond;
240 pthread_mutex_t mutex;
241 BOOL broadcast;
5f743326 242 BOOL isSet;
d16cf8a5 243};
a3c76aba 244typedef struct netxms_condition_t * CONDITION;
54481027 245
449e3da9
VK
246#define INVALID_MUTEX_HANDLE (NULL)
247#define INVALID_CONDITION_HANDLE (NULL)
ccdbbb52 248#define INVALID_THREAD_HANDLE 0
54481027 249
7e679c4b
AK
250#ifndef INFINITE
251# define INFINITE 0
252#endif
54481027 253
ccdbbb52
VK
254typedef void *THREAD_RESULT;
255
256#define THREAD_OK ((void *)0)
257#define THREAD_CALL
258
259
54481027
VK
260//
261// Inline functions
262//
263
d16cf8a5 264inline void ThreadSleep(int nSeconds)
54481027 265{
22412a01
VK
266#ifdef _NETWARE
267 sleep(nSeconds);
268#else
d16cf8a5
AK
269 struct timeval tv;
270
271 tv.tv_sec = nSeconds;
272 tv.tv_usec = 0;
273
274 select(1, NULL, NULL, NULL, &tv);
22412a01 275#endif
54481027
VK
276}
277
278inline void ThreadSleepMs(DWORD dwMilliseconds)
279{
642bb2d8
VK
280#if HAVE_NANOSLEEP
281 struct timespec interval, remainder;
282
283 interval.tv_sec = dwMilliseconds / 1000;
284 interval.tv_nsec = (dwMilliseconds % 1000) * 1000000; // milli -> nano
285 nanosleep(&interval, &remainder);
286#else
287 usleep(dwMilliseconds * 1000); // Convert to microseconds
288#endif
54481027
VK
289}
290
ccdbbb52 291inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
7e679c4b
AK
292{
293 THREAD id;
294
ccdbbb52 295 if (pthread_create(&id, NULL, start_address, args) == 0)
d1fbf6ba
VK
296 {
297 pthread_detach(id);
ccdbbb52
VK
298 return TRUE;
299 }
300 else
301 {
302 return FALSE;
303 }
304}
305
306inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
307{
35a3a09e 308 THREAD id;
ccdbbb52 309
35a3a09e 310 if (pthread_create(&id, NULL, start_address, args) == 0)
ccdbbb52 311 {
35a3a09e
VK
312 return id;
313 }
d1fbf6ba
VK
314 else
315 {
35a3a09e
VK
316 return INVALID_THREAD_HANDLE;
317 }
7e679c4b
AK
318}
319
320inline void ThreadExit(void)
321{
521d90e7 322 pthread_exit(NULL);
7e679c4b
AK
323}
324
ccdbbb52
VK
325inline void ThreadJoin(THREAD hThread)
326{
327 if (hThread != INVALID_THREAD_HANDLE)
35a3a09e 328 pthread_join(hThread, NULL);
ccdbbb52
VK
329}
330
54481027
VK
331inline MUTEX MutexCreate(void)
332{
333 MUTEX mutex;
334
a3c76aba 335 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
54481027 336 if (mutex != NULL)
8118ecaf 337 pthread_mutex_init(&mutex->mutex, NULL);
a3c76aba
VK
338 return mutex;
339}
340
341inline MUTEX MutexCreateRecursive(void)
342{
343 MUTEX mutex;
344
345 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
346 if (mutex != NULL)
347 {
348#ifdef HAVE_RECURSIVE_MUTEXES
349 pthread_mutexattr_t a;
350
351 pthread_mutexattr_init(&a);
a0537937 352 MUTEXATTR_SETTYPE(&a, MUTEX_RECURSIVE_FLAG);
a3c76aba
VK
353 pthread_mutex_init(&mutex->mutex, &a);
354 pthread_mutexattr_destroy(&a);
355#else
356#error FIXME: implement recursive mutexes
357#endif
358 }
54481027
VK
359 return mutex;
360}
361
362inline void MutexDestroy(MUTEX mutex)
363{
a3c76aba
VK
364 if (mutex != NULL)
365 {
366 pthread_mutex_destroy(&mutex->mutex);
54481027
VK
367 free(mutex);
368 }
369}
370
53c17a96 371inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
54481027 372{
d16cf8a5
AK
373 int i;
374 int ret = FALSE;
375
a3c76aba
VK
376 if (mutex != NULL)
377 {
951e884e
AK
378 if (dwTimeOut == INFINITE)
379 {
a3c76aba
VK
380 if (pthread_mutex_lock(&mutex->mutex) == 0)
381 {
d16cf8a5 382 ret = TRUE;
d16cf8a5 383 }
951e884e
AK
384 }
385 else
386 {
a3c76aba
VK
387 for (i = (dwTimeOut / 50) + 1; i > 0; i--)
388 {
389 if (pthread_mutex_trylock(&mutex->mutex) == 0)
8a435919 390 {
951e884e
AK
391 ret = TRUE;
392 break;
393 }
02ed4cf1 394 ThreadSleepMs(50);
951e884e 395 }
d16cf8a5 396 }
7e679c4b 397 }
d16cf8a5 398 return ret;
54481027
VK
399}
400
401inline void MutexUnlock(MUTEX mutex)
402{
8a435919
VK
403 if (mutex != NULL)
404 {
a3c76aba 405 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
406 }
407}
408
d16cf8a5 409inline CONDITION ConditionCreate(BOOL bBroadcast)
7e679c4b
AK
410{
411 CONDITION cond;
412
a3c76aba 413 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
414 if (cond != NULL)
415 {
d16cf8a5
AK
416 pthread_cond_init(&cond->cond, NULL);
417 pthread_mutex_init(&cond->mutex, NULL);
418 cond->broadcast = bBroadcast;
5f743326 419 cond->isSet = FALSE;
7e679c4b 420 }
d16cf8a5 421
7e679c4b
AK
422 return cond;
423}
424
d16cf8a5 425inline void ConditionDestroy(CONDITION cond)
7e679c4b 426{
5f743326 427 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
428 {
429 pthread_cond_destroy(&cond->cond);
430 pthread_mutex_destroy(&cond->mutex);
431 free(cond);
7e679c4b
AK
432 }
433}
434
d16cf8a5 435inline void ConditionSet(CONDITION cond)
7e679c4b 436{
5f743326 437 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
438 {
439 pthread_mutex_lock(&cond->mutex);
5f743326 440 cond->isSet = TRUE;
02ed4cf1 441 if (cond->broadcast)
d16cf8a5
AK
442 {
443 pthread_cond_broadcast(&cond->cond);
444 }
445 else
446 {
447 pthread_cond_signal(&cond->cond);
448 }
449 pthread_mutex_unlock(&cond->mutex);
450 }
7e679c4b
AK
451}
452
5f743326
VK
453inline void ConditionReset(CONDITION cond)
454{
455 if (cond != INVALID_CONDITION_HANDLE)
456 {
457 pthread_mutex_lock(&cond->mutex);
458 cond->isSet = FALSE;
459 pthread_mutex_unlock(&cond->mutex);
460 }
461}
462
463inline void ConditionPulse(CONDITION cond)
464{
465 if (cond != INVALID_CONDITION_HANDLE)
466 {
467 pthread_mutex_lock(&cond->mutex);
468 if (cond->broadcast)
469 {
470 pthread_cond_broadcast(&cond->cond);
471 }
472 else
473 {
474 pthread_cond_signal(&cond->cond);
475 }
476 cond->isSet = FALSE;
477 pthread_mutex_unlock(&cond->mutex);
478 }
479}
480
d16cf8a5 481inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
7e679c4b 482{
d16cf8a5
AK
483 BOOL ret = FALSE;
484
485 if (cond != NULL)
486 {
487 int retcode;
488
489 pthread_mutex_lock(&cond->mutex);
5f743326
VK
490 if (cond->isSet)
491 {
492 ret = TRUE;
493 if (!cond->broadcast)
494 cond->isSet = FALSE;
495 }
496 else
497 {
498 if (dwTimeOut != INFINITE)
499 {
58e7e86f 500#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 501 struct timespec timeout;
696fc54f 502
5f743326
VK
503 timeout.tv_sec = dwTimeOut / 1000;
504 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
505#ifdef _NETWARE
506 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
507#else
5f743326 508 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 509#endif
696fc54f 510#else
5f743326
VK
511 struct timeval now;
512 struct timespec timeout;
d16cf8a5 513
5f743326
VK
514 // note.
515 // mili - 10^-3
516 // micro - 10^-6
517 // nano - 10^-9
ed452de5 518
5f743326
VK
519 // FIXME there should be more accurate way
520 gettimeofday(&now, NULL);
521 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 522
5f743326
VK
523 now.tv_usec += (dwTimeOut % 1000) * 1000;
524 timeout.tv_sec += now.tv_usec / 1000000;
525 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 526
5f743326 527 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 528#endif
5f743326
VK
529 }
530 else
531 {
532 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
533 }
534
535 if (retcode == 0)
536 {
633907a4
VK
537 if (!cond->broadcast)
538 cond->isSet = FALSE;
5f743326
VK
539 ret = TRUE;
540 }
541 }
7e679c4b 542
d16cf8a5 543 pthread_mutex_unlock(&cond->mutex);
7e679c4b 544 }
d16cf8a5
AK
545
546 return ret;
54481027
VK
547}
548
bff234b8
VK
549inline DWORD GetCurrentProcessId(void)
550{
551 return getpid();
552}
553
d8250de7 554inline THREAD GetCurrentThreadId(void)
5e3c403d 555{
05f0165e 556 return pthread_self();
5e3c403d
VK
557}
558
54481027
VK
559#endif /* _WIN32 */
560
df7156b3
VK
561#include <rwlock.h>
562
b71bff93
VK
563#endif /* __cplusplus */
564
54481027 565#endif /* _nms_threads_h_ */