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