preparation for 1.1.6 release
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
68f384ea 3** Copyright (C) 2003-2010 Victor Kirhenshtein
54481027
VK
4**
5** This program is free software; you can redistribute it and/or modify
68f384ea
VK
6** it under the terms of the GNU Lesser General Public License as published
7** by the Free Software Foundation; either version 3 of the License, or
54481027
VK
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**
68f384ea 15** You should have received a copy of the GNU Lesser General Public License
54481027
VK
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
5405ce0b 19** File: nms_threads.h
54481027
VK
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
449e3da9
VK
40#define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
41#define INVALID_CONDITION_HANDLE INVALID_HANDLE_VALUE
ccdbbb52
VK
42#define INVALID_THREAD_HANDLE (NULL)
43
288ddda4
VK
44#ifdef UNDER_CE
45typedef DWORD THREAD_RESULT;
46typedef DWORD THREAD_ID;
47#else
ccdbbb52 48typedef unsigned int THREAD_RESULT;
288ddda4
VK
49typedef unsigned int THREAD_ID;
50#endif
ccdbbb52
VK
51
52#define THREAD_OK 0
288ddda4
VK
53
54#ifdef UNDER_CE
55#define THREAD_CALL
56#else
ccdbbb52 57#define THREAD_CALL __stdcall
ba2c1467 58
5405ce0b
VK
59typedef HANDLE MUTEX;
60typedef HANDLE CONDITION;
61struct netxms_thread_t
62{
63 HANDLE handle;
64 THREAD_ID id;
65};
66typedef struct netxms_thread_t *THREAD;
67
ba2c1467
VK
68typedef struct
69{
70 THREAD_RESULT (THREAD_CALL *start_address)(void *);
71 void *args;
72} THREAD_START_DATA;
73
74THREAD_RESULT LIBNETXMS_EXPORTABLE THREAD_CALL SEHThreadStarter(void *);
7a7ba846 75int LIBNETXMS_EXPORTABLE ___ExceptionHandler(EXCEPTION_POINTERS *pInfo);
ba2c1467 76
bb7a686c 77void LIBNETXMS_EXPORTABLE SetExceptionHandler(BOOL (*pfHandler)(EXCEPTION_POINTERS *),
ccc34207 78 void (*pfWriter)(const TCHAR *), const TCHAR *pszDumpDir,
cbc777ee
VK
79 const TCHAR *pszBaseProcessName, DWORD dwLogMsgCode,
80 BOOL writeFullDump, BOOL printToScreen);
bb7a686c 81BOOL LIBNETXMS_EXPORTABLE SEHDefaultConsoleHandler(EXCEPTION_POINTERS *pInfo);
ba2c1467
VK
82TCHAR LIBNETXMS_EXPORTABLE *SEHExceptionName(DWORD code);
83void LIBNETXMS_EXPORTABLE SEHShowCallStack(CONTEXT *pCtx);
84
ccc34207
VK
85void LIBNETXMS_EXPORTABLE SEHServiceExceptionDataWriter(const TCHAR *pszText);
86BOOL LIBNETXMS_EXPORTABLE SEHServiceExceptionHandler(EXCEPTION_POINTERS *pInfo);
87
7a7ba846
VK
88#define LIBNETXMS_EXCEPTION_HANDLER \
89 } __except(___ExceptionHandler((EXCEPTION_POINTERS *)_exception_info())) { ExitProcess(99); }
90
288ddda4 91#endif
54481027
VK
92
93
94//
95// Inline functions
96//
97
dc5bad96
VK
98inline void InitThreadLibrary(void)
99{
100}
101
54481027
VK
102inline void ThreadSleep(int iSeconds)
103{
104 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
105}
106
107inline void ThreadSleepMs(DWORD dwMilliseconds)
108{
109 Sleep(dwMilliseconds);
110}
111
ba2c1467 112inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address)(void *), int stack_size, void *args)
54481027 113{
ccdbbb52 114 HANDLE hThread;
288ddda4 115 THREAD_ID dwThreadId;
ccdbbb52 116
f2fdf1b5 117#ifdef UNDER_CE
288ddda4 118 hThread = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
f2fdf1b5 119#else
ba2c1467
VK
120 THREAD_START_DATA *data = (THREAD_START_DATA *)malloc(sizeof(THREAD_START_DATA));
121 data->start_address = start_address;
122 data->args = args;
123 hThread = (HANDLE)_beginthreadex(NULL, stack_size, SEHThreadStarter, data, 0, &dwThreadId);
f2fdf1b5 124#endif
ccdbbb52
VK
125 if (hThread != NULL)
126 CloseHandle(hThread);
127 return (hThread != NULL);
128}
129
ba2c1467 130inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address)(void *), int stack_size, void *args)
ccdbbb52 131{
5405ce0b 132 THREAD thread;
ccdbbb52 133
5405ce0b 134 thread = (THREAD)malloc(sizeof(struct netxms_thread_t));
288ddda4 135#ifdef UNDER_CE
5405ce0b
VK
136 thread->handle = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &thread->id);
137 if (thread->handle == NULL)
138 {
631ec742 139#else
ba2c1467
VK
140 THREAD_START_DATA *data = (THREAD_START_DATA *)malloc(sizeof(THREAD_START_DATA));
141 data->start_address = start_address;
142 data->args = args;
5405ce0b
VK
143 thread->handle = (HANDLE)_beginthreadex(NULL, stack_size, SEHThreadStarter, data, 0, &thread->id);
144 if ((thread->handle == (HANDLE)-1) || (thread->handle == 0))
145 {
146 free(data);
631ec742 147#endif
5405ce0b
VK
148 free(thread);
149 thread = INVALID_THREAD_HANDLE;
150 }
151 return thread;
54481027
VK
152}
153
154inline void ThreadExit(void)
155{
f2fdf1b5 156#ifdef UNDER_CE
018fda4d 157 ExitThread(0);
f2fdf1b5
VK
158#else
159 _endthreadex(0);
018fda4d 160#endif
54481027
VK
161}
162
5405ce0b 163inline void ThreadJoin(THREAD thread)
ccdbbb52 164{
5405ce0b 165 if (thread != INVALID_THREAD_HANDLE)
ccdbbb52 166 {
5405ce0b
VK
167 WaitForSingleObject(thread->handle, INFINITE);
168 CloseHandle(thread->handle);
169 free(thread);
ccdbbb52
VK
170 }
171}
172
5405ce0b
VK
173inline THREAD_ID ThreadId(THREAD thread)
174{
175 return (thread != INVALID_THREAD_HANDLE) ? thread->id : 0;
176}
177
54481027
VK
178inline MUTEX MutexCreate(void)
179{
180 return CreateMutex(NULL, FALSE, NULL);
181}
182
a3c76aba
VK
183inline MUTEX MutexCreateRecursive(void)
184{
185 return CreateMutex(NULL, FALSE, NULL);
186}
187
54481027
VK
188inline void MutexDestroy(MUTEX mutex)
189{
190 CloseHandle(mutex);
191}
192
193inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
194{
d113a890
VK
195 if (mutex == INVALID_MUTEX_HANDLE)
196 return FALSE;
54481027
VK
197 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
198}
199
200inline void MutexUnlock(MUTEX mutex)
201{
202 ReleaseMutex(mutex);
203}
204
d16cf8a5 205inline CONDITION ConditionCreate(BOOL bBroadcast)
54481027 206{
646d58de 207 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
54481027
VK
208}
209
210inline void ConditionDestroy(CONDITION hCond)
211{
212 CloseHandle(hCond);
213}
214
215inline void ConditionSet(CONDITION hCond)
216{
5f743326
VK
217 SetEvent(hCond);
218}
219
220inline void ConditionReset(CONDITION hCond)
221{
222 ResetEvent(hCond);
223}
224
225inline void ConditionPulse(CONDITION hCond)
226{
39d7a7ed 227 PulseEvent(hCond);
54481027
VK
228}
229
c7f4f5a9 230inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
54481027 231{
d113a890
VK
232 if (hCond == INVALID_CONDITION_HANDLE)
233 return FALSE;
c7f4f5a9 234 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
54481027
VK
235}
236
9b2bfc05
VK
237#elif defined(_USE_GNU_PTH)
238
239/****************************************************************************/
240/* GNU Pth */
241/****************************************************************************/
242
60414f77
VK
243//
244// Related datatypes and constants
245//
246
247typedef pth_t THREAD;
248typedef pth_mutex_t * MUTEX;
249struct netxms_condition_t
250{
251 pth_cond_t cond;
252 pth_mutex_t mutex;
253 BOOL broadcast;
254 BOOL isSet;
255};
256typedef struct netxms_condition_t * CONDITION;
257
258#define INVALID_MUTEX_HANDLE (NULL)
259#define INVALID_CONDITION_HANDLE (NULL)
260#define INVALID_THREAD_HANDLE (NULL)
261
262#ifndef INFINITE
9c8cf170 263#define INFINITE 0xFFFFFFFF
60414f77
VK
264#endif
265
266typedef void *THREAD_RESULT;
267
268#define THREAD_OK ((void *)0)
269#define THREAD_CALL
270
271
272//
273// Inline functions
274//
275
dc5bad96
VK
276inline void InitThreadLibrary(void)
277{
278 if (!pth_init())
279 {
280 perror("pth_init() failed");
281 exit(200);
282 }
283}
284
60414f77
VK
285inline void ThreadSleep(int nSeconds)
286{
287 pth_sleep(nSeconds);
288}
289
290inline void ThreadSleepMs(DWORD dwMilliseconds)
291{
cd4c8ca3 292 pth_usleep(dwMilliseconds * 1000);
60414f77
VK
293}
294
295inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
296{
297 THREAD id;
298
299 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
300 {
301 pth_attr_set(pth_attr_of(id), PTH_ATTR_JOINABLE, 0);
302 return TRUE;
303 }
304 else
305 {
306 return FALSE;
307 }
308}
309
310inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
311{
312 THREAD id;
313
314 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
315 {
cd4c8ca3 316 return id;
60414f77
VK
317 }
318 else
319 {
cd4c8ca3 320 return INVALID_THREAD_HANDLE;
60414f77
VK
321 }
322}
323
324inline void ThreadExit(void)
325{
326 pth_exit(NULL);
327}
328
329inline void ThreadJoin(THREAD hThread)
330{
331 if (hThread != INVALID_THREAD_HANDLE)
332 pth_join(hThread, NULL);
333}
334
335inline MUTEX MutexCreate(void)
336{
337 MUTEX mutex;
338
339 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
340 if (mutex != NULL)
dc5bad96 341 {
60414f77 342 pth_mutex_init(mutex);
dc5bad96 343 }
60414f77
VK
344 return mutex;
345}
346
347inline MUTEX MutexCreateRecursive(void)
348{
349 MUTEX mutex;
350
351 // In libpth, recursive locking is explicitly supported,
352 // so we just create mutex
353 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
354 if (mutex != NULL)
dc5bad96 355 {
60414f77 356 pth_mutex_init(mutex);
dc5bad96 357 }
60414f77
VK
358 return mutex;
359}
360
361inline void MutexDestroy(MUTEX mutex)
362{
363 if (mutex != NULL)
364 free(mutex);
365}
366
367inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
368{
369 int i;
370 int ret = FALSE;
371
372 if (mutex != NULL)
373 {
374 if (dwTimeOut == INFINITE)
375 {
376 if (pth_mutex_acquire(mutex, FALSE, NULL))
377 {
378 ret = TRUE;
379 }
380 }
381 else
382 {
383 pth_event_t ev;
384
385 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
386 if (pth_mutex_acquire(mutex, FALSE, ev))
387 {
388 ret = TRUE;
389 }
390 pth_event_free(ev, PTH_FREE_ALL);
391 }
392 }
393 return ret;
394}
395
396inline void MutexUnlock(MUTEX mutex)
397{
398 if (mutex != NULL)
399 {
400 pth_mutex_release(mutex);
401 }
402}
403
404inline CONDITION ConditionCreate(BOOL bBroadcast)
405{
406 CONDITION cond;
407
cd4c8ca3
VK
408 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
409 if (cond != NULL)
410 {
411 pth_cond_init(&cond->cond);
412 pth_mutex_init(&cond->mutex);
60414f77 413 cond->broadcast = bBroadcast;
cd4c8ca3 414 cond->isSet = FALSE;
60414f77
VK
415 }
416
cd4c8ca3 417 return cond;
60414f77
VK
418}
419
420inline void ConditionDestroy(CONDITION cond)
421{
422 if (cond != INVALID_CONDITION_HANDLE)
423 {
424 free(cond);
425 }
426}
427
428inline void ConditionSet(CONDITION cond)
429{
430 if (cond != INVALID_CONDITION_HANDLE)
431 {
432 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
433 cond->isSet = TRUE;
434 pth_cond_notify(&cond->cond, cond->broadcast);
435 pth_mutex_release(&cond->mutex);
436 }
437}
438
439inline void ConditionReset(CONDITION cond)
440{
441 if (cond != INVALID_CONDITION_HANDLE)
442 {
443 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
444 cond->isSet = FALSE;
445 pth_mutex_release(&cond->mutex);
446 }
447}
448
449inline void ConditionPulse(CONDITION cond)
450{
451 if (cond != INVALID_CONDITION_HANDLE)
452 {
453 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
454 pth_cond_notify(&cond->cond, cond->broadcast);
455 cond->isSet = FALSE;
456 pth_mutex_release(&cond->mutex);
457 }
458}
459
460inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
461{
462 BOOL ret = FALSE;
463
464 if (cond != NULL)
465 {
466 int retcode;
467
468 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
469 if (cond->isSet)
470 {
471 ret = TRUE;
472 if (!cond->broadcast)
473 cond->isSet = FALSE;
474 }
475 else
476 {
477 if (dwTimeOut != INFINITE)
478 {
479 pth_event_t ev;
480
481 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
cd4c8ca3 482 retcode = pth_cond_await(&cond->cond, &cond->mutex, ev);
60414f77
VK
483 pth_event_free(ev, PTH_FREE_ALL);
484 }
485 else
486 {
487 retcode = pth_cond_await(&cond->cond, &cond->mutex, NULL);
488 }
489
490 if (retcode)
491 {
492 if (!cond->broadcast)
493 cond->isSet = FALSE;
494 ret = TRUE;
495 }
496 }
497
498 pth_mutex_release(&cond->mutex);
499 }
500
501 return ret;
502}
503
504inline DWORD GetCurrentProcessId(void)
505{
506 return getpid();
507}
508
509inline THREAD GetCurrentThreadId(void)
510{
511 return pth_self();
512}
513
514#else /* not _WIN32 && not _USE_GNU_PTH */
54481027 515
d16cf8a5 516/****************************************************************************/
9b2bfc05 517/* pthreads */
d16cf8a5
AK
518/****************************************************************************/
519
54481027 520#include <pthread.h>
d16cf8a5
AK
521#include <errno.h>
522#include <sys/time.h>
54481027 523
9b2bfc05 524#if HAVE_PTHREAD_NP_H && !defined(_IPSO)
6cd41ceb
VK
525#include <pthread_np.h>
526#endif
527
39086394
VK
528#if (HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE___PTHREAD_MUTEXATTR_SETTYPE || HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) && \
529 HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE && \
530 (HAVE_DECL_PTHREAD_MUTEX_RECURSIVE || \
6cd41ceb
VK
531 HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP || \
532 HAVE_DECL_MUTEX_TYPE_COUNTING_FAST)
a0537937
VK
533
534#define HAVE_RECURSIVE_MUTEXES 1
535
536#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
537#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE
6cd41ceb 538#elif HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP
a0537937 539#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE_NP
6cd41ceb
VK
540#elif HAVE_DECL_MUTEX_TYPE_COUNTING_FAST
541#define MUTEX_RECURSIVE_FLAG MUTEX_TYPE_COUNTING_FAST
542#else
543#error Constant used to declare recursive mutex is not known
a0537937
VK
544#endif
545
39086394 546#if HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE
a0537937 547#define MUTEXATTR_SETTYPE pthread_mutexattr_settype
39086394
VK
548#elif HAVE___PTHREAD_MUTEXATTR_SETTYPE
549#define MUTEXATTR_SETTYPE __pthread_mutexattr_settype
a0537937
VK
550#else
551#define MUTEXATTR_SETTYPE pthread_mutexattr_setkind_np
552#endif
553
554#endif
555
54481027
VK
556//
557// Related datatypes and constants
558//
559
7e679c4b 560typedef pthread_t THREAD;
a3c76aba
VK
561struct netxms_mutex_t
562{
563 pthread_mutex_t mutex;
564#ifndef HAVE_RECURSIVE_MUTEXES
565 BOOL isRecursive;
566 pthread_t owner;
567#endif
568};
569typedef netxms_mutex_t * MUTEX;
570struct netxms_condition_t
d16cf8a5
AK
571{
572 pthread_cond_t cond;
573 pthread_mutex_t mutex;
574 BOOL broadcast;
5f743326 575 BOOL isSet;
d16cf8a5 576};
a3c76aba 577typedef struct netxms_condition_t * CONDITION;
54481027 578
449e3da9
VK
579#define INVALID_MUTEX_HANDLE (NULL)
580#define INVALID_CONDITION_HANDLE (NULL)
ccdbbb52 581#define INVALID_THREAD_HANDLE 0
54481027 582
7e679c4b 583#ifndef INFINITE
9c8cf170 584#define INFINITE 0xFFFFFFFF
7e679c4b 585#endif
54481027 586
ccdbbb52
VK
587typedef void *THREAD_RESULT;
588
589#define THREAD_OK ((void *)0)
590#define THREAD_CALL
591
592
54481027
VK
593//
594// Inline functions
595//
596
dc5bad96
VK
597inline void InitThreadLibrary(void)
598{
599}
600
d16cf8a5 601inline void ThreadSleep(int nSeconds)
54481027 602{
22412a01
VK
603#ifdef _NETWARE
604 sleep(nSeconds);
605#else
d16cf8a5
AK
606 struct timeval tv;
607
608 tv.tv_sec = nSeconds;
609 tv.tv_usec = 0;
610
611 select(1, NULL, NULL, NULL, &tv);
22412a01 612#endif
54481027
VK
613}
614
615inline void ThreadSleepMs(DWORD dwMilliseconds)
616{
ccc34207 617#if HAVE_NANOSLEEP && HAVE_DECL_NANOSLEEP
642bb2d8
VK
618 struct timespec interval, remainder;
619
620 interval.tv_sec = dwMilliseconds / 1000;
621 interval.tv_nsec = (dwMilliseconds % 1000) * 1000000; // milli -> nano
622 nanosleep(&interval, &remainder);
623#else
624 usleep(dwMilliseconds * 1000); // Convert to microseconds
625#endif
54481027
VK
626}
627
f7b2df08 628inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
7e679c4b 629{
f7b2df08 630 THREAD id;
7e679c4b 631
f7b2df08
AK
632 if (stack_size <= 0)
633 {
634 // TODO: Find out minimal stack size
635 stack_size = 1024 * 1024; // 1MB
636 // set stack size to 1mb (it's windows default - and application works,
637 // we need to investigate more on this)
ccdbbb52 638 }
f7b2df08
AK
639 pthread_attr_t attr;
640 pthread_attr_init(&attr);
641 pthread_attr_setstacksize(&attr, stack_size);
642
643 if (pthread_create(&id, &attr, start_address, args) != 0)
644 {
645 id = INVALID_THREAD_HANDLE;
646 }
647
ab51c4d0
VK
648 pthread_attr_destroy(&attr);
649
f7b2df08 650 return id;
ccdbbb52
VK
651}
652
f7b2df08 653inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
ccdbbb52 654{
f7b2df08 655 THREAD id = ThreadCreateEx(start_address, stack_size, args);
ccdbbb52 656
f7b2df08
AK
657 if (id != INVALID_THREAD_HANDLE)
658 {
659 pthread_detach(id);
660 return TRUE;
661 }
662
663 return FALSE;
7e679c4b
AK
664}
665
666inline void ThreadExit(void)
667{
521d90e7 668 pthread_exit(NULL);
7e679c4b
AK
669}
670
ccdbbb52
VK
671inline void ThreadJoin(THREAD hThread)
672{
673 if (hThread != INVALID_THREAD_HANDLE)
35a3a09e 674 pthread_join(hThread, NULL);
ccdbbb52
VK
675}
676
54481027
VK
677inline MUTEX MutexCreate(void)
678{
679 MUTEX mutex;
680
a3c76aba 681 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
54481027 682 if (mutex != NULL)
9c8cf170 683 {
8118ecaf 684 pthread_mutex_init(&mutex->mutex, NULL);
9c8cf170
VK
685#ifndef HAVE_RECURSIVE_MUTEXES
686 mutex->isRecursive = FALSE;
687#endif
688 }
a3c76aba
VK
689 return mutex;
690}
691
692inline MUTEX MutexCreateRecursive(void)
693{
694 MUTEX mutex;
695
696 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
697 if (mutex != NULL)
698 {
699#ifdef HAVE_RECURSIVE_MUTEXES
700 pthread_mutexattr_t a;
701
702 pthread_mutexattr_init(&a);
a0537937 703 MUTEXATTR_SETTYPE(&a, MUTEX_RECURSIVE_FLAG);
a3c76aba
VK
704 pthread_mutex_init(&mutex->mutex, &a);
705 pthread_mutexattr_destroy(&a);
706#else
9c8cf170 707 mutex->isRecursive = TRUE;
a3c76aba
VK
708#error FIXME: implement recursive mutexes
709#endif
710 }
54481027
VK
711 return mutex;
712}
713
714inline void MutexDestroy(MUTEX mutex)
715{
a3c76aba
VK
716 if (mutex != NULL)
717 {
718 pthread_mutex_destroy(&mutex->mutex);
54481027
VK
719 free(mutex);
720 }
721}
722
53c17a96 723inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
54481027 724{
d16cf8a5
AK
725 int i;
726 int ret = FALSE;
727
a3c76aba
VK
728 if (mutex != NULL)
729 {
951e884e
AK
730 if (dwTimeOut == INFINITE)
731 {
a3c76aba
VK
732 if (pthread_mutex_lock(&mutex->mutex) == 0)
733 {
d16cf8a5 734 ret = TRUE;
d16cf8a5 735 }
951e884e
AK
736 }
737 else
738 {
a3c76aba
VK
739 for (i = (dwTimeOut / 50) + 1; i > 0; i--)
740 {
741 if (pthread_mutex_trylock(&mutex->mutex) == 0)
8a435919 742 {
951e884e
AK
743 ret = TRUE;
744 break;
745 }
02ed4cf1 746 ThreadSleepMs(50);
951e884e 747 }
d16cf8a5 748 }
7e679c4b 749 }
d16cf8a5 750 return ret;
54481027
VK
751}
752
753inline void MutexUnlock(MUTEX mutex)
754{
8a435919
VK
755 if (mutex != NULL)
756 {
a3c76aba 757 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
758 }
759}
760
d16cf8a5 761inline CONDITION ConditionCreate(BOOL bBroadcast)
7e679c4b
AK
762{
763 CONDITION cond;
764
a3c76aba 765 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
766 if (cond != NULL)
767 {
d16cf8a5
AK
768 pthread_cond_init(&cond->cond, NULL);
769 pthread_mutex_init(&cond->mutex, NULL);
770 cond->broadcast = bBroadcast;
5f743326 771 cond->isSet = FALSE;
7e679c4b 772 }
d16cf8a5 773
7e679c4b
AK
774 return cond;
775}
776
d16cf8a5 777inline void ConditionDestroy(CONDITION cond)
7e679c4b 778{
5f743326 779 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
780 {
781 pthread_cond_destroy(&cond->cond);
782 pthread_mutex_destroy(&cond->mutex);
783 free(cond);
7e679c4b
AK
784 }
785}
786
d16cf8a5 787inline void ConditionSet(CONDITION cond)
7e679c4b 788{
5f743326 789 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
790 {
791 pthread_mutex_lock(&cond->mutex);
5f743326 792 cond->isSet = TRUE;
02ed4cf1 793 if (cond->broadcast)
d16cf8a5
AK
794 {
795 pthread_cond_broadcast(&cond->cond);
796 }
797 else
798 {
799 pthread_cond_signal(&cond->cond);
800 }
801 pthread_mutex_unlock(&cond->mutex);
802 }
7e679c4b
AK
803}
804
5f743326
VK
805inline void ConditionReset(CONDITION cond)
806{
807 if (cond != INVALID_CONDITION_HANDLE)
808 {
809 pthread_mutex_lock(&cond->mutex);
810 cond->isSet = FALSE;
811 pthread_mutex_unlock(&cond->mutex);
812 }
813}
814
815inline void ConditionPulse(CONDITION cond)
816{
817 if (cond != INVALID_CONDITION_HANDLE)
818 {
819 pthread_mutex_lock(&cond->mutex);
820 if (cond->broadcast)
821 {
822 pthread_cond_broadcast(&cond->cond);
823 }
824 else
825 {
826 pthread_cond_signal(&cond->cond);
827 }
828 cond->isSet = FALSE;
829 pthread_mutex_unlock(&cond->mutex);
830 }
831}
832
d16cf8a5 833inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
7e679c4b 834{
d16cf8a5
AK
835 BOOL ret = FALSE;
836
837 if (cond != NULL)
838 {
839 int retcode;
840
841 pthread_mutex_lock(&cond->mutex);
5f743326
VK
842 if (cond->isSet)
843 {
844 ret = TRUE;
845 if (!cond->broadcast)
846 cond->isSet = FALSE;
847 }
848 else
849 {
850 if (dwTimeOut != INFINITE)
851 {
58e7e86f 852#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 853 struct timespec timeout;
696fc54f 854
5f743326
VK
855 timeout.tv_sec = dwTimeOut / 1000;
856 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
857#ifdef _NETWARE
858 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
859#else
5f743326 860 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 861#endif
696fc54f 862#else
5f743326
VK
863 struct timeval now;
864 struct timespec timeout;
d16cf8a5 865
5f743326
VK
866 // note.
867 // mili - 10^-3
868 // micro - 10^-6
869 // nano - 10^-9
ed452de5 870
5f743326
VK
871 // FIXME there should be more accurate way
872 gettimeofday(&now, NULL);
873 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 874
5f743326
VK
875 now.tv_usec += (dwTimeOut % 1000) * 1000;
876 timeout.tv_sec += now.tv_usec / 1000000;
877 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 878
5f743326 879 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 880#endif
5f743326
VK
881 }
882 else
883 {
884 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
885 }
886
887 if (retcode == 0)
888 {
633907a4
VK
889 if (!cond->broadcast)
890 cond->isSet = FALSE;
5f743326
VK
891 ret = TRUE;
892 }
893 }
7e679c4b 894
d16cf8a5 895 pthread_mutex_unlock(&cond->mutex);
7e679c4b 896 }
d16cf8a5
AK
897
898 return ret;
54481027
VK
899}
900
bff234b8
VK
901inline DWORD GetCurrentProcessId(void)
902{
903 return getpid();
904}
905
d8250de7 906inline THREAD GetCurrentThreadId(void)
5e3c403d 907{
05f0165e 908 return pthread_self();
5e3c403d
VK
909}
910
54481027
VK
911#endif /* _WIN32 */
912
df7156b3
VK
913#include <rwlock.h>
914
b71bff93
VK
915#endif /* __cplusplus */
916
54481027 917#endif /* _nms_threads_h_ */