cosmetic changes
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
5d3459af 3** Copyright (C) 2003-2015 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
a87ef571
VK
175inline void ThreadDetach(THREAD thread)
176{
177 if (thread != INVALID_THREAD_HANDLE)
178 {
179 CloseHandle(thread->handle);
180 free(thread);
181 }
182}
183
5405ce0b
VK
184inline THREAD_ID ThreadId(THREAD thread)
185{
186 return (thread != INVALID_THREAD_HANDLE) ? thread->id : 0;
187}
188
98abc9f1 189inline MUTEX MutexCreate()
54481027 190{
03bb60ae
VK
191 MUTEX mutex = (MUTEX)malloc(sizeof(CRITICAL_SECTION));
192 InitializeCriticalSectionAndSpinCount(mutex, 4000);
193 return mutex;
54481027
VK
194}
195
98abc9f1 196inline MUTEX MutexCreateRecursive()
a3c76aba 197{
03bb60ae 198 return MutexCreate();
a3c76aba
VK
199}
200
54481027
VK
201inline void MutexDestroy(MUTEX mutex)
202{
03bb60ae
VK
203 DeleteCriticalSection(mutex);
204 free(mutex);
54481027
VK
205}
206
c17f6cbc 207inline BOOL MutexLock(MUTEX mutex)
54481027 208{
d113a890
VK
209 if (mutex == INVALID_MUTEX_HANDLE)
210 return FALSE;
03bb60ae
VK
211 EnterCriticalSection(mutex);
212 return TRUE;
54481027
VK
213}
214
215inline void MutexUnlock(MUTEX mutex)
216{
03bb60ae 217 LeaveCriticalSection(mutex);
54481027
VK
218}
219
d16cf8a5 220inline CONDITION ConditionCreate(BOOL bBroadcast)
54481027 221{
646d58de 222 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
54481027
VK
223}
224
225inline void ConditionDestroy(CONDITION hCond)
226{
227 CloseHandle(hCond);
228}
229
230inline void ConditionSet(CONDITION hCond)
231{
5f743326
VK
232 SetEvent(hCond);
233}
234
235inline void ConditionReset(CONDITION hCond)
236{
237 ResetEvent(hCond);
238}
239
240inline void ConditionPulse(CONDITION hCond)
241{
39d7a7ed 242 PulseEvent(hCond);
54481027
VK
243}
244
400e55c4 245inline bool ConditionWait(CONDITION hCond, UINT32 dwTimeOut)
54481027 246{
d113a890 247 if (hCond == INVALID_CONDITION_HANDLE)
400e55c4 248 return false;
c7f4f5a9 249 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
54481027
VK
250}
251
9b2bfc05
VK
252#elif defined(_USE_GNU_PTH)
253
254/****************************************************************************/
255/* GNU Pth */
256/****************************************************************************/
257
60414f77
VK
258//
259// Related datatypes and constants
260//
261
262typedef pth_t THREAD;
263typedef pth_mutex_t * MUTEX;
264struct netxms_condition_t
265{
266 pth_cond_t cond;
267 pth_mutex_t mutex;
268 BOOL broadcast;
269 BOOL isSet;
270};
271typedef struct netxms_condition_t * CONDITION;
272
273#define INVALID_MUTEX_HANDLE (NULL)
274#define INVALID_CONDITION_HANDLE (NULL)
275#define INVALID_THREAD_HANDLE (NULL)
276
277#ifndef INFINITE
9c8cf170 278#define INFINITE 0xFFFFFFFF
60414f77
VK
279#endif
280
281typedef void *THREAD_RESULT;
282
283#define THREAD_OK ((void *)0)
284#define THREAD_CALL
285
9113e749
VK
286extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *);
287
60414f77
VK
288
289//
290// Inline functions
291//
292
f7d1334b 293inline void InitThreadLibrary()
dc5bad96
VK
294{
295 if (!pth_init())
296 {
297 perror("pth_init() failed");
298 exit(200);
299 }
300}
301
60414f77
VK
302inline void ThreadSleep(int nSeconds)
303{
304 pth_sleep(nSeconds);
305}
306
967893bb 307inline void ThreadSleepMs(UINT32 dwMilliseconds)
60414f77 308{
cd4c8ca3 309 pth_usleep(dwMilliseconds * 1000);
60414f77
VK
310}
311
9113e749 312inline BOOL ThreadCreate(ThreadFunction start_address, int stack_size, void *args)
60414f77
VK
313{
314 THREAD id;
315
316 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
317 {
318 pth_attr_set(pth_attr_of(id), PTH_ATTR_JOINABLE, 0);
319 return TRUE;
320 }
321 else
322 {
323 return FALSE;
324 }
325}
326
9113e749 327inline THREAD ThreadCreateEx(ThreadFunction start_address, int stack_size, void *args)
60414f77
VK
328{
329 THREAD id;
330
331 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
332 {
cd4c8ca3 333 return id;
60414f77
VK
334 }
335 else
336 {
cd4c8ca3 337 return INVALID_THREAD_HANDLE;
60414f77
VK
338 }
339}
340
341inline void ThreadExit(void)
342{
343 pth_exit(NULL);
344}
345
346inline void ThreadJoin(THREAD hThread)
347{
348 if (hThread != INVALID_THREAD_HANDLE)
349 pth_join(hThread, NULL);
350}
351
a87ef571
VK
352inline void ThreadDetach(THREAD hThread)
353{
354 if (hThread != INVALID_THREAD_HANDLE)
355 pth_detach(hThread);
356}
357
60414f77
VK
358inline MUTEX MutexCreate(void)
359{
360 MUTEX mutex;
361
362 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
363 if (mutex != NULL)
dc5bad96 364 {
60414f77 365 pth_mutex_init(mutex);
dc5bad96 366 }
60414f77
VK
367 return mutex;
368}
369
98abc9f1 370inline MUTEX MutexCreateRecursive()
60414f77
VK
371{
372 MUTEX mutex;
373
374 // In libpth, recursive locking is explicitly supported,
375 // so we just create mutex
376 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
377 if (mutex != NULL)
dc5bad96 378 {
60414f77 379 pth_mutex_init(mutex);
dc5bad96 380 }
60414f77
VK
381 return mutex;
382}
383
384inline void MutexDestroy(MUTEX mutex)
385{
386 if (mutex != NULL)
387 free(mutex);
388}
389
c17f6cbc 390inline BOOL MutexLock(MUTEX mutex)
60414f77
VK
391{
392 int i;
393 int ret = FALSE;
394
395 if (mutex != NULL)
396 {
c17f6cbc
VK
397 if (pth_mutex_acquire(mutex, FALSE, NULL))
398 {
399 ret = TRUE;
60414f77
VK
400 }
401 }
402 return ret;
403}
404
405inline void MutexUnlock(MUTEX mutex)
406{
407 if (mutex != NULL)
408 {
409 pth_mutex_release(mutex);
410 }
411}
412
413inline CONDITION ConditionCreate(BOOL bBroadcast)
414{
415 CONDITION cond;
416
cd4c8ca3
VK
417 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
418 if (cond != NULL)
419 {
420 pth_cond_init(&cond->cond);
421 pth_mutex_init(&cond->mutex);
60414f77 422 cond->broadcast = bBroadcast;
cd4c8ca3 423 cond->isSet = FALSE;
60414f77
VK
424 }
425
cd4c8ca3 426 return cond;
60414f77
VK
427}
428
429inline void ConditionDestroy(CONDITION cond)
430{
431 if (cond != INVALID_CONDITION_HANDLE)
432 {
433 free(cond);
434 }
435}
436
437inline void ConditionSet(CONDITION cond)
438{
439 if (cond != INVALID_CONDITION_HANDLE)
440 {
441 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
442 cond->isSet = TRUE;
443 pth_cond_notify(&cond->cond, cond->broadcast);
444 pth_mutex_release(&cond->mutex);
445 }
446}
447
448inline void ConditionReset(CONDITION cond)
449{
450 if (cond != INVALID_CONDITION_HANDLE)
451 {
452 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
453 cond->isSet = FALSE;
454 pth_mutex_release(&cond->mutex);
455 }
456}
457
458inline void ConditionPulse(CONDITION cond)
459{
460 if (cond != INVALID_CONDITION_HANDLE)
461 {
462 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
463 pth_cond_notify(&cond->cond, cond->broadcast);
464 cond->isSet = FALSE;
465 pth_mutex_release(&cond->mutex);
466 }
467}
468
400e55c4 469inline bool ConditionWait(CONDITION cond, UINT32 dwTimeOut)
60414f77 470{
400e55c4 471 bool ret = false;
60414f77
VK
472
473 if (cond != NULL)
474 {
475 int retcode;
476
477 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
478 if (cond->isSet)
479 {
400e55c4 480 ret = true;
60414f77
VK
481 if (!cond->broadcast)
482 cond->isSet = FALSE;
483 }
484 else
485 {
486 if (dwTimeOut != INFINITE)
487 {
488 pth_event_t ev;
489
490 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
cd4c8ca3 491 retcode = pth_cond_await(&cond->cond, &cond->mutex, ev);
60414f77
VK
492 pth_event_free(ev, PTH_FREE_ALL);
493 }
494 else
495 {
496 retcode = pth_cond_await(&cond->cond, &cond->mutex, NULL);
497 }
498
499 if (retcode)
500 {
501 if (!cond->broadcast)
502 cond->isSet = FALSE;
400e55c4 503 ret = true;
60414f77
VK
504 }
505 }
506
507 pth_mutex_release(&cond->mutex);
508 }
509
510 return ret;
511}
512
967893bb 513inline UINT32 GetCurrentProcessId()
60414f77
VK
514{
515 return getpid();
516}
517
98abc9f1 518inline THREAD GetCurrentThreadId()
60414f77
VK
519{
520 return pth_self();
521}
522
523#else /* not _WIN32 && not _USE_GNU_PTH */
54481027 524
d16cf8a5 525/****************************************************************************/
9b2bfc05 526/* pthreads */
d16cf8a5
AK
527/****************************************************************************/
528
54481027 529#include <pthread.h>
d16cf8a5
AK
530#include <errno.h>
531#include <sys/time.h>
54481027 532
9b2bfc05 533#if HAVE_PTHREAD_NP_H && !defined(_IPSO)
6cd41ceb
VK
534#include <pthread_np.h>
535#endif
536
39086394
VK
537#if (HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE___PTHREAD_MUTEXATTR_SETTYPE || HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) && \
538 HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE && \
539 (HAVE_DECL_PTHREAD_MUTEX_RECURSIVE || \
6cd41ceb
VK
540 HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP || \
541 HAVE_DECL_MUTEX_TYPE_COUNTING_FAST)
a0537937
VK
542
543#define HAVE_RECURSIVE_MUTEXES 1
544
545#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
546#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE
6cd41ceb 547#elif HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP
a0537937 548#define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE_NP
6cd41ceb
VK
549#elif HAVE_DECL_MUTEX_TYPE_COUNTING_FAST
550#define MUTEX_RECURSIVE_FLAG MUTEX_TYPE_COUNTING_FAST
551#else
552#error Constant used to declare recursive mutex is not known
a0537937
VK
553#endif
554
39086394 555#if HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE
a0537937 556#define MUTEXATTR_SETTYPE pthread_mutexattr_settype
39086394
VK
557#elif HAVE___PTHREAD_MUTEXATTR_SETTYPE
558#define MUTEXATTR_SETTYPE __pthread_mutexattr_settype
a0537937
VK
559#else
560#define MUTEXATTR_SETTYPE pthread_mutexattr_setkind_np
561#endif
562
563#endif
564
54481027
VK
565//
566// Related datatypes and constants
567//
568
7e679c4b 569typedef pthread_t THREAD;
a3c76aba
VK
570struct netxms_mutex_t
571{
572 pthread_mutex_t mutex;
573#ifndef HAVE_RECURSIVE_MUTEXES
574 BOOL isRecursive;
575 pthread_t owner;
576#endif
577};
578typedef netxms_mutex_t * MUTEX;
579struct netxms_condition_t
d16cf8a5
AK
580{
581 pthread_cond_t cond;
582 pthread_mutex_t mutex;
583 BOOL broadcast;
5f743326 584 BOOL isSet;
d16cf8a5 585};
a3c76aba 586typedef struct netxms_condition_t * CONDITION;
54481027 587
449e3da9
VK
588#define INVALID_MUTEX_HANDLE (NULL)
589#define INVALID_CONDITION_HANDLE (NULL)
ccdbbb52 590#define INVALID_THREAD_HANDLE 0
54481027 591
7e679c4b 592#ifndef INFINITE
9c8cf170 593#define INFINITE 0xFFFFFFFF
7e679c4b 594#endif
54481027 595
ccdbbb52
VK
596typedef void *THREAD_RESULT;
597
598#define THREAD_OK ((void *)0)
599#define THREAD_CALL
600
9113e749
VK
601extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *);
602
ccdbbb52 603
54481027
VK
604//
605// Inline functions
606//
607
98abc9f1 608inline void InitThreadLibrary()
dc5bad96
VK
609{
610}
611
d16cf8a5 612inline void ThreadSleep(int nSeconds)
54481027 613{
22412a01
VK
614#ifdef _NETWARE
615 sleep(nSeconds);
616#else
d16cf8a5
AK
617 struct timeval tv;
618
619 tv.tv_sec = nSeconds;
620 tv.tv_usec = 0;
621
622 select(1, NULL, NULL, NULL, &tv);
22412a01 623#endif
54481027
VK
624}
625
967893bb 626inline void ThreadSleepMs(UINT32 dwMilliseconds)
54481027 627{
ccc34207 628#if HAVE_NANOSLEEP && HAVE_DECL_NANOSLEEP
642bb2d8
VK
629 struct timespec interval, remainder;
630
631 interval.tv_sec = dwMilliseconds / 1000;
632 interval.tv_nsec = (dwMilliseconds % 1000) * 1000000; // milli -> nano
633 nanosleep(&interval, &remainder);
634#else
635 usleep(dwMilliseconds * 1000); // Convert to microseconds
636#endif
54481027
VK
637}
638
9113e749 639inline THREAD ThreadCreateEx(ThreadFunction start_address, int stack_size, void *args)
7e679c4b 640{
f7b2df08 641 THREAD id;
7e679c4b 642
f7b2df08
AK
643 if (stack_size <= 0)
644 {
645 // TODO: Find out minimal stack size
646 stack_size = 1024 * 1024; // 1MB
647 // set stack size to 1mb (it's windows default - and application works,
648 // we need to investigate more on this)
ccdbbb52 649 }
f7b2df08
AK
650 pthread_attr_t attr;
651 pthread_attr_init(&attr);
652 pthread_attr_setstacksize(&attr, stack_size);
653
654 if (pthread_create(&id, &attr, start_address, args) != 0)
655 {
656 id = INVALID_THREAD_HANDLE;
657 }
658
ab51c4d0
VK
659 pthread_attr_destroy(&attr);
660
f7b2df08 661 return id;
ccdbbb52
VK
662}
663
9113e749 664inline BOOL ThreadCreate(ThreadFunction start_address, int stack_size, void *args)
ccdbbb52 665{
f7b2df08 666 THREAD id = ThreadCreateEx(start_address, stack_size, args);
ccdbbb52 667
f7b2df08
AK
668 if (id != INVALID_THREAD_HANDLE)
669 {
670 pthread_detach(id);
671 return TRUE;
672 }
673
674 return FALSE;
7e679c4b
AK
675}
676
98abc9f1 677inline void ThreadExit()
7e679c4b 678{
521d90e7 679 pthread_exit(NULL);
7e679c4b
AK
680}
681
ccdbbb52
VK
682inline void ThreadJoin(THREAD hThread)
683{
684 if (hThread != INVALID_THREAD_HANDLE)
35a3a09e 685 pthread_join(hThread, NULL);
ccdbbb52
VK
686}
687
a87ef571
VK
688inline void ThreadDetach(THREAD hThread)
689{
690 if (hThread != INVALID_THREAD_HANDLE)
691 pthread_detach(hThread);
692}
693
5096f5a5 694inline MUTEX MutexCreate()
54481027
VK
695{
696 MUTEX mutex;
697
a3c76aba 698 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
54481027 699 if (mutex != NULL)
9c8cf170 700 {
8118ecaf 701 pthread_mutex_init(&mutex->mutex, NULL);
9c8cf170
VK
702#ifndef HAVE_RECURSIVE_MUTEXES
703 mutex->isRecursive = FALSE;
704#endif
705 }
a3c76aba
VK
706 return mutex;
707}
708
98abc9f1 709inline MUTEX MutexCreateRecursive()
a3c76aba
VK
710{
711 MUTEX mutex;
712
713 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
714 if (mutex != NULL)
715 {
716#ifdef HAVE_RECURSIVE_MUTEXES
717 pthread_mutexattr_t a;
718
719 pthread_mutexattr_init(&a);
a0537937 720 MUTEXATTR_SETTYPE(&a, MUTEX_RECURSIVE_FLAG);
a3c76aba
VK
721 pthread_mutex_init(&mutex->mutex, &a);
722 pthread_mutexattr_destroy(&a);
723#else
9c8cf170 724 mutex->isRecursive = TRUE;
a3c76aba
VK
725#error FIXME: implement recursive mutexes
726#endif
727 }
54481027
VK
728 return mutex;
729}
730
731inline void MutexDestroy(MUTEX mutex)
732{
a3c76aba
VK
733 if (mutex != NULL)
734 {
735 pthread_mutex_destroy(&mutex->mutex);
54481027
VK
736 free(mutex);
737 }
738}
739
c17f6cbc 740inline BOOL MutexLock(MUTEX mutex)
54481027 741{
d16cf8a5
AK
742 int ret = FALSE;
743
a3c76aba
VK
744 if (mutex != NULL)
745 {
c17f6cbc
VK
746 if (pthread_mutex_lock(&mutex->mutex) == 0)
747 {
748 ret = TRUE;
d16cf8a5 749 }
7e679c4b 750 }
d16cf8a5 751 return ret;
54481027
VK
752}
753
754inline void MutexUnlock(MUTEX mutex)
755{
8a435919
VK
756 if (mutex != NULL)
757 {
a3c76aba 758 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
759 }
760}
761
d16cf8a5 762inline CONDITION ConditionCreate(BOOL bBroadcast)
7e679c4b
AK
763{
764 CONDITION cond;
765
a3c76aba 766 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
767 if (cond != NULL)
768 {
d16cf8a5
AK
769 pthread_cond_init(&cond->cond, NULL);
770 pthread_mutex_init(&cond->mutex, NULL);
771 cond->broadcast = bBroadcast;
5f743326 772 cond->isSet = FALSE;
7e679c4b 773 }
d16cf8a5 774
7e679c4b
AK
775 return cond;
776}
777
d16cf8a5 778inline void ConditionDestroy(CONDITION cond)
7e679c4b 779{
5f743326 780 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
781 {
782 pthread_cond_destroy(&cond->cond);
783 pthread_mutex_destroy(&cond->mutex);
784 free(cond);
7e679c4b
AK
785 }
786}
787
d16cf8a5 788inline void ConditionSet(CONDITION cond)
7e679c4b 789{
5f743326 790 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
791 {
792 pthread_mutex_lock(&cond->mutex);
5f743326 793 cond->isSet = TRUE;
02ed4cf1 794 if (cond->broadcast)
d16cf8a5
AK
795 {
796 pthread_cond_broadcast(&cond->cond);
797 }
798 else
799 {
800 pthread_cond_signal(&cond->cond);
801 }
802 pthread_mutex_unlock(&cond->mutex);
803 }
7e679c4b
AK
804}
805
5f743326
VK
806inline void ConditionReset(CONDITION cond)
807{
808 if (cond != INVALID_CONDITION_HANDLE)
809 {
810 pthread_mutex_lock(&cond->mutex);
811 cond->isSet = FALSE;
812 pthread_mutex_unlock(&cond->mutex);
813 }
814}
815
816inline void ConditionPulse(CONDITION cond)
817{
818 if (cond != INVALID_CONDITION_HANDLE)
819 {
820 pthread_mutex_lock(&cond->mutex);
821 if (cond->broadcast)
822 {
823 pthread_cond_broadcast(&cond->cond);
824 }
825 else
826 {
827 pthread_cond_signal(&cond->cond);
828 }
829 cond->isSet = FALSE;
830 pthread_mutex_unlock(&cond->mutex);
831 }
832}
833
400e55c4 834inline bool ConditionWait(CONDITION cond, UINT32 dwTimeOut)
7e679c4b 835{
400e55c4 836 bool ret = FALSE;
d16cf8a5
AK
837
838 if (cond != NULL)
839 {
840 int retcode;
841
842 pthread_mutex_lock(&cond->mutex);
5f743326
VK
843 if (cond->isSet)
844 {
400e55c4 845 ret = true;
5f743326
VK
846 if (!cond->broadcast)
847 cond->isSet = FALSE;
848 }
849 else
850 {
851 if (dwTimeOut != INFINITE)
852 {
58e7e86f 853#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 854 struct timespec timeout;
696fc54f 855
5f743326
VK
856 timeout.tv_sec = dwTimeOut / 1000;
857 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
858#ifdef _NETWARE
859 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
860#else
5f743326 861 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 862#endif
696fc54f 863#else
5f743326
VK
864 struct timeval now;
865 struct timespec timeout;
d16cf8a5 866
5f743326
VK
867 // note.
868 // mili - 10^-3
869 // micro - 10^-6
870 // nano - 10^-9
ed452de5 871
5f743326
VK
872 // FIXME there should be more accurate way
873 gettimeofday(&now, NULL);
874 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 875
5f743326
VK
876 now.tv_usec += (dwTimeOut % 1000) * 1000;
877 timeout.tv_sec += now.tv_usec / 1000000;
878 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 879
5f743326 880 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 881#endif
5f743326
VK
882 }
883 else
884 {
885 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
886 }
887
888 if (retcode == 0)
889 {
633907a4
VK
890 if (!cond->broadcast)
891 cond->isSet = FALSE;
400e55c4 892 ret = true;
5f743326
VK
893 }
894 }
7e679c4b 895
d16cf8a5 896 pthread_mutex_unlock(&cond->mutex);
7e679c4b 897 }
d16cf8a5
AK
898
899 return ret;
54481027
VK
900}
901
967893bb 902inline UINT32 GetCurrentProcessId()
bff234b8
VK
903{
904 return getpid();
905}
906
c17f6cbc 907inline THREAD GetCurrentThreadId()
5e3c403d 908{
05f0165e 909 return pthread_self();
5e3c403d
VK
910}
911
54481027
VK
912#endif /* _WIN32 */
913
df7156b3
VK
914#include <rwlock.h>
915
5d3459af 916/**
374afd7b
VK
917 * String list
918 */
919class StringList;
920
921/**
5d3459af
VK
922 * Thread pool
923 */
924struct ThreadPool;
925
926/**
927 * Thread pool information
928 */
929struct ThreadPoolInfo
930{
931 const TCHAR *name; // pool name
932 int minThreads; // min threads
933 int maxThreads; // max threads
934 int curThreads; // current threads
935 int activeRequests; // number of active requests
5d3459af 936 int usage; // Pool usage in %
7e1816e5
VK
937 int load; // Pool current load in % (can be more than 100% if there are more requests then threads available)
938 double loadAvg[3]; // Pool load average
5d3459af
VK
939};
940
941/**
942 * Worker function for thread pool
943 */
944typedef void (* ThreadPoolWorkerFunction)(void *);
945
946/* Thread pool functions */
947ThreadPool LIBNETXMS_EXPORTABLE *ThreadPoolCreate(int minThreads, int maxThreads, const TCHAR *name);
948void LIBNETXMS_EXPORTABLE ThreadPoolDestroy(ThreadPool *p);
949void LIBNETXMS_EXPORTABLE ThreadPoolExecute(ThreadPool *p, ThreadPoolWorkerFunction f, void *arg);
e1415980 950void LIBNETXMS_EXPORTABLE ThreadPoolExecuteSerialized(ThreadPool *p, const TCHAR *key, ThreadPoolWorkerFunction f, void *arg);
5d3459af
VK
951void LIBNETXMS_EXPORTABLE ThreadPoolScheduleAbsolute(ThreadPool *p, time_t runTime, ThreadPoolWorkerFunction f, void *arg);
952void LIBNETXMS_EXPORTABLE ThreadPoolScheduleRelative(ThreadPool *p, UINT32 delay, ThreadPoolWorkerFunction f, void *arg);
953void LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(ThreadPool *p, ThreadPoolInfo *info);
374afd7b
VK
954bool LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(const TCHAR *name, ThreadPoolInfo *info);
955StringList LIBNETXMS_EXPORTABLE *ThreadPoolGetAllPools();
5d3459af 956
134c3d00
VK
957/**
958 * Wrapper data for ThreadPoolExecute
959 */
960template <typename T, typename R> class __ThreadPoolExecute_WrapperData
961{
962public:
963 T *m_object;
964 void (T::*m_func)(R);
965 R m_arg;
966
967 __ThreadPoolExecute_WrapperData(T *object, void (T::*func)(R), R arg) { m_object = object; m_func = func; m_arg = arg; }
968};
969
970/**
971 * Wrapper for ThreadPoolExecute
972 */
973template <typename T, typename R> void __ThreadPoolExecute_Wrapper(void *arg)
974{
975 __ThreadPoolExecute_WrapperData<T, R> *wd = static_cast<__ThreadPoolExecute_WrapperData<T, R> *>(arg);
976 ((*wd->m_object).*(wd->m_func))(wd->m_arg);
977 delete wd;
978}
979
980/**
981 * Execute task as soon as possible (use class member with one argument)
982 */
983template <typename T, typename R> inline void ThreadPoolExecute(ThreadPool *p, T *object, void (T::*f)(R), R arg)
984{
985 ThreadPoolExecute(p, __ThreadPoolExecute_Wrapper<T,R>, new __ThreadPoolExecute_WrapperData<T, R>(object, f, arg));
986}
987
22aaa779 988/* Interlocked increment/decrement functions */
7785322f
VK
989#ifdef _WIN32
990
991typedef volatile LONG VolatileCounter;
7785322f
VK
992
993#else
22aaa779 994
5a64ab96 995#if defined(__sun)
22aaa779 996
7785322f 997typedef volatile uint32_t VolatileCounter;
f47bd4ca
VK
998
999#if !HAVE_ATOMIC_INC_32_NV
1000extern "C" volatile uint32_t solaris9_atomic_inc32(volatile uint32_t *v);
1001#endif
1002
1003#if !HAVE_ATOMIC_DEC_32_NV
1004extern "C" volatile uint32_t solaris9_atomic_dec32(volatile uint32_t *v);
1005#endif
7785322f 1006
22aaa779
VK
1007/**
1008 * Atomically increment 32-bit value by 1
1009 */
7785322f 1010inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
22aaa779 1011{
f47bd4ca 1012#if HAVE_ATOMIC_INC_32_NV
7785322f 1013 return atomic_inc_32_nv(v);
f47bd4ca
VK
1014#else
1015 return solaris9_atomic_inc32(v);
1016#endif
22aaa779
VK
1017}
1018
1019/**
1020 * Atomically decrement 32-bit value by 1
1021 */
7785322f 1022inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
22aaa779 1023{
f47bd4ca 1024#if HAVE_ATOMIC_DEC_32_NV
7785322f 1025 return atomic_dec_32_nv(v);
f47bd4ca
VK
1026#else
1027 return solaris9_atomic_dec32(v);
1028#endif
22aaa779
VK
1029}
1030
5a64ab96
VK
1031#elif defined(__HP_aCC)
1032
1033typedef volatile uint32_t VolatileCounter;
5a64ab96 1034
6dde8627
VK
1035#if defined(__hppa) && !HAVE_ATOMIC_H
1036VolatileCounter parisc_atomic_inc(VolatileCounter *v);
1037VolatileCounter parisc_atomic_dec(VolatileCounter *v);
1038#endif
1039
5a64ab96
VK
1040/**
1041 * Atomically increment 32-bit value by 1
1042 */
1043inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
1044{
3268bb77 1045#if HAVE_ATOMIC_H
5a64ab96 1046 return atomic_inc_32(v) + 1;
3268bb77 1047#else
6dde8627
VK
1048#ifdef __hppa
1049 return parisc_atomic_inc(v);
1050#else
3268bb77
VK
1051 _Asm_mf(_DFLT_FENCE);
1052 return (uint32_t)_Asm_fetchadd(_FASZ_W, _SEM_ACQ, (void *)v, +1, _LDHINT_NONE) + 1;
1053#endif
6dde8627 1054#endif
5a64ab96
VK
1055}
1056
1057/**
1058 * Atomically decrement 32-bit value by 1
1059 */
1060inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
1061{
3268bb77 1062#if HAVE_ATOMIC_H
5a64ab96 1063 return atomic_dec_32(v) - 1;
3268bb77 1064#else
6dde8627
VK
1065#ifdef __hppa
1066 return parisc_atomic_inc(v);
1067#else
3268bb77
VK
1068 _Asm_mf(_DFLT_FENCE);
1069 return (uint32_t)_Asm_fetchadd(_FASZ_W, _SEM_ACQ, (void *)v, -1, _LDHINT_NONE) - 1;
1070#endif
6dde8627 1071#endif
5a64ab96
VK
1072}
1073
5a64ab96 1074#else /* not Solaris nor HP-UX */
22aaa779 1075
7785322f 1076typedef volatile INT32 VolatileCounter;
7785322f 1077
22aaa779
VK
1078/**
1079 * Atomically increment 32-bit value by 1
1080 */
7785322f 1081inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
22aaa779 1082{
efdaffe4
VK
1083#if (defined(__IBMC__) || defined(__IBMCPP__)) && !HAVE_DECL___SYNC_ADD_AND_FETCH
1084 VolatileCounter oldval;
1085 do
1086 {
1087 oldval = __lwarx(v);
1088 } while(__stwcx(v, oldval + 1) == 0);
1089 return oldval + 1;
2368dc85
VK
1090#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC_MINOR__ < 1)) && (defined(__i386__) || defined(__x86_64__))
1091 VolatileCounter temp = 1;
1092 __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*v) : : "memory");
1093 return temp + 1;
efdaffe4 1094#else
22aaa779 1095 return __sync_add_and_fetch(v, 1);
efdaffe4 1096#endif
22aaa779
VK
1097}
1098
1099/**
1100 * Atomically decrement 32-bit value by 1
1101 */
7785322f 1102inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
22aaa779 1103{
efdaffe4
VK
1104#if (defined(__IBMC__) || defined(__IBMCPP__)) && !HAVE_DECL___SYNC_SUB_AND_FETCH
1105 VolatileCounter oldval;
1106 do
1107 {
1108 oldval = __lwarx(v);
1109 } while(__stwcx(v, oldval - 1) == 0);
1110 return oldval - 1;
2368dc85
VK
1111#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC_MINOR__ < 1)) && (defined(__i386__) || defined(__x86_64__))
1112 VolatileCounter temp = -1;
1113 __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*v) : : "memory");
1114 return temp - 1;
efdaffe4 1115#else
22aaa779 1116 return __sync_sub_and_fetch(v, 1);
efdaffe4 1117#endif
22aaa779
VK
1118}
1119
22aaa779
VK
1120#endif /* __sun */
1121
1122#endif /* _WIN32 */
1123
c73c3ba9
VK
1124/**
1125 * Wrappers for mutex
1126 */
1127class LIBNETXMS_EXPORTABLE Mutex
1128{
1129private:
1130 MUTEX m_mutex;
1131 VolatileCounter *m_refCount;
1132
1133public:
1134 Mutex();
1135 Mutex(const Mutex& src);
1136 ~Mutex();
1137
1138 Mutex& operator =(const Mutex &src);
1139
1140 void lock() { MutexLock(m_mutex); }
1141 void unlock() { MutexUnlock(m_mutex); }
1142};
1143
1144/**
1145 * Wrappers for read/write lock
1146 */
1147class LIBNETXMS_EXPORTABLE RWLock
1148{
1149private:
1150 RWLOCK m_rwlock;
1151 VolatileCounter *m_refCount;
1152
1153public:
1154 RWLock();
1155 RWLock(const RWLock& src);
1156 ~RWLock();
1157
1158 RWLock& operator =(const RWLock &src);
1159
1160 void readLock(UINT32 timeout = INFINITE) { RWLockReadLock(m_rwlock, timeout); }
1161 void writeLock(UINT32 timeout = INFINITE) { RWLockWriteLock(m_rwlock, timeout); }
1162 void unlock() { RWLockUnlock(m_rwlock); }
1163};
1164
1165/**
1166 * Wrappers for condition
1167 */
1168class LIBNETXMS_EXPORTABLE Condition
1169{
1170private:
1171 CONDITION m_condition;
1172 VolatileCounter *m_refCount;
1173
1174public:
1175 Condition(bool broadcast);
1176 Condition(const Condition& src);
1177 ~Condition();
1178
1179 Condition& operator =(const Condition &src);
1180
1181 void set() { ConditionSet(m_condition); }
1182 void pulse() { ConditionPulse(m_condition); }
1183 void reset() { ConditionReset(m_condition); }
1184 bool wait(UINT32 timeout = INFINITE) { return ConditionWait(m_condition, timeout); }
1185};
1186
b71bff93
VK
1187#endif /* __cplusplus */
1188
54481027 1189#endif /* _nms_threads_h_ */