752ffce98fe6292fcfadd70f0f6df681f0020569
[public/netxms.git] / include / nms_threads.h
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2009 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
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 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: nms_threads.h
20 **
21 **/
22
23 #ifndef _nms_threads_h_
24 #define _nms_threads_h_
25
26 #ifdef __cplusplus
27
28 #define NMS_THREADS_H_INCLUDED
29
30 #if defined(_WIN32)
31
32 #ifndef UNDER_CE
33 #include <process.h>
34 #endif
35
36 //
37 // Related datatypes and constants
38 //
39
40 #define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
41 #define INVALID_CONDITION_HANDLE INVALID_HANDLE_VALUE
42 #define INVALID_THREAD_HANDLE (NULL)
43
44 #ifdef UNDER_CE
45 typedef DWORD THREAD_RESULT;
46 typedef DWORD THREAD_ID;
47 #else
48 typedef unsigned int THREAD_RESULT;
49 typedef unsigned int THREAD_ID;
50 #endif
51
52 #define THREAD_OK 0
53
54 #ifdef UNDER_CE
55 #define THREAD_CALL
56 #else
57 #define THREAD_CALL __stdcall
58
59 typedef HANDLE MUTEX;
60 typedef HANDLE CONDITION;
61 struct netxms_thread_t
62 {
63 HANDLE handle;
64 THREAD_ID id;
65 };
66 typedef struct netxms_thread_t *THREAD;
67
68 typedef struct
69 {
70 THREAD_RESULT (THREAD_CALL *start_address)(void *);
71 void *args;
72 } THREAD_START_DATA;
73
74 THREAD_RESULT LIBNETXMS_EXPORTABLE THREAD_CALL SEHThreadStarter(void *);
75 int LIBNETXMS_EXPORTABLE ___ExceptionHandler(EXCEPTION_POINTERS *pInfo);
76
77 void LIBNETXMS_EXPORTABLE SetExceptionHandler(BOOL (*pfHandler)(EXCEPTION_POINTERS *),
78 void (*pfWriter)(const TCHAR *), const TCHAR *pszDumpDir,
79 const TCHAR *pszBaseProcessName, DWORD dwLogMsgCode,
80 BOOL writeFullDump, BOOL printToScreen);
81 BOOL LIBNETXMS_EXPORTABLE SEHDefaultConsoleHandler(EXCEPTION_POINTERS *pInfo);
82 TCHAR LIBNETXMS_EXPORTABLE *SEHExceptionName(DWORD code);
83 void LIBNETXMS_EXPORTABLE SEHShowCallStack(CONTEXT *pCtx);
84
85 void LIBNETXMS_EXPORTABLE SEHServiceExceptionDataWriter(const TCHAR *pszText);
86 BOOL LIBNETXMS_EXPORTABLE SEHServiceExceptionHandler(EXCEPTION_POINTERS *pInfo);
87
88 #define LIBNETXMS_EXCEPTION_HANDLER \
89 } __except(___ExceptionHandler((EXCEPTION_POINTERS *)_exception_info())) { ExitProcess(99); }
90
91 #endif
92
93
94 //
95 // Inline functions
96 //
97
98 inline void InitThreadLibrary(void)
99 {
100 }
101
102 inline void ThreadSleep(int iSeconds)
103 {
104 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
105 }
106
107 inline void ThreadSleepMs(DWORD dwMilliseconds)
108 {
109 Sleep(dwMilliseconds);
110 }
111
112 inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address)(void *), int stack_size, void *args)
113 {
114 HANDLE hThread;
115 THREAD_ID dwThreadId;
116
117 #ifdef UNDER_CE
118 hThread = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
119 #else
120 THREAD_START_DATA *data = (THREAD_START_DATA *)malloc(sizeof(THREAD_START_DATA));
121 data->start_address = start_address;
122 data->args = args;
123 hThread = (HANDLE)_beginthreadex(NULL, stack_size, SEHThreadStarter, data, 0, &dwThreadId);
124 #endif
125 if (hThread != NULL)
126 CloseHandle(hThread);
127 return (hThread != NULL);
128 }
129
130 inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address)(void *), int stack_size, void *args)
131 {
132 THREAD thread;
133
134 thread = (THREAD)malloc(sizeof(struct netxms_thread_t));
135 #ifdef UNDER_CE
136 thread->handle = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &thread->id);
137 if (thread->handle == NULL)
138 {
139 #else
140 THREAD_START_DATA *data = (THREAD_START_DATA *)malloc(sizeof(THREAD_START_DATA));
141 data->start_address = start_address;
142 data->args = args;
143 thread->handle = (HANDLE)_beginthreadex(NULL, stack_size, SEHThreadStarter, data, 0, &thread->id);
144 if ((thread->handle == (HANDLE)-1) || (thread->handle == 0))
145 {
146 free(data);
147 #endif
148 free(thread);
149 thread = INVALID_THREAD_HANDLE;
150 }
151 return thread;
152 }
153
154 inline void ThreadExit(void)
155 {
156 #ifdef UNDER_CE
157 ExitThread(0);
158 #else
159 _endthreadex(0);
160 #endif
161 }
162
163 inline void ThreadJoin(THREAD thread)
164 {
165 if (thread != INVALID_THREAD_HANDLE)
166 {
167 WaitForSingleObject(thread->handle, INFINITE);
168 CloseHandle(thread->handle);
169 free(thread);
170 }
171 }
172
173 inline THREAD_ID ThreadId(THREAD thread)
174 {
175 return (thread != INVALID_THREAD_HANDLE) ? thread->id : 0;
176 }
177
178 inline MUTEX MutexCreate(void)
179 {
180 return CreateMutex(NULL, FALSE, NULL);
181 }
182
183 inline MUTEX MutexCreateRecursive(void)
184 {
185 return CreateMutex(NULL, FALSE, NULL);
186 }
187
188 inline void MutexDestroy(MUTEX mutex)
189 {
190 CloseHandle(mutex);
191 }
192
193 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
194 {
195 if (mutex == INVALID_MUTEX_HANDLE)
196 return FALSE;
197 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
198 }
199
200 inline void MutexUnlock(MUTEX mutex)
201 {
202 ReleaseMutex(mutex);
203 }
204
205 inline CONDITION ConditionCreate(BOOL bBroadcast)
206 {
207 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
208 }
209
210 inline void ConditionDestroy(CONDITION hCond)
211 {
212 CloseHandle(hCond);
213 }
214
215 inline void ConditionSet(CONDITION hCond)
216 {
217 SetEvent(hCond);
218 }
219
220 inline void ConditionReset(CONDITION hCond)
221 {
222 ResetEvent(hCond);
223 }
224
225 inline void ConditionPulse(CONDITION hCond)
226 {
227 PulseEvent(hCond);
228 }
229
230 inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
231 {
232 if (hCond == INVALID_CONDITION_HANDLE)
233 return FALSE;
234 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
235 }
236
237 #elif defined(_USE_GNU_PTH)
238
239 /****************************************************************************/
240 /* GNU Pth */
241 /****************************************************************************/
242
243 //
244 // Related datatypes and constants
245 //
246
247 typedef pth_t THREAD;
248 typedef pth_mutex_t * MUTEX;
249 struct netxms_condition_t
250 {
251 pth_cond_t cond;
252 pth_mutex_t mutex;
253 BOOL broadcast;
254 BOOL isSet;
255 };
256 typedef struct netxms_condition_t * CONDITION;
257
258 #define INVALID_MUTEX_HANDLE (NULL)
259 #define INVALID_CONDITION_HANDLE (NULL)
260 #define INVALID_THREAD_HANDLE (NULL)
261
262 #ifndef INFINITE
263 #define INFINITE 0xFFFFFFFF
264 #endif
265
266 typedef void *THREAD_RESULT;
267
268 #define THREAD_OK ((void *)0)
269 #define THREAD_CALL
270
271
272 //
273 // Inline functions
274 //
275
276 inline void InitThreadLibrary(void)
277 {
278 if (!pth_init())
279 {
280 perror("pth_init() failed");
281 exit(200);
282 }
283 }
284
285 inline void ThreadSleep(int nSeconds)
286 {
287 pth_sleep(nSeconds);
288 }
289
290 inline void ThreadSleepMs(DWORD dwMilliseconds)
291 {
292 pth_usleep(dwMilliseconds * 1000);
293 }
294
295 inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
296 {
297 THREAD id;
298
299 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
300 {
301 pth_attr_set(pth_attr_of(id), PTH_ATTR_JOINABLE, 0);
302 return TRUE;
303 }
304 else
305 {
306 return FALSE;
307 }
308 }
309
310 inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
311 {
312 THREAD id;
313
314 if ((id = pth_spawn(PTH_ATTR_DEFAULT, start_address, args)) != NULL)
315 {
316 return id;
317 }
318 else
319 {
320 return INVALID_THREAD_HANDLE;
321 }
322 }
323
324 inline void ThreadExit(void)
325 {
326 pth_exit(NULL);
327 }
328
329 inline void ThreadJoin(THREAD hThread)
330 {
331 if (hThread != INVALID_THREAD_HANDLE)
332 pth_join(hThread, NULL);
333 }
334
335 inline MUTEX MutexCreate(void)
336 {
337 MUTEX mutex;
338
339 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
340 if (mutex != NULL)
341 {
342 pth_mutex_init(mutex);
343 }
344 return mutex;
345 }
346
347 inline MUTEX MutexCreateRecursive(void)
348 {
349 MUTEX mutex;
350
351 // In libpth, recursive locking is explicitly supported,
352 // so we just create mutex
353 mutex = (MUTEX)malloc(sizeof(pth_mutex_t));
354 if (mutex != NULL)
355 {
356 pth_mutex_init(mutex);
357 }
358 return mutex;
359 }
360
361 inline void MutexDestroy(MUTEX mutex)
362 {
363 if (mutex != NULL)
364 free(mutex);
365 }
366
367 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
368 {
369 int i;
370 int ret = FALSE;
371
372 if (mutex != NULL)
373 {
374 if (dwTimeOut == INFINITE)
375 {
376 if (pth_mutex_acquire(mutex, FALSE, NULL))
377 {
378 ret = TRUE;
379 }
380 }
381 else
382 {
383 pth_event_t ev;
384
385 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
386 if (pth_mutex_acquire(mutex, FALSE, ev))
387 {
388 ret = TRUE;
389 }
390 pth_event_free(ev, PTH_FREE_ALL);
391 }
392 }
393 return ret;
394 }
395
396 inline void MutexUnlock(MUTEX mutex)
397 {
398 if (mutex != NULL)
399 {
400 pth_mutex_release(mutex);
401 }
402 }
403
404 inline CONDITION ConditionCreate(BOOL bBroadcast)
405 {
406 CONDITION cond;
407
408 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
409 if (cond != NULL)
410 {
411 pth_cond_init(&cond->cond);
412 pth_mutex_init(&cond->mutex);
413 cond->broadcast = bBroadcast;
414 cond->isSet = FALSE;
415 }
416
417 return cond;
418 }
419
420 inline void ConditionDestroy(CONDITION cond)
421 {
422 if (cond != INVALID_CONDITION_HANDLE)
423 {
424 free(cond);
425 }
426 }
427
428 inline void ConditionSet(CONDITION cond)
429 {
430 if (cond != INVALID_CONDITION_HANDLE)
431 {
432 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
433 cond->isSet = TRUE;
434 pth_cond_notify(&cond->cond, cond->broadcast);
435 pth_mutex_release(&cond->mutex);
436 }
437 }
438
439 inline void ConditionReset(CONDITION cond)
440 {
441 if (cond != INVALID_CONDITION_HANDLE)
442 {
443 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
444 cond->isSet = FALSE;
445 pth_mutex_release(&cond->mutex);
446 }
447 }
448
449 inline void ConditionPulse(CONDITION cond)
450 {
451 if (cond != INVALID_CONDITION_HANDLE)
452 {
453 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
454 pth_cond_notify(&cond->cond, cond->broadcast);
455 cond->isSet = FALSE;
456 pth_mutex_release(&cond->mutex);
457 }
458 }
459
460 inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
461 {
462 BOOL ret = FALSE;
463
464 if (cond != NULL)
465 {
466 int retcode;
467
468 pth_mutex_acquire(&cond->mutex, FALSE, NULL);
469 if (cond->isSet)
470 {
471 ret = TRUE;
472 if (!cond->broadcast)
473 cond->isSet = FALSE;
474 }
475 else
476 {
477 if (dwTimeOut != INFINITE)
478 {
479 pth_event_t ev;
480
481 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
482 retcode = pth_cond_await(&cond->cond, &cond->mutex, ev);
483 pth_event_free(ev, PTH_FREE_ALL);
484 }
485 else
486 {
487 retcode = pth_cond_await(&cond->cond, &cond->mutex, NULL);
488 }
489
490 if (retcode)
491 {
492 if (!cond->broadcast)
493 cond->isSet = FALSE;
494 ret = TRUE;
495 }
496 }
497
498 pth_mutex_release(&cond->mutex);
499 }
500
501 return ret;
502 }
503
504 inline DWORD GetCurrentProcessId(void)
505 {
506 return getpid();
507 }
508
509 inline THREAD GetCurrentThreadId(void)
510 {
511 return pth_self();
512 }
513
514 #else /* not _WIN32 && not _USE_GNU_PTH */
515
516 /****************************************************************************/
517 /* pthreads */
518 /****************************************************************************/
519
520 #include <pthread.h>
521 #include <errno.h>
522 #include <sys/time.h>
523
524 #if HAVE_PTHREAD_NP_H && !defined(_IPSO)
525 #include <pthread_np.h>
526 #endif
527
528 #if (HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE___PTHREAD_MUTEXATTR_SETTYPE || HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) && \
529 HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE && \
530 (HAVE_DECL_PTHREAD_MUTEX_RECURSIVE || \
531 HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP || \
532 HAVE_DECL_MUTEX_TYPE_COUNTING_FAST)
533
534 #define HAVE_RECURSIVE_MUTEXES 1
535
536 #if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
537 #define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE
538 #elif HAVE_DECL_PTHREAD_MUTEX_RECURSIVE_NP
539 #define MUTEX_RECURSIVE_FLAG PTHREAD_MUTEX_RECURSIVE_NP
540 #elif HAVE_DECL_MUTEX_TYPE_COUNTING_FAST
541 #define MUTEX_RECURSIVE_FLAG MUTEX_TYPE_COUNTING_FAST
542 #else
543 #error Constant used to declare recursive mutex is not known
544 #endif
545
546 #if HAVE_PTHREAD_MUTEXATTR_SETTYPE || HAVE_DECL_PTHREAD_MUTEXATTR_SETTYPE
547 #define MUTEXATTR_SETTYPE pthread_mutexattr_settype
548 #elif HAVE___PTHREAD_MUTEXATTR_SETTYPE
549 #define MUTEXATTR_SETTYPE __pthread_mutexattr_settype
550 #else
551 #define MUTEXATTR_SETTYPE pthread_mutexattr_setkind_np
552 #endif
553
554 #endif
555
556 //
557 // Related datatypes and constants
558 //
559
560 typedef pthread_t THREAD;
561 struct netxms_mutex_t
562 {
563 pthread_mutex_t mutex;
564 #ifndef HAVE_RECURSIVE_MUTEXES
565 BOOL isRecursive;
566 pthread_t owner;
567 #endif
568 };
569 typedef netxms_mutex_t * MUTEX;
570 struct netxms_condition_t
571 {
572 pthread_cond_t cond;
573 pthread_mutex_t mutex;
574 BOOL broadcast;
575 BOOL isSet;
576 };
577 typedef struct netxms_condition_t * CONDITION;
578
579 #define INVALID_MUTEX_HANDLE (NULL)
580 #define INVALID_CONDITION_HANDLE (NULL)
581 #define INVALID_THREAD_HANDLE 0
582
583 #ifndef INFINITE
584 #define INFINITE 0xFFFFFFFF
585 #endif
586
587 typedef void *THREAD_RESULT;
588
589 #define THREAD_OK ((void *)0)
590 #define THREAD_CALL
591
592
593 //
594 // Inline functions
595 //
596
597 inline void InitThreadLibrary(void)
598 {
599 }
600
601 inline void ThreadSleep(int nSeconds)
602 {
603 #ifdef _NETWARE
604 sleep(nSeconds);
605 #else
606 struct timeval tv;
607
608 tv.tv_sec = nSeconds;
609 tv.tv_usec = 0;
610
611 select(1, NULL, NULL, NULL, &tv);
612 #endif
613 }
614
615 inline void ThreadSleepMs(DWORD dwMilliseconds)
616 {
617 #if HAVE_NANOSLEEP && HAVE_DECL_NANOSLEEP
618 struct timespec interval, remainder;
619
620 interval.tv_sec = dwMilliseconds / 1000;
621 interval.tv_nsec = (dwMilliseconds % 1000) * 1000000; // milli -> nano
622 nanosleep(&interval, &remainder);
623 #else
624 usleep(dwMilliseconds * 1000); // Convert to microseconds
625 #endif
626 }
627
628 inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
629 {
630 THREAD id;
631
632 if (stack_size <= 0)
633 {
634 // TODO: Find out minimal stack size
635 stack_size = 1024 * 1024; // 1MB
636 // set stack size to 1mb (it's windows default - and application works,
637 // we need to investigate more on this)
638 }
639 pthread_attr_t attr;
640 pthread_attr_init(&attr);
641 pthread_attr_setstacksize(&attr, stack_size);
642
643 if (pthread_create(&id, &attr, start_address, args) != 0)
644 {
645 id = INVALID_THREAD_HANDLE;
646 }
647
648 pthread_attr_destroy(&attr);
649
650 return id;
651 }
652
653 inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
654 {
655 THREAD id = ThreadCreateEx(start_address, stack_size, args);
656
657 if (id != INVALID_THREAD_HANDLE)
658 {
659 pthread_detach(id);
660 return TRUE;
661 }
662
663 return FALSE;
664 }
665
666 inline void ThreadExit(void)
667 {
668 pthread_exit(NULL);
669 }
670
671 inline void ThreadJoin(THREAD hThread)
672 {
673 if (hThread != INVALID_THREAD_HANDLE)
674 pthread_join(hThread, NULL);
675 }
676
677 inline MUTEX MutexCreate(void)
678 {
679 MUTEX mutex;
680
681 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
682 if (mutex != NULL)
683 {
684 pthread_mutex_init(&mutex->mutex, NULL);
685 #ifndef HAVE_RECURSIVE_MUTEXES
686 mutex->isRecursive = FALSE;
687 #endif
688 }
689 return mutex;
690 }
691
692 inline MUTEX MutexCreateRecursive(void)
693 {
694 MUTEX mutex;
695
696 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
697 if (mutex != NULL)
698 {
699 #ifdef HAVE_RECURSIVE_MUTEXES
700 pthread_mutexattr_t a;
701
702 pthread_mutexattr_init(&a);
703 MUTEXATTR_SETTYPE(&a, MUTEX_RECURSIVE_FLAG);
704 pthread_mutex_init(&mutex->mutex, &a);
705 pthread_mutexattr_destroy(&a);
706 #else
707 mutex->isRecursive = TRUE;
708 #error FIXME: implement recursive mutexes
709 #endif
710 }
711 return mutex;
712 }
713
714 inline void MutexDestroy(MUTEX mutex)
715 {
716 if (mutex != NULL)
717 {
718 pthread_mutex_destroy(&mutex->mutex);
719 free(mutex);
720 }
721 }
722
723 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
724 {
725 int i;
726 int ret = FALSE;
727
728 if (mutex != NULL)
729 {
730 if (dwTimeOut == INFINITE)
731 {
732 if (pthread_mutex_lock(&mutex->mutex) == 0)
733 {
734 ret = TRUE;
735 }
736 }
737 else
738 {
739 for (i = (dwTimeOut / 50) + 1; i > 0; i--)
740 {
741 if (pthread_mutex_trylock(&mutex->mutex) == 0)
742 {
743 ret = TRUE;
744 break;
745 }
746 ThreadSleepMs(50);
747 }
748 }
749 }
750 return ret;
751 }
752
753 inline void MutexUnlock(MUTEX mutex)
754 {
755 if (mutex != NULL)
756 {
757 pthread_mutex_unlock(&mutex->mutex);
758 }
759 }
760
761 inline CONDITION ConditionCreate(BOOL bBroadcast)
762 {
763 CONDITION cond;
764
765 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
766 if (cond != NULL)
767 {
768 pthread_cond_init(&cond->cond, NULL);
769 pthread_mutex_init(&cond->mutex, NULL);
770 cond->broadcast = bBroadcast;
771 cond->isSet = FALSE;
772 }
773
774 return cond;
775 }
776
777 inline void ConditionDestroy(CONDITION cond)
778 {
779 if (cond != INVALID_CONDITION_HANDLE)
780 {
781 pthread_cond_destroy(&cond->cond);
782 pthread_mutex_destroy(&cond->mutex);
783 free(cond);
784 }
785 }
786
787 inline void ConditionSet(CONDITION cond)
788 {
789 if (cond != INVALID_CONDITION_HANDLE)
790 {
791 pthread_mutex_lock(&cond->mutex);
792 cond->isSet = TRUE;
793 if (cond->broadcast)
794 {
795 pthread_cond_broadcast(&cond->cond);
796 }
797 else
798 {
799 pthread_cond_signal(&cond->cond);
800 }
801 pthread_mutex_unlock(&cond->mutex);
802 }
803 }
804
805 inline void ConditionReset(CONDITION cond)
806 {
807 if (cond != INVALID_CONDITION_HANDLE)
808 {
809 pthread_mutex_lock(&cond->mutex);
810 cond->isSet = FALSE;
811 pthread_mutex_unlock(&cond->mutex);
812 }
813 }
814
815 inline void ConditionPulse(CONDITION cond)
816 {
817 if (cond != INVALID_CONDITION_HANDLE)
818 {
819 pthread_mutex_lock(&cond->mutex);
820 if (cond->broadcast)
821 {
822 pthread_cond_broadcast(&cond->cond);
823 }
824 else
825 {
826 pthread_cond_signal(&cond->cond);
827 }
828 cond->isSet = FALSE;
829 pthread_mutex_unlock(&cond->mutex);
830 }
831 }
832
833 inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
834 {
835 BOOL ret = FALSE;
836
837 if (cond != NULL)
838 {
839 int retcode;
840
841 pthread_mutex_lock(&cond->mutex);
842 if (cond->isSet)
843 {
844 ret = TRUE;
845 if (!cond->broadcast)
846 cond->isSet = FALSE;
847 }
848 else
849 {
850 if (dwTimeOut != INFINITE)
851 {
852 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
853 struct timespec timeout;
854
855 timeout.tv_sec = dwTimeOut / 1000;
856 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
857 #ifdef _NETWARE
858 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
859 #else
860 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
861 #endif
862 #else
863 struct timeval now;
864 struct timespec timeout;
865
866 // note.
867 // mili - 10^-3
868 // micro - 10^-6
869 // nano - 10^-9
870
871 // FIXME there should be more accurate way
872 gettimeofday(&now, NULL);
873 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
874
875 now.tv_usec += (dwTimeOut % 1000) * 1000;
876 timeout.tv_sec += now.tv_usec / 1000000;
877 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
878
879 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
880 #endif
881 }
882 else
883 {
884 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
885 }
886
887 if (retcode == 0)
888 {
889 if (!cond->broadcast)
890 cond->isSet = FALSE;
891 ret = TRUE;
892 }
893 }
894
895 pthread_mutex_unlock(&cond->mutex);
896 }
897
898 return ret;
899 }
900
901 inline DWORD GetCurrentProcessId(void)
902 {
903 return getpid();
904 }
905
906 inline THREAD GetCurrentThreadId(void)
907 {
908 return pthread_self();
909 }
910
911 #endif /* _WIN32 */
912
913 #include <rwlock.h>
914
915 #endif /* __cplusplus */
916
917 #endif /* _nms_threads_h_ */