Fixed NetWare compilation issue
[public/netxms.git] / include / nms_threads.h
CommitLineData
54481027 1/*
4997be5c 2** NetXMS - Network Management System
54481027
VK
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
b71bff93
VK
26#ifdef __cplusplus
27
28#define NMS_THREADS_H_INCLUDED
29
54481027
VK
30#ifdef _WIN32
31
018fda4d
AK
32#ifndef UNDER_CE
33# include <process.h>
34#endif
54481027
VK
35
36//
37// Related datatypes and constants
38//
39
dbe67493
VK
40typedef HANDLE MUTEX;
41typedef HANDLE THREAD;
42typedef HANDLE CONDITION;
54481027 43
449e3da9
VK
44#define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
45#define INVALID_CONDITION_HANDLE INVALID_HANDLE_VALUE
ccdbbb52
VK
46#define INVALID_THREAD_HANDLE (NULL)
47
288ddda4
VK
48#ifdef UNDER_CE
49typedef DWORD THREAD_RESULT;
50typedef DWORD THREAD_ID;
51#else
ccdbbb52 52typedef unsigned int THREAD_RESULT;
288ddda4
VK
53typedef unsigned int THREAD_ID;
54#endif
ccdbbb52
VK
55
56#define THREAD_OK 0
288ddda4
VK
57
58#ifdef UNDER_CE
59#define THREAD_CALL
60#else
ccdbbb52 61#define THREAD_CALL __stdcall
288ddda4 62#endif
54481027
VK
63
64
65//
66// Inline functions
67//
68
69inline void ThreadSleep(int iSeconds)
70{
71 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
72}
73
74inline void ThreadSleepMs(DWORD dwMilliseconds)
75{
76 Sleep(dwMilliseconds);
77}
78
ccdbbb52 79inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
54481027 80{
ccdbbb52 81 HANDLE hThread;
288ddda4 82 THREAD_ID dwThreadId;
ccdbbb52 83
f2fdf1b5 84#ifdef UNDER_CE
288ddda4 85 hThread = CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
f2fdf1b5 86#else
ccdbbb52 87 hThread = (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
f2fdf1b5 88#endif
ccdbbb52
VK
89 if (hThread != NULL)
90 CloseHandle(hThread);
91 return (hThread != NULL);
92}
93
94inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
95{
288ddda4 96 THREAD_ID dwThreadId;
ccdbbb52 97
288ddda4
VK
98#ifdef UNDER_CE
99 return CreateThread(NULL, (DWORD)stack_size, start_address, args, 0, &dwThreadId);
631ec742 100#else
288ddda4 101 return (HANDLE)_beginthreadex(NULL, stack_size, start_address, args, 0, &dwThreadId);
631ec742 102#endif
54481027
VK
103}
104
105inline void ThreadExit(void)
106{
f2fdf1b5 107#ifdef UNDER_CE
018fda4d 108 ExitThread(0);
f2fdf1b5
VK
109#else
110 _endthreadex(0);
018fda4d 111#endif
54481027
VK
112}
113
ccdbbb52
VK
114inline void ThreadJoin(THREAD hThread)
115{
116 if (hThread != INVALID_THREAD_HANDLE)
117 {
118 WaitForSingleObject(hThread, INFINITE);
119 CloseHandle(hThread);
120 }
121}
122
54481027
VK
123inline MUTEX MutexCreate(void)
124{
125 return CreateMutex(NULL, FALSE, NULL);
126}
127
a3c76aba
VK
128inline MUTEX MutexCreateRecursive(void)
129{
130 return CreateMutex(NULL, FALSE, NULL);
131}
132
54481027
VK
133inline void MutexDestroy(MUTEX mutex)
134{
135 CloseHandle(mutex);
136}
137
138inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
139{
140 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
141}
142
143inline void MutexUnlock(MUTEX mutex)
144{
145 ReleaseMutex(mutex);
146}
147
d16cf8a5 148inline CONDITION ConditionCreate(BOOL bBroadcast)
54481027 149{
646d58de 150 return CreateEvent(NULL, bBroadcast, FALSE, NULL);
54481027
VK
151}
152
153inline void ConditionDestroy(CONDITION hCond)
154{
155 CloseHandle(hCond);
156}
157
158inline void ConditionSet(CONDITION hCond)
5f743326
VK
159{
160 SetEvent(hCond);
161}
162
163inline void ConditionReset(CONDITION hCond)
164{
165 ResetEvent(hCond);
166}
167
168inline void ConditionPulse(CONDITION hCond)
54481027 169{
39d7a7ed 170 PulseEvent(hCond);
54481027
VK
171}
172
c7f4f5a9 173inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
54481027 174{
c7f4f5a9 175 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
54481027
VK
176}
177
178#else /* _WIN32 */
179
d16cf8a5
AK
180/****************************************************************************/
181/* unix part */
182/****************************************************************************/
183
54481027 184#include <pthread.h>
d16cf8a5
AK
185#include <errno.h>
186#include <sys/time.h>
54481027
VK
187
188//
189// Related datatypes and constants
190//
191
7e679c4b 192typedef pthread_t THREAD;
a3c76aba
VK
193struct netxms_mutex_t
194{
195 pthread_mutex_t mutex;
196#ifndef HAVE_RECURSIVE_MUTEXES
197 BOOL isRecursive;
198 pthread_t owner;
199#endif
200};
201typedef netxms_mutex_t * MUTEX;
202struct netxms_condition_t
d16cf8a5
AK
203{
204 pthread_cond_t cond;
205 pthread_mutex_t mutex;
206 BOOL broadcast;
5f743326 207 BOOL isSet;
d16cf8a5 208};
a3c76aba 209typedef struct netxms_condition_t * CONDITION;
54481027 210
449e3da9
VK
211#define INVALID_MUTEX_HANDLE (NULL)
212#define INVALID_CONDITION_HANDLE (NULL)
ccdbbb52 213#define INVALID_THREAD_HANDLE 0
54481027 214
7e679c4b
AK
215#ifndef INFINITE
216# define INFINITE 0
217#endif
54481027 218
ccdbbb52
VK
219typedef void *THREAD_RESULT;
220
221#define THREAD_OK ((void *)0)
222#define THREAD_CALL
223
224
54481027
VK
225//
226// Inline functions
227//
228
d16cf8a5 229inline void ThreadSleep(int nSeconds)
54481027 230{
22412a01
VK
231#ifdef _NETWARE
232 sleep(nSeconds);
233#else
d16cf8a5
AK
234 struct timeval tv;
235
236 tv.tv_sec = nSeconds;
237 tv.tv_usec = 0;
238
239 select(1, NULL, NULL, NULL, &tv);
22412a01 240#endif
54481027
VK
241}
242
243inline void ThreadSleepMs(DWORD dwMilliseconds)
244{
d16cf8a5 245 // select is a sort of overkill
54481027
VK
246 usleep(dwMilliseconds * 1000); // Convert to microseconds
247}
248
ccdbbb52 249inline BOOL ThreadCreate(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
7e679c4b
AK
250{
251 THREAD id;
252
ccdbbb52 253 if (pthread_create(&id, NULL, start_address, args) == 0)
d1fbf6ba
VK
254 {
255 pthread_detach(id);
ccdbbb52
VK
256 return TRUE;
257 }
258 else
259 {
260 return FALSE;
261 }
262}
263
264inline THREAD ThreadCreateEx(THREAD_RESULT (THREAD_CALL *start_address )(void *), int stack_size, void *args)
265{
35a3a09e 266 THREAD id;
ccdbbb52 267
35a3a09e 268 if (pthread_create(&id, NULL, start_address, args) == 0)
ccdbbb52 269 {
35a3a09e
VK
270 return id;
271 }
d1fbf6ba
VK
272 else
273 {
35a3a09e
VK
274 return INVALID_THREAD_HANDLE;
275 }
7e679c4b
AK
276}
277
278inline void ThreadExit(void)
279{
521d90e7 280 pthread_exit(NULL);
7e679c4b
AK
281}
282
ccdbbb52
VK
283inline void ThreadJoin(THREAD hThread)
284{
285 if (hThread != INVALID_THREAD_HANDLE)
35a3a09e 286 pthread_join(hThread, NULL);
ccdbbb52
VK
287}
288
54481027
VK
289inline MUTEX MutexCreate(void)
290{
291 MUTEX mutex;
292
a3c76aba 293 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
54481027 294 if (mutex != NULL)
8118ecaf 295 pthread_mutex_init(&mutex->mutex, NULL);
a3c76aba
VK
296 return mutex;
297}
298
299inline MUTEX MutexCreateRecursive(void)
300{
301 MUTEX mutex;
302
303 mutex = (MUTEX)malloc(sizeof(netxms_mutex_t));
304 if (mutex != NULL)
305 {
306#ifdef HAVE_RECURSIVE_MUTEXES
307 pthread_mutexattr_t a;
308
309 pthread_mutexattr_init(&a);
310 pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
311 pthread_mutex_init(&mutex->mutex, &a);
312 pthread_mutexattr_destroy(&a);
313#else
314#error FIXME: implement recursive mutexes
315#endif
316 }
54481027
VK
317 return mutex;
318}
319
320inline void MutexDestroy(MUTEX mutex)
321{
a3c76aba
VK
322 if (mutex != NULL)
323 {
324 pthread_mutex_destroy(&mutex->mutex);
54481027
VK
325 free(mutex);
326 }
327}
328
53c17a96 329inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
54481027 330{
d16cf8a5
AK
331 int i;
332 int ret = FALSE;
333
a3c76aba
VK
334 if (mutex != NULL)
335 {
951e884e
AK
336 if (dwTimeOut == INFINITE)
337 {
a3c76aba
VK
338 if (pthread_mutex_lock(&mutex->mutex) == 0)
339 {
d16cf8a5 340 ret = TRUE;
d16cf8a5 341 }
951e884e
AK
342 }
343 else
344 {
a3c76aba
VK
345 for (i = (dwTimeOut / 50) + 1; i > 0; i--)
346 {
347 if (pthread_mutex_trylock(&mutex->mutex) == 0)
8a435919 348 {
951e884e
AK
349 ret = TRUE;
350 break;
351 }
02ed4cf1 352 ThreadSleepMs(50);
951e884e 353 }
d16cf8a5 354 }
7e679c4b 355 }
d16cf8a5 356 return ret;
54481027
VK
357}
358
359inline void MutexUnlock(MUTEX mutex)
360{
8a435919
VK
361 if (mutex != NULL)
362 {
a3c76aba 363 pthread_mutex_unlock(&mutex->mutex);
7e679c4b
AK
364 }
365}
366
d16cf8a5 367inline CONDITION ConditionCreate(BOOL bBroadcast)
7e679c4b
AK
368{
369 CONDITION cond;
370
a3c76aba 371 cond = (CONDITION)malloc(sizeof(struct netxms_condition_t));
8a435919
VK
372 if (cond != NULL)
373 {
d16cf8a5
AK
374 pthread_cond_init(&cond->cond, NULL);
375 pthread_mutex_init(&cond->mutex, NULL);
376 cond->broadcast = bBroadcast;
5f743326 377 cond->isSet = FALSE;
7e679c4b 378 }
d16cf8a5 379
7e679c4b
AK
380 return cond;
381}
382
d16cf8a5 383inline void ConditionDestroy(CONDITION cond)
7e679c4b 384{
5f743326 385 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
386 {
387 pthread_cond_destroy(&cond->cond);
388 pthread_mutex_destroy(&cond->mutex);
389 free(cond);
7e679c4b
AK
390 }
391}
392
d16cf8a5 393inline void ConditionSet(CONDITION cond)
7e679c4b 394{
5f743326 395 if (cond != INVALID_CONDITION_HANDLE)
d16cf8a5
AK
396 {
397 pthread_mutex_lock(&cond->mutex);
5f743326 398 cond->isSet = TRUE;
02ed4cf1 399 if (cond->broadcast)
d16cf8a5
AK
400 {
401 pthread_cond_broadcast(&cond->cond);
402 }
403 else
404 {
405 pthread_cond_signal(&cond->cond);
406 }
407 pthread_mutex_unlock(&cond->mutex);
408 }
7e679c4b
AK
409}
410
5f743326
VK
411inline void ConditionReset(CONDITION cond)
412{
413 if (cond != INVALID_CONDITION_HANDLE)
414 {
415 pthread_mutex_lock(&cond->mutex);
416 cond->isSet = FALSE;
417 pthread_mutex_unlock(&cond->mutex);
418 }
419}
420
421inline void ConditionPulse(CONDITION cond)
422{
423 if (cond != INVALID_CONDITION_HANDLE)
424 {
425 pthread_mutex_lock(&cond->mutex);
426 if (cond->broadcast)
427 {
428 pthread_cond_broadcast(&cond->cond);
429 }
430 else
431 {
432 pthread_cond_signal(&cond->cond);
433 }
434 cond->isSet = FALSE;
435 pthread_mutex_unlock(&cond->mutex);
436 }
437}
438
d16cf8a5 439inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
7e679c4b 440{
d16cf8a5
AK
441 BOOL ret = FALSE;
442
443 if (cond != NULL)
444 {
445 int retcode;
446
447 pthread_mutex_lock(&cond->mutex);
5f743326
VK
448 if (cond->isSet)
449 {
450 ret = TRUE;
451 if (!cond->broadcast)
452 cond->isSet = FALSE;
453 }
454 else
455 {
456 if (dwTimeOut != INFINITE)
457 {
58e7e86f 458#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP || defined(_NETWARE)
5f743326 459 struct timespec timeout;
696fc54f 460
5f743326
VK
461 timeout.tv_sec = dwTimeOut / 1000;
462 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
58e7e86f
VK
463#ifdef _NETWARE
464 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
465#else
5f743326 466 retcode = pthread_cond_reltimedwait_np(&cond->cond, &cond->mutex, &timeout);
58e7e86f 467#endif
696fc54f 468#else
5f743326
VK
469 struct timeval now;
470 struct timespec timeout;
d16cf8a5 471
5f743326
VK
472 // note.
473 // mili - 10^-3
474 // micro - 10^-6
475 // nano - 10^-9
ed452de5 476
5f743326
VK
477 // FIXME there should be more accurate way
478 gettimeofday(&now, NULL);
479 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
1216cc73 480
5f743326
VK
481 now.tv_usec += (dwTimeOut % 1000) * 1000;
482 timeout.tv_sec += now.tv_usec / 1000000;
483 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
ed452de5 484
5f743326 485 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
696fc54f 486#endif
5f743326
VK
487 }
488 else
489 {
490 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
491 }
492
493 if (retcode == 0)
494 {
633907a4
VK
495 if (!cond->broadcast)
496 cond->isSet = FALSE;
5f743326
VK
497 ret = TRUE;
498 }
499 }
7e679c4b 500
d16cf8a5 501 pthread_mutex_unlock(&cond->mutex);
7e679c4b 502 }
d16cf8a5
AK
503
504 return ret;
54481027
VK
505}
506
bff234b8
VK
507inline DWORD GetCurrentProcessId(void)
508{
509 return getpid();
510}
511
54481027
VK
512#endif /* _WIN32 */
513
b71bff93
VK
514#endif /* __cplusplus */
515
54481027 516#endif /* _nms_threads_h_ */