fixed makefile
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
ebf7222a 3** Copyright (C) 2003-2017 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
ebf7222a 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
ebf7222a 207inline bool MutexLock(MUTEX mutex)
54481027 208{
d113a890 209 if (mutex == INVALID_MUTEX_HANDLE)
ebf7222a 210 return false;
242108d4
VK
211 EnterCriticalSection(mutex);
212 return true;
ebf7222a
VK
213}
214
215inline bool MutexTryLock(MUTEX mutex)
216{
217 if (mutex == INVALID_MUTEX_HANDLE)
218 return false;
219 return TryEnterCriticalSection(mutex) ? true : false;
54481027
VK
220}
221
222inline void MutexUnlock(MUTEX mutex)
223{
03bb60ae 224 LeaveCriticalSection(mutex);
54481027
VK
225}
226
ebf7222a 227inline CONDITION ConditionCreate(bool bBroadcast)
54481027 228{
646d58de 229 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
54481027
VK
230}
231
232inline void ConditionDestroy(CONDITION hCond)
233{
234 CloseHandle(hCond);
235}
236
237inline void ConditionSet(CONDITION hCond)
238{
5f743326
VK
239 SetEvent(hCond);
240}
241
242inline void ConditionReset(CONDITION hCond)
243{
244 ResetEvent(hCond);
245}
246
247inline void ConditionPulse(CONDITION hCond)
248{
39d7a7ed 249 PulseEvent(hCond);
54481027
VK
250}
251
400e55c4 252inline bool ConditionWait(CONDITION hCond, UINT32 dwTimeOut)
54481027 253{
d113a890 254 if (hCond == INVALID_CONDITION_HANDLE)
400e55c4 255 return false;
c7f4f5a9 256 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
54481027
VK
257}
258
9b2bfc05
VK
259#elif defined(_USE_GNU_PTH)
260
261/****************************************************************************/
262/* GNU Pth */
263/****************************************************************************/
264
60414f77
VK
265//
266// Related datatypes and constants
267//
268
269typedef pth_t THREAD;
270typedef pth_mutex_t * MUTEX;
271struct netxms_condition_t
272{
273 pth_cond_t cond;
274 pth_mutex_t mutex;
ebf7222a
VK
275 bool broadcast;
276 bool isSet;
60414f77
VK
277};
278typedef struct netxms_condition_t * CONDITION;
279
280#define INVALID_MUTEX_HANDLE (NULL)
281#define INVALID_CONDITION_HANDLE (NULL)
282#define INVALID_THREAD_HANDLE (NULL)
283
284#ifndef INFINITE
9c8cf170 285#define INFINITE 0xFFFFFFFF
60414f77
VK
286#endif
287
288typedef void *THREAD_RESULT;
289
290#define THREAD_OK ((void *)0)
291#define THREAD_CALL
292
9113e749
VK
293extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *);
294
60414f77
VK
295
296//
297// Inline functions
298//
299
f7d1334b 300inline void InitThreadLibrary()
dc5bad96
VK
301{
302 if (!pth_init())
303 {
304 perror("pth_init() failed");
305 exit(200);
306 }
307}
308
60414f77
VK
309inline void ThreadSleep(int nSeconds)
310{
311 pth_sleep(nSeconds);
312}
313
967893bb 314inline void ThreadSleepMs(UINT32 dwMilliseconds)
60414f77 315{
cd4c8ca3 316 pth_usleep(dwMilliseconds * 1000);
60414f77
VK
317}
318
ebf7222a 319inline bool ThreadCreate(ThreadFunction start_address, int stack_size, void *args)
60414f77
VK
320{
321 THREAD id;
322
323 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
324 {
325 pth_attr_set(pth_attr_of(id), PTH_ATTR_JOINABLE, 0);
326 return TRUE;
327 }
328 else
329 {
330 return FALSE;
331 }
332}
333
9113e749 334inline THREAD ThreadCreateEx(ThreadFunction start_address, int stack_size, void *args)
60414f77
VK
335{
336 THREAD id;
337
338 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
339 {
cd4c8ca3 340 return id;
60414f77
VK
341 }
342 else
343 {
cd4c8ca3 344 return INVALID_THREAD_HANDLE;
60414f77
VK
345 }
346}
347
348inline void ThreadExit(void)
349{
350 pth_exit(NULL);
351}
352
353inline void ThreadJoin(THREAD hThread)
354{
355 if (hThread != INVALID_THREAD_HANDLE)
356 pth_join(hThread, NULL);
357}
358
a87ef571
VK
359inline void ThreadDetach(THREAD hThread)
360{
361 if (hThread != INVALID_THREAD_HANDLE)
362 pth_detach(hThread);
363}
364
60414f77
VK
365inline MUTEX MutexCreate(void)
366{
367 MUTEX mutex;
368
369 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
370 if (mutex != NULL)
dc5bad96 371 {
60414f77 372 pth_mutex_init(mutex);
dc5bad96 373 }
60414f77
VK
374 return mutex;
375}
376
98abc9f1 377inline MUTEX MutexCreateRecursive()
60414f77
VK
378{
379 MUTEX mutex;
380
381 // In libpth, recursive locking is explicitly supported,
382 // so we just create mutex
383 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
384 if (mutex != NULL)
dc5bad96 385 {
60414f77 386 pth_mutex_init(mutex);
dc5bad96 387 }
60414f77
VK
388 return mutex;
389}
390
391inline void MutexDestroy(MUTEX mutex)
392{
393 if (mutex != NULL)
394 free(mutex);
395}
396
ebf7222a 397inline bool MutexLock(MUTEX mutex)
60414f77 398{
ebf7222a
VK
399 return (mutex != NULL) ? (pth_mutex_acquire(mutex, FALSE, NULL) != 0) : false;
400}
60414f77 401
ebf7222a
VK
402inline bool MutexTryLock(MUTEX mutex)
403{
404 return (mutex != NULL) ? (pth_mutex_acquire(mutex, TRUE, NULL) != 0) : false;
60414f77
VK
405}
406
407inline void MutexUnlock(MUTEX mutex)
408{
409 if (mutex != NULL)
60414f77 410 pth_mutex_release(mutex);
60414f77
VK
411}
412
ebf7222a 413inline CONDITION ConditionCreate(bool bBroadcast)
60414f77
VK
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
ebf7222a 574 bool isRecursive;
a3c76aba
VK
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;
ebf7222a
VK
583 bool broadcast;
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
ebf7222a 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
ebf7222a 740inline bool MutexLock(MUTEX mutex)
54481027 741{
ebf7222a
VK
742 return (mutex != NULL) ? (pthread_mutex_lock(&mutex->mutex) == 0) : false;
743}
d16cf8a5 744
ebf7222a
VK
745inline bool MutexTryLock(MUTEX mutex)
746{
747 return (mutex != NULL) ? (pthread_mutex_trylock(&mutex->mutex) == 0) : false;
54481027
VK
748}
749
750inline void MutexUnlock(MUTEX mutex)
751{
8a435919 752 if (mutex != NULL)
a3c76aba 753 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
754}
755
ebf7222a 756inline CONDITION ConditionCreate(bool bBroadcast)
7e679c4b
AK
757{
758 CONDITION cond;
759
a3c76aba 760 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
761 if (cond != NULL)
762 {
d16cf8a5
AK
763 pthread_cond_init(&cond->cond, NULL);
764 pthread_mutex_init(&cond->mutex, NULL);
765 cond->broadcast = bBroadcast;
5f743326 766 cond->isSet = FALSE;
7e679c4b 767 }
d16cf8a5 768
7e679c4b
AK
769 return cond;
770}
771
d16cf8a5 772inline void ConditionDestroy(CONDITION cond)
7e679c4b 773{
5f743326 774 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
775 {
776 pthread_cond_destroy(&cond->cond);
777 pthread_mutex_destroy(&cond->mutex);
778 free(cond);
7e679c4b
AK
779 }
780}
781
d16cf8a5 782inline void ConditionSet(CONDITION cond)
7e679c4b 783{
5f743326 784 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
785 {
786 pthread_mutex_lock(&cond->mutex);
5f743326 787 cond->isSet = TRUE;
02ed4cf1 788 if (cond->broadcast)
d16cf8a5
AK
789 {
790 pthread_cond_broadcast(&cond->cond);
791 }
792 else
793 {
794 pthread_cond_signal(&cond->cond);
795 }
796 pthread_mutex_unlock(&cond->mutex);
797 }
7e679c4b
AK
798}
799
5f743326
VK
800inline void ConditionReset(CONDITION cond)
801{
802 if (cond != INVALID_CONDITION_HANDLE)
803 {
804 pthread_mutex_lock(&cond->mutex);
805 cond->isSet = FALSE;
806 pthread_mutex_unlock(&cond->mutex);
807 }
808}
809
810inline void ConditionPulse(CONDITION cond)
811{
812 if (cond != INVALID_CONDITION_HANDLE)
813 {
814 pthread_mutex_lock(&cond->mutex);
815 if (cond->broadcast)
816 {
817 pthread_cond_broadcast(&cond->cond);
818 }
819 else
820 {
821 pthread_cond_signal(&cond->cond);
822 }
823 cond->isSet = FALSE;
824 pthread_mutex_unlock(&cond->mutex);
825 }
826}
827
400e55c4 828inline bool ConditionWait(CONDITION cond, UINT32 dwTimeOut)
7e679c4b 829{
400e55c4 830 bool ret = FALSE;
d16cf8a5
AK
831
832 if (cond != NULL)
833 {
834 int retcode;
835
836 pthread_mutex_lock(&cond->mutex);
5f743326
VK
837 if (cond->isSet)
838 {
400e55c4 839 ret = true;
5f743326
VK
840 if (!cond->broadcast)
841 cond->isSet = FALSE;
842 }
843 else
844 {
845 if (dwTimeOut != INFINITE)
846 {
58e7e86f 847#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 848 struct timespec timeout;
696fc54f 849
5f743326
VK
850 timeout.tv_sec = dwTimeOut / 1000;
851 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
852#ifdef _NETWARE
853 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
854#else
5f743326 855 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 856#endif
696fc54f 857#else
5f743326
VK
858 struct timeval now;
859 struct timespec timeout;
d16cf8a5 860
5f743326
VK
861 // note.
862 // mili - 10^-3
863 // micro - 10^-6
864 // nano - 10^-9
ed452de5 865
5f743326
VK
866 // FIXME there should be more accurate way
867 gettimeofday(&now, NULL);
868 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 869
5f743326
VK
870 now.tv_usec += (dwTimeOut % 1000) * 1000;
871 timeout.tv_sec += now.tv_usec / 1000000;
872 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 873
5f743326 874 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 875#endif
5f743326
VK
876 }
877 else
878 {
879 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
880 }
881
882 if (retcode == 0)
883 {
633907a4
VK
884 if (!cond->broadcast)
885 cond->isSet = FALSE;
400e55c4 886 ret = true;
5f743326
VK
887 }
888 }
7e679c4b 889
d16cf8a5 890 pthread_mutex_unlock(&cond->mutex);
7e679c4b 891 }
d16cf8a5
AK
892
893 return ret;
54481027
VK
894}
895
967893bb 896inline UINT32 GetCurrentProcessId()
bff234b8
VK
897{
898 return getpid();
899}
900
c17f6cbc 901inline THREAD GetCurrentThreadId()
5e3c403d 902{
05f0165e 903 return pthread_self();
5e3c403d
VK
904}
905
54481027
VK
906#endif /* _WIN32 */
907
df7156b3
VK
908#include <rwlock.h>
909
5d3459af 910/**
374afd7b
VK
911 * String list
912 */
913class StringList;
914
915/**
5d3459af
VK
916 * Thread pool
917 */
918struct ThreadPool;
919
920/**
921 * Thread pool information
922 */
923struct ThreadPoolInfo
924{
925 const TCHAR *name; // pool name
926 int minThreads; // min threads
927 int maxThreads; // max threads
928 int curThreads; // current threads
929 int activeRequests; // number of active requests
5d3459af 930 int usage; // Pool usage in %
7e1816e5
VK
931 int load; // Pool current load in % (can be more than 100% if there are more requests then threads available)
932 double loadAvg[3]; // Pool load average
5d3459af
VK
933};
934
935/**
936 * Worker function for thread pool
937 */
938typedef void (* ThreadPoolWorkerFunction)(void *);
939
940/* Thread pool functions */
941ThreadPool LIBNETXMS_EXPORTABLE *ThreadPoolCreate(int minThreads, int maxThreads, const TCHAR *name);
942void LIBNETXMS_EXPORTABLE ThreadPoolDestroy(ThreadPool *p);
943void LIBNETXMS_EXPORTABLE ThreadPoolExecute(ThreadPool *p, ThreadPoolWorkerFunction f, void *arg);
e1415980 944void LIBNETXMS_EXPORTABLE ThreadPoolExecuteSerialized(ThreadPool *p, const TCHAR *key, ThreadPoolWorkerFunction f, void *arg);
5d3459af
VK
945void LIBNETXMS_EXPORTABLE ThreadPoolScheduleAbsolute(ThreadPool *p, time_t runTime, ThreadPoolWorkerFunction f, void *arg);
946void LIBNETXMS_EXPORTABLE ThreadPoolScheduleRelative(ThreadPool *p, UINT32 delay, ThreadPoolWorkerFunction f, void *arg);
947void LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(ThreadPool *p, ThreadPoolInfo *info);
374afd7b
VK
948bool LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(const TCHAR *name, ThreadPoolInfo *info);
949StringList LIBNETXMS_EXPORTABLE *ThreadPoolGetAllPools();
5d3459af 950
134c3d00
VK
951/**
952 * Wrapper data for ThreadPoolExecute
953 */
954template <typename T, typename R> class __ThreadPoolExecute_WrapperData
955{
956public:
957 T *m_object;
958 void (T::*m_func)(R);
959 R m_arg;
960
961 __ThreadPoolExecute_WrapperData(T *object, void (T::*func)(R), R arg) { m_object = object; m_func = func; m_arg = arg; }
962};
963
964/**
965 * Wrapper for ThreadPoolExecute
966 */
967template <typename T, typename R> void __ThreadPoolExecute_Wrapper(void *arg)
968{
969 __ThreadPoolExecute_WrapperData<T, R> *wd = static_cast<__ThreadPoolExecute_WrapperData<T, R> *>(arg);
970 ((*wd->m_object).*(wd->m_func))(wd->m_arg);
971 delete wd;
972}
973
974/**
975 * Execute task as soon as possible (use class member with one argument)
976 */
b029c8bc 977template <typename T, typename B, typename R> inline void ThreadPoolExecute(ThreadPool *p, T *object, void (B::*f)(R), R arg)
134c3d00 978{
b029c8bc 979 ThreadPoolExecute(p, __ThreadPoolExecute_Wrapper<B,R>, new __ThreadPoolExecute_WrapperData<B, R>(object, f, arg));
134c3d00
VK
980}
981
22aaa779 982/* Interlocked increment/decrement functions */
7785322f
VK
983#ifdef _WIN32
984
985typedef volatile LONG VolatileCounter;
7785322f
VK
986
987#else
22aaa779 988
5a64ab96 989#if defined(__sun)
22aaa779 990
7785322f 991typedef volatile uint32_t VolatileCounter;
f47bd4ca
VK
992
993#if !HAVE_ATOMIC_INC_32_NV
994extern "C" volatile uint32_t solaris9_atomic_inc32(volatile uint32_t *v);
995#endif
996
997#if !HAVE_ATOMIC_DEC_32_NV
998extern "C" volatile uint32_t solaris9_atomic_dec32(volatile uint32_t *v);
999#endif
7785322f 1000
22aaa779
VK
1001/**
1002 * Atomically increment 32-bit value by 1
1003 */
7785322f 1004inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
22aaa779 1005{
f47bd4ca 1006#if HAVE_ATOMIC_INC_32_NV
7785322f 1007 return atomic_inc_32_nv(v);
f47bd4ca
VK
1008#else
1009 return solaris9_atomic_inc32(v);
1010#endif
22aaa779
VK
1011}
1012
1013/**
1014 * Atomically decrement 32-bit value by 1
1015 */
7785322f 1016inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
22aaa779 1017{
f47bd4ca 1018#if HAVE_ATOMIC_DEC_32_NV
7785322f 1019 return atomic_dec_32_nv(v);
f47bd4ca
VK
1020#else
1021 return solaris9_atomic_dec32(v);
1022#endif
22aaa779
VK
1023}
1024
5a64ab96
VK
1025#elif defined(__HP_aCC)
1026
1027typedef volatile uint32_t VolatileCounter;
5a64ab96 1028
6dde8627
VK
1029#if defined(__hppa) && !HAVE_ATOMIC_H
1030VolatileCounter parisc_atomic_inc(VolatileCounter *v);
1031VolatileCounter parisc_atomic_dec(VolatileCounter *v);
1032#endif
1033
5a64ab96
VK
1034/**
1035 * Atomically increment 32-bit value by 1
1036 */
1037inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
1038{
3268bb77 1039#if HAVE_ATOMIC_H
5a64ab96 1040 return atomic_inc_32(v) + 1;
3268bb77 1041#else
6dde8627
VK
1042#ifdef __hppa
1043 return parisc_atomic_inc(v);
1044#else
3268bb77
VK
1045 _Asm_mf(_DFLT_FENCE);
1046 return (uint32_t)_Asm_fetchadd(_FASZ_W, _SEM_ACQ, (void *)v, +1, _LDHINT_NONE) + 1;
1047#endif
6dde8627 1048#endif
5a64ab96
VK
1049}
1050
1051/**
1052 * Atomically decrement 32-bit value by 1
1053 */
1054inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
1055{
3268bb77 1056#if HAVE_ATOMIC_H
5a64ab96 1057 return atomic_dec_32(v) - 1;
3268bb77 1058#else
6dde8627
VK
1059#ifdef __hppa
1060 return parisc_atomic_inc(v);
1061#else
3268bb77
VK
1062 _Asm_mf(_DFLT_FENCE);
1063 return (uint32_t)_Asm_fetchadd(_FASZ_W, _SEM_ACQ, (void *)v, -1, _LDHINT_NONE) - 1;
1064#endif
6dde8627 1065#endif
5a64ab96
VK
1066}
1067
5a64ab96 1068#else /* not Solaris nor HP-UX */
22aaa779 1069
7785322f 1070typedef volatile INT32 VolatileCounter;
7785322f 1071
22aaa779
VK
1072/**
1073 * Atomically increment 32-bit value by 1
1074 */
7785322f 1075inline VolatileCounter InterlockedIncrement(VolatileCounter *v)
22aaa779 1076{
efdaffe4
VK
1077#if (defined(__IBMC__) || defined(__IBMCPP__)) && !HAVE_DECL___SYNC_ADD_AND_FETCH
1078 VolatileCounter oldval;
1079 do
1080 {
1081 oldval = __lwarx(v);
1082 } while(__stwcx(v, oldval + 1) == 0);
1083 return oldval + 1;
2368dc85
VK
1084#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC_MINOR__ < 1)) && (defined(__i386__) || defined(__x86_64__))
1085 VolatileCounter temp = 1;
1086 __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*v) : : "memory");
1087 return temp + 1;
efdaffe4 1088#else
22aaa779 1089 return __sync_add_and_fetch(v, 1);
efdaffe4 1090#endif
22aaa779
VK
1091}
1092
1093/**
1094 * Atomically decrement 32-bit value by 1
1095 */
7785322f 1096inline VolatileCounter InterlockedDecrement(VolatileCounter *v)
22aaa779 1097{
efdaffe4
VK
1098#if (defined(__IBMC__) || defined(__IBMCPP__)) && !HAVE_DECL___SYNC_SUB_AND_FETCH
1099 VolatileCounter oldval;
1100 do
1101 {
1102 oldval = __lwarx(v);
1103 } while(__stwcx(v, oldval - 1) == 0);
1104 return oldval - 1;
2368dc85
VK
1105#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC_MINOR__ < 1)) && (defined(__i386__) || defined(__x86_64__))
1106 VolatileCounter temp = -1;
1107 __asm__ __volatile__("lock; xaddl %0,%1" : "+r" (temp), "+m" (*v) : : "memory");
1108 return temp - 1;
efdaffe4 1109#else
22aaa779 1110 return __sync_sub_and_fetch(v, 1);
efdaffe4 1111#endif
22aaa779
VK
1112}
1113
22aaa779
VK
1114#endif /* __sun */
1115
1116#endif /* _WIN32 */
1117
c73c3ba9
VK
1118/**
1119 * Wrappers for mutex
1120 */
1121class LIBNETXMS_EXPORTABLE Mutex
1122{
1123private:
1124 MUTEX m_mutex;
1125 VolatileCounter *m_refCount;
1126
1127public:
1128 Mutex();
1129 Mutex(const Mutex& src);
1130 ~Mutex();
1131
1132 Mutex& operator =(const Mutex &src);
1133
1134 void lock() { MutexLock(m_mutex); }
ebf7222a 1135 bool tryLock() { return MutexTryLock(m_mutex); }
c73c3ba9
VK
1136 void unlock() { MutexUnlock(m_mutex); }
1137};
1138
1139/**
1140 * Wrappers for read/write lock
1141 */
1142class LIBNETXMS_EXPORTABLE RWLock
1143{
1144private:
1145 RWLOCK m_rwlock;
1146 VolatileCounter *m_refCount;
1147
1148public:
1149 RWLock();
1150 RWLock(const RWLock& src);
1151 ~RWLock();
1152
1153 RWLock& operator =(const RWLock &src);
1154
1155 void readLock(UINT32 timeout = INFINITE) { RWLockReadLock(m_rwlock, timeout); }
1156 void writeLock(UINT32 timeout = INFINITE) { RWLockWriteLock(m_rwlock, timeout); }
1157 void unlock() { RWLockUnlock(m_rwlock); }
1158};
1159
1160/**
1161 * Wrappers for condition
1162 */
1163class LIBNETXMS_EXPORTABLE Condition
1164{
1165private:
1166 CONDITION m_condition;
1167 VolatileCounter *m_refCount;
1168
1169public:
1170 Condition(bool broadcast);
1171 Condition(const Condition& src);
1172 ~Condition();
1173
1174 Condition& operator =(const Condition &src);
1175
1176 void set() { ConditionSet(m_condition); }
1177 void pulse() { ConditionPulse(m_condition); }
1178 void reset() { ConditionReset(m_condition); }
1179 bool wait(UINT32 timeout = INFINITE) { return ConditionWait(m_condition, timeout); }
1180};
1181
b71bff93
VK
1182#endif /* __cplusplus */
1183
54481027 1184#endif /* _nms_threads_h_ */