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