Commit | Line | Data |
---|---|---|
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 |
45 | typedef UINT32 THREAD_RESULT; |
46 | typedef UINT32 THREAD_ID; | |
288ddda4 | 47 | #else |
ccdbbb52 | 48 | typedef unsigned int THREAD_RESULT; |
288ddda4 VK |
49 | typedef 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 |
59 | extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *); |
60 | ||
03bb60ae | 61 | typedef CRITICAL_SECTION *MUTEX; |
5405ce0b VK |
62 | typedef HANDLE CONDITION; |
63 | struct netxms_thread_t | |
64 | { | |
65 | HANDLE handle; | |
66 | THREAD_ID id; | |
67 | }; | |
68 | typedef struct netxms_thread_t *THREAD; | |
69 | ||
ba2c1467 VK |
70 | typedef struct |
71 | { | |
9113e749 | 72 | ThreadFunction start_address; |
ba2c1467 VK |
73 | void *args; |
74 | } THREAD_START_DATA; | |
75 | ||
76 | THREAD_RESULT LIBNETXMS_EXPORTABLE THREAD_CALL SEHThreadStarter(void *); | |
7a7ba846 | 77 | int LIBNETXMS_EXPORTABLE ___ExceptionHandler(EXCEPTION_POINTERS *pInfo); |
ba2c1467 | 78 | |
bb7a686c | 79 | void 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 | 83 | BOOL LIBNETXMS_EXPORTABLE SEHDefaultConsoleHandler(EXCEPTION_POINTERS *pInfo); |
eeb2f8d0 | 84 | TCHAR LIBNETXMS_EXPORTABLE *SEHExceptionName(DWORD code); |
ba2c1467 VK |
85 | void LIBNETXMS_EXPORTABLE SEHShowCallStack(CONTEXT *pCtx); |
86 | ||
ccc34207 VK |
87 | void LIBNETXMS_EXPORTABLE SEHServiceExceptionDataWriter(const TCHAR *pszText); |
88 | BOOL 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 | 100 | inline void InitThreadLibrary() |
dc5bad96 VK |
101 | { |
102 | } | |
103 | ||
54481027 VK |
104 | inline void ThreadSleep(int iSeconds) |
105 | { | |
967893bb | 106 | Sleep((UINT32)iSeconds * 1000); // Convert to milliseconds |
54481027 VK |
107 | } |
108 | ||
967893bb | 109 | inline void ThreadSleepMs(UINT32 dwMilliseconds) |
54481027 VK |
110 | { |
111 | Sleep(dwMilliseconds); | |
112 | } | |
113 | ||
ebf7222a | 114 | inline 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 | 132 | inline 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 | 156 | inline 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 | 165 | inline 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 |
175 | inline void ThreadDetach(THREAD thread) |
176 | { | |
177 | if (thread != INVALID_THREAD_HANDLE) | |
178 | { | |
179 | CloseHandle(thread->handle); | |
180 | free(thread); | |
181 | } | |
182 | } | |
183 | ||
5405ce0b VK |
184 | inline THREAD_ID ThreadId(THREAD thread) |
185 | { | |
186 | return (thread != INVALID_THREAD_HANDLE) ? thread->id : 0; | |
187 | } | |
188 | ||
98abc9f1 | 189 | inline 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 | 196 | inline MUTEX MutexCreateRecursive() |
a3c76aba | 197 | { |
03bb60ae | 198 | return MutexCreate(); |
a3c76aba VK |
199 | } |
200 | ||
54481027 VK |
201 | inline void MutexDestroy(MUTEX mutex) |
202 | { | |
03bb60ae VK |
203 | DeleteCriticalSection(mutex); |
204 | free(mutex); | |
54481027 VK |
205 | } |
206 | ||
ebf7222a | 207 | inline 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 | ||
215 | inline bool MutexTryLock(MUTEX mutex) | |
216 | { | |
217 | if (mutex == INVALID_MUTEX_HANDLE) | |
218 | return false; | |
219 | return TryEnterCriticalSection(mutex) ? true : false; | |
54481027 VK |
220 | } |
221 | ||
222 | inline void MutexUnlock(MUTEX mutex) | |
223 | { | |
03bb60ae | 224 | LeaveCriticalSection(mutex); |
54481027 VK |
225 | } |
226 | ||
ebf7222a | 227 | inline CONDITION ConditionCreate(bool bBroadcast) |
54481027 | 228 | { |
646d58de | 229 | return CreateEvent(NULL, bBroadcast, FALSE, NULL); |
54481027 VK |
230 | } |
231 | ||
232 | inline void ConditionDestroy(CONDITION hCond) | |
233 | { | |
234 | CloseHandle(hCond); | |
235 | } | |
236 | ||
237 | inline void ConditionSet(CONDITION hCond) | |
238 | { | |
5f743326 VK |
239 | SetEvent(hCond); |
240 | } | |
241 | ||
242 | inline void ConditionReset(CONDITION hCond) | |
243 | { | |
244 | ResetEvent(hCond); | |
245 | } | |
246 | ||
247 | inline void ConditionPulse(CONDITION hCond) | |
248 | { | |
39d7a7ed | 249 | PulseEvent(hCond); |
54481027 VK |
250 | } |
251 | ||
400e55c4 | 252 | inline 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 | ||
269 | typedef pth_t THREAD; | |
270 | typedef pth_mutex_t * MUTEX; | |
271 | struct 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 | }; |
278 | typedef 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 | ||
288 | typedef void *THREAD_RESULT; | |
289 | ||
290 | #define THREAD_OK ((void *)0) | |
291 | #define THREAD_CALL | |
292 | ||
9113e749 VK |
293 | extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *); |
294 | ||
60414f77 VK |
295 | |
296 | // | |
297 | // Inline functions | |
298 | // | |
299 | ||
f7d1334b | 300 | inline void InitThreadLibrary() |
dc5bad96 VK |
301 | { |
302 | if (!pth_init()) | |
303 | { | |
304 | perror("pth_init() failed"); | |
305 | exit(200); | |
306 | } | |
307 | } | |
308 | ||
60414f77 VK |
309 | inline void ThreadSleep(int nSeconds) |
310 | { | |
311 | pth_sleep(nSeconds); | |
312 | } | |
313 | ||
967893bb | 314 | inline void ThreadSleepMs(UINT32 dwMilliseconds) |
60414f77 | 315 | { |
cd4c8ca3 | 316 | pth_usleep(dwMilliseconds * 1000); |
60414f77 VK |
317 | } |
318 | ||
ebf7222a | 319 | inline 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 | 334 | inline 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 | ||
348 | inline void ThreadExit(void) | |
349 | { | |
350 | pth_exit(NULL); | |
351 | } | |
352 | ||
353 | inline void ThreadJoin(THREAD hThread) | |
354 | { | |
355 | if (hThread != INVALID_THREAD_HANDLE) | |
356 | pth_join(hThread, NULL); | |
357 | } | |
358 | ||
a87ef571 VK |
359 | inline void ThreadDetach(THREAD hThread) |
360 | { | |
361 | if (hThread != INVALID_THREAD_HANDLE) | |
362 | pth_detach(hThread); | |
363 | } | |
364 | ||
60414f77 VK |
365 | inline 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 | 377 | inline 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 | ||
391 | inline void MutexDestroy(MUTEX mutex) | |
392 | { | |
393 | if (mutex != NULL) | |
394 | free(mutex); | |
395 | } | |
396 | ||
ebf7222a | 397 | inline 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 |
402 | inline bool MutexTryLock(MUTEX mutex) |
403 | { | |
404 | return (mutex != NULL) ? (pth_mutex_acquire(mutex, TRUE, NULL) != 0) : false; | |
60414f77 VK |
405 | } |
406 | ||
407 | inline void MutexUnlock(MUTEX mutex) | |
408 | { | |
409 | if (mutex != NULL) | |
60414f77 | 410 | pth_mutex_release(mutex); |
60414f77 VK |
411 | } |
412 | ||
ebf7222a | 413 | inline 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 | ||
429 | inline void ConditionDestroy(CONDITION cond) | |
430 | { | |
431 | if (cond != INVALID_CONDITION_HANDLE) | |
432 | { | |
433 | free(cond); | |
434 | } | |
435 | } | |
436 | ||
437 | inline 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 | ||
448 | inline 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 | ||
458 | inline 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 | 469 | inline 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 | 513 | inline UINT32 GetCurrentProcessId() |
60414f77 VK |
514 | { |
515 | return getpid(); | |
516 | } | |
517 | ||
98abc9f1 | 518 | inline 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 | 569 | typedef pthread_t THREAD; |
a3c76aba VK |
570 | struct 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 | }; | |
578 | typedef netxms_mutex_t * MUTEX; | |
579 | struct 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 | 586 | typedef 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 |
596 | typedef void *THREAD_RESULT; |
597 | ||
598 | #define THREAD_OK ((void *)0) | |
599 | #define THREAD_CALL | |
600 | ||
9113e749 VK |
601 | extern "C" typedef THREAD_RESULT (THREAD_CALL *ThreadFunction)(void *); |
602 | ||
ccdbbb52 | 603 | |
54481027 VK |
604 | // |
605 | // Inline functions | |
606 | // | |
607 | ||
98abc9f1 | 608 | inline void InitThreadLibrary() |
dc5bad96 VK |
609 | { |
610 | } | |
611 | ||
d16cf8a5 | 612 | inline 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 | 626 | inline 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 | 639 | inline 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 | 664 | inline 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 | 677 | inline void ThreadExit() |
7e679c4b | 678 | { |
521d90e7 | 679 | pthread_exit(NULL); |
7e679c4b AK |
680 | } |
681 | ||
ccdbbb52 VK |
682 | inline void ThreadJoin(THREAD hThread) |
683 | { | |
684 | if (hThread != INVALID_THREAD_HANDLE) | |
35a3a09e | 685 | pthread_join(hThread, NULL); |
ccdbbb52 VK |
686 | } |
687 | ||
a87ef571 VK |
688 | inline void ThreadDetach(THREAD hThread) |
689 | { | |
690 | if (hThread != INVALID_THREAD_HANDLE) | |
691 | pthread_detach(hThread); | |
692 | } | |
693 | ||
5096f5a5 | 694 | inline 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 | 709 | inline 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 | ||
731 | inline 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 | 740 | inline bool MutexLock(MUTEX mutex) |
54481027 | 741 | { |
ebf7222a VK |
742 | return (mutex != NULL) ? (pthread_mutex_lock(&mutex->mutex) == 0) : false; |
743 | } | |
d16cf8a5 | 744 | |
ebf7222a VK |
745 | inline bool MutexTryLock(MUTEX mutex) |
746 | { | |
747 | return (mutex != NULL) ? (pthread_mutex_trylock(&mutex->mutex) == 0) : false; | |
54481027 VK |
748 | } |
749 | ||
750 | inline void MutexUnlock(MUTEX mutex) | |
751 | { | |
8a435919 | 752 | if (mutex != NULL) |
a3c76aba | 753 | pthread_mutex_unlock(&mutex->mutex); |
7e679c4b AK |
754 | } |
755 | ||
ebf7222a | 756 | inline 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 | 772 | inline 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 | 782 | inline 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 |
800 | inline 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 | ||
810 | inline 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 | 828 | inline 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 | 896 | inline UINT32 GetCurrentProcessId() |
bff234b8 VK |
897 | { |
898 | return getpid(); | |
899 | } | |
900 | ||
c17f6cbc | 901 | inline 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 | */ | |
913 | class StringList; | |
914 | ||
915 | /** | |
5d3459af VK |
916 | * Thread pool |
917 | */ | |
918 | struct ThreadPool; | |
919 | ||
920 | /** | |
921 | * Thread pool information | |
922 | */ | |
923 | struct 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 | */ | |
938 | typedef void (* ThreadPoolWorkerFunction)(void *); | |
939 | ||
940 | /* Thread pool functions */ | |
941 | ThreadPool LIBNETXMS_EXPORTABLE *ThreadPoolCreate(int minThreads, int maxThreads, const TCHAR *name); | |
942 | void LIBNETXMS_EXPORTABLE ThreadPoolDestroy(ThreadPool *p); | |
943 | void LIBNETXMS_EXPORTABLE ThreadPoolExecute(ThreadPool *p, ThreadPoolWorkerFunction f, void *arg); | |
e1415980 | 944 | void LIBNETXMS_EXPORTABLE ThreadPoolExecuteSerialized(ThreadPool *p, const TCHAR *key, ThreadPoolWorkerFunction f, void *arg); |
5d3459af VK |
945 | void LIBNETXMS_EXPORTABLE ThreadPoolScheduleAbsolute(ThreadPool *p, time_t runTime, ThreadPoolWorkerFunction f, void *arg); |
946 | void LIBNETXMS_EXPORTABLE ThreadPoolScheduleRelative(ThreadPool *p, UINT32 delay, ThreadPoolWorkerFunction f, void *arg); | |
947 | void LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(ThreadPool *p, ThreadPoolInfo *info); | |
374afd7b VK |
948 | bool LIBNETXMS_EXPORTABLE ThreadPoolGetInfo(const TCHAR *name, ThreadPoolInfo *info); |
949 | StringList LIBNETXMS_EXPORTABLE *ThreadPoolGetAllPools(); | |
5d3459af | 950 | |
134c3d00 VK |
951 | /** |
952 | * Wrapper data for ThreadPoolExecute | |
953 | */ | |
954 | template <typename T, typename R> class __ThreadPoolExecute_WrapperData | |
955 | { | |
956 | public: | |
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 | */ | |
967 | template <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 | */ | |
977 | template <typename T, typename R> inline void ThreadPoolExecute(ThreadPool *p, T *object, void (T::*f)(R), R arg) | |
978 | { | |
979 | ThreadPoolExecute(p, __ThreadPoolExecute_Wrapper<T,R>, new __ThreadPoolExecute_WrapperData<T, R>(object, f, arg)); | |
980 | } | |
981 | ||
22aaa779 | 982 | /* Interlocked increment/decrement functions */ |
7785322f VK |
983 | #ifdef _WIN32 |
984 | ||
985 | typedef volatile LONG VolatileCounter; | |
7785322f VK |
986 | |
987 | #else | |
22aaa779 | 988 | |
5a64ab96 | 989 | #if defined(__sun) |
22aaa779 | 990 | |
7785322f | 991 | typedef volatile uint32_t VolatileCounter; |
f47bd4ca VK |
992 | |
993 | #if !HAVE_ATOMIC_INC_32_NV | |
994 | extern "C" volatile uint32_t solaris9_atomic_inc32(volatile uint32_t *v); | |
995 | #endif | |
996 | ||
997 | #if !HAVE_ATOMIC_DEC_32_NV | |
998 | extern "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 | 1004 | inline 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 | 1016 | inline 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 | ||
1027 | typedef volatile uint32_t VolatileCounter; | |
5a64ab96 | 1028 | |
6dde8627 VK |
1029 | #if defined(__hppa) && !HAVE_ATOMIC_H |
1030 | VolatileCounter parisc_atomic_inc(VolatileCounter *v); | |
1031 | VolatileCounter parisc_atomic_dec(VolatileCounter *v); | |
1032 | #endif | |
1033 | ||
5a64ab96 VK |
1034 | /** |
1035 | * Atomically increment 32-bit value by 1 | |
1036 | */ | |
1037 | inline 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 | */ | |
1054 | inline 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 | 1070 | typedef volatile INT32 VolatileCounter; |
7785322f | 1071 | |
22aaa779 VK |
1072 | /** |
1073 | * Atomically increment 32-bit value by 1 | |
1074 | */ | |
7785322f | 1075 | inline 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 | 1096 | inline 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 | */ | |
1121 | class LIBNETXMS_EXPORTABLE Mutex | |
1122 | { | |
1123 | private: | |
1124 | MUTEX m_mutex; | |
1125 | VolatileCounter *m_refCount; | |
1126 | ||
1127 | public: | |
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 | */ | |
1142 | class LIBNETXMS_EXPORTABLE RWLock | |
1143 | { | |
1144 | private: | |
1145 | RWLOCK m_rwlock; | |
1146 | VolatileCounter *m_refCount; | |
1147 | ||
1148 | public: | |
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 | */ | |
1163 | class LIBNETXMS_EXPORTABLE Condition | |
1164 | { | |
1165 | private: | |
1166 | CONDITION m_condition; | |
1167 | VolatileCounter *m_refCount; | |
1168 | ||
1169 | public: | |
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_ */ |