fixed bug in x64 agent installer
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
ccc34207 3** Copyright (C) 2003-2009 Victor Kirhenshtein
54481027
VK
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**
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
263#define INFINITE 0
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
AK
583#ifndef INFINITE
584# define INFINITE 0
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
648 return id;
ccdbbb52
VK
649}
650
f7b2df08 651inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
ccdbbb52 652{
f7b2df08 653 THREAD id = ThreadCreateEx(start_address, stack_size, args);
ccdbbb52 654
f7b2df08
AK
655 if (id != INVALID_THREAD_HANDLE)
656 {
657 pthread_detach(id);
658 return TRUE;
659 }
660
661 return FALSE;
7e679c4b
AK
662}
663
664inline void ThreadExit(void)
665{
521d90e7 666 pthread_exit(NULL);
7e679c4b
AK
667}
668
ccdbbb52
VK
669inline void ThreadJoin(THREAD hThread)
670{
671 if (hThread != INVALID_THREAD_HANDLE)
35a3a09e 672 pthread_join(hThread, NULL);
ccdbbb52
VK
673}
674
54481027
VK
675inline MUTEX MutexCreate(void)
676{
677 MUTEX mutex;
678
a3c76aba 679 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
54481027 680 if (mutex != NULL)
8118ecaf 681 pthread_mutex_init(&mutex->mutex, NULL);
a3c76aba
VK
682 return mutex;
683}
684
685inline MUTEX MutexCreateRecursive(void)
686{
687 MUTEX mutex;
688
689 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
690 if (mutex != NULL)
691 {
692#ifdef HAVE_RECURSIVE_MUTEXES
693 pthread_mutexattr_t a;
694
695 pthread_mutexattr_init(&a);
a0537937 696 MUTEXATTR_SETTYPE(&a, MUTEX_RECURSIVE_FLAG);
a3c76aba
VK
697 pthread_mutex_init(&mutex->mutex, &a);
698 pthread_mutexattr_destroy(&a);
699#else
700#error FIXME: implement recursive mutexes
701#endif
702 }
54481027
VK
703 return mutex;
704}
705
706inline void MutexDestroy(MUTEX mutex)
707{
a3c76aba
VK
708 if (mutex != NULL)
709 {
710 pthread_mutex_destroy(&mutex->mutex);
54481027
VK
711 free(mutex);
712 }
713}
714
53c17a96 715inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
54481027 716{
d16cf8a5
AK
717 int i;
718 int ret = FALSE;
719
a3c76aba
VK
720 if (mutex != NULL)
721 {
951e884e
AK
722 if (dwTimeOut == INFINITE)
723 {
a3c76aba
VK
724 if (pthread_mutex_lock(&mutex->mutex) == 0)
725 {
d16cf8a5 726 ret = TRUE;
d16cf8a5 727 }
951e884e
AK
728 }
729 else
730 {
a3c76aba
VK
731 for (i = (dwTimeOut / 50) + 1; i > 0; i--)
732 {
733 if (pthread_mutex_trylock(&mutex->mutex) == 0)
8a435919 734 {
951e884e
AK
735 ret = TRUE;
736 break;
737 }
02ed4cf1 738 ThreadSleepMs(50);
951e884e 739 }
d16cf8a5 740 }
7e679c4b 741 }
d16cf8a5 742 return ret;
54481027
VK
743}
744
745inline void MutexUnlock(MUTEX mutex)
746{
8a435919
VK
747 if (mutex != NULL)
748 {
a3c76aba 749 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
750 }
751}
752
d16cf8a5 753inline CONDITION ConditionCreate(BOOL bBroadcast)
7e679c4b
AK
754{
755 CONDITION cond;
756
a3c76aba 757 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
758 if (cond != NULL)
759 {
d16cf8a5
AK
760 pthread_cond_init(&cond->cond, NULL);
761 pthread_mutex_init(&cond->mutex, NULL);
762 cond->broadcast = bBroadcast;
5f743326 763 cond->isSet = FALSE;
7e679c4b 764 }
d16cf8a5 765
7e679c4b
AK
766 return cond;
767}
768
d16cf8a5 769inline void ConditionDestroy(CONDITION cond)
7e679c4b 770{
5f743326 771 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
772 {
773 pthread_cond_destroy(&cond->cond);
774 pthread_mutex_destroy(&cond->mutex);
775 free(cond);
7e679c4b
AK
776 }
777}
778
d16cf8a5 779inline void ConditionSet(CONDITION cond)
7e679c4b 780{
5f743326 781 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
782 {
783 pthread_mutex_lock(&cond->mutex);
5f743326 784 cond->isSet = TRUE;
02ed4cf1 785 if (cond->broadcast)
d16cf8a5
AK
786 {
787 pthread_cond_broadcast(&cond->cond);
788 }
789 else
790 {
791 pthread_cond_signal(&cond->cond);
792 }
793 pthread_mutex_unlock(&cond->mutex);
794 }
7e679c4b
AK
795}
796
5f743326
VK
797inline void ConditionReset(CONDITION cond)
798{
799 if (cond != INVALID_CONDITION_HANDLE)
800 {
801 pthread_mutex_lock(&cond->mutex);
802 cond->isSet = FALSE;
803 pthread_mutex_unlock(&cond->mutex);
804 }
805}
806
807inline void ConditionPulse(CONDITION cond)
808{
809 if (cond != INVALID_CONDITION_HANDLE)
810 {
811 pthread_mutex_lock(&cond->mutex);
812 if (cond->broadcast)
813 {
814 pthread_cond_broadcast(&cond->cond);
815 }
816 else
817 {
818 pthread_cond_signal(&cond->cond);
819 }
820 cond->isSet = FALSE;
821 pthread_mutex_unlock(&cond->mutex);
822 }
823}
824
d16cf8a5 825inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
7e679c4b 826{
d16cf8a5
AK
827 BOOL ret = FALSE;
828
829 if (cond != NULL)
830 {
831 int retcode;
832
833 pthread_mutex_lock(&cond->mutex);
5f743326
VK
834 if (cond->isSet)
835 {
836 ret = TRUE;
837 if (!cond->broadcast)
838 cond->isSet = FALSE;
839 }
840 else
841 {
842 if (dwTimeOut != INFINITE)
843 {
58e7e86f 844#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 845 struct timespec timeout;
696fc54f 846
5f743326
VK
847 timeout.tv_sec = dwTimeOut / 1000;
848 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
849#ifdef _NETWARE
850 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
851#else
5f743326 852 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 853#endif
696fc54f 854#else
5f743326
VK
855 struct timeval now;
856 struct timespec timeout;
d16cf8a5 857
5f743326
VK
858 // note.
859 // mili - 10^-3
860 // micro - 10^-6
861 // nano - 10^-9
ed452de5 862
5f743326
VK
863 // FIXME there should be more accurate way
864 gettimeofday(&now, NULL);
865 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 866
5f743326
VK
867 now.tv_usec += (dwTimeOut % 1000) * 1000;
868 timeout.tv_sec += now.tv_usec / 1000000;
869 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 870
5f743326 871 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 872#endif
5f743326
VK
873 }
874 else
875 {
876 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
877 }
878
879 if (retcode == 0)
880 {
633907a4
VK
881 if (!cond->broadcast)
882 cond->isSet = FALSE;
5f743326
VK
883 ret = TRUE;
884 }
885 }
7e679c4b 886
d16cf8a5 887 pthread_mutex_unlock(&cond->mutex);
7e679c4b 888 }
d16cf8a5
AK
889
890 return ret;
54481027
VK
891}
892
bff234b8
VK
893inline DWORD GetCurrentProcessId(void)
894{
895 return getpid();
896}
897
d8250de7 898inline THREAD GetCurrentThreadId(void)
5e3c403d 899{
05f0165e 900 return pthread_self();
5e3c403d
VK
901}
902
54481027
VK
903#endif /* _WIN32 */
904
df7156b3
VK
905#include <rwlock.h>
906
b71bff93
VK
907#endif /* __cplusplus */
908
54481027 909#endif /* _nms_threads_h_ */