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