+ conditions should work
[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 _WIN32
27
28 #include <process.h>
29
30 //
31 // Related datatypes and constants
32 //
33
34 #define MUTEX HANDLE
35 #define THREAD HANDLE
36 #define CONDITION HANDLE
37
38 #define INVALID_MUTEX_HANDLE INVALID_HANDLE_VALUE
39
40
41 //
42 // Inline functions
43 //
44
45 inline void ThreadSleep(int iSeconds)
46 {
47 Sleep((DWORD)iSeconds * 1000); // Convert to milliseconds
48 }
49
50 inline void ThreadSleepMs(DWORD dwMilliseconds)
51 {
52 Sleep(dwMilliseconds);
53 }
54
55 inline THREAD ThreadCreate(void (__cdecl *start_address )(void *), int stack_size, void *args)
56 {
57 return (THREAD)_beginthread(start_address, stack_size, args);
58 }
59
60 inline void ThreadExit(void)
61 {
62 _endthread();
63 }
64
65 inline MUTEX MutexCreate(void)
66 {
67 return CreateMutex(NULL, FALSE, NULL);
68 }
69
70 inline void MutexDestroy(MUTEX mutex)
71 {
72 CloseHandle(mutex);
73 }
74
75 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
76 {
77 return WaitForSingleObject(mutex, dwTimeOut) == WAIT_OBJECT_0;
78 }
79
80 inline void MutexUnlock(MUTEX mutex)
81 {
82 ReleaseMutex(mutex);
83 }
84
85 inline CONDITION ConditionCreate(BOOL bBroadcast)
86 {
87 if (bBroadcast == TRUE)
88 {
89 return CreateEvent(NULL, TRUE, FALSE, NULL);
90 }
91 else
92 {
93 return CreateEvent(NULL, FALSE, FALSE, NULL);
94 }
95 }
96
97 inline void ConditionDestroy(CONDITION hCond)
98 {
99 CloseHandle(hCond);
100 }
101
102 inline void ConditionSet(CONDITION hCond)
103 {
104 SetEvent(hCond);
105 }
106
107 inline BOOL ConditionWait(CONDITION hCond, DWORD dwTimeOut)
108 {
109 return WaitForSingleObject(hCond, dwTimeOut) == WAIT_OBJECT_0;
110 }
111
112 #else /* _WIN32 */
113
114 /****************************************************************************/
115 /* unix part */
116 /****************************************************************************/
117
118 #include <pthread.h>
119 #include <errno.h>
120 #include <sys/time.h>
121
122 //
123 // Related datatypes and constants
124 //
125
126 typedef pthread_t THREAD;
127 typedef pthread_mutex_t * MUTEX;
128 struct condition_t
129 {
130 pthread_cond_t cond;
131 pthread_mutex_t mutex;
132 BOOL broadcast;
133 };
134 typedef struct condition_t * CONDITION;
135
136 #define INVALID_MUTEX_HANDLE NULL
137
138 #ifndef INFINITE
139 # define INFINITE 0
140 #endif
141
142 //
143 // Inline functions
144 //
145
146 inline void ThreadSleep(int nSeconds)
147 {
148 struct timeval tv;
149
150 tv.tv_sec = nSeconds;
151 tv.tv_usec = 0;
152
153 select(1, NULL, NULL, NULL, &tv);
154 }
155
156 inline void ThreadSleepMs(DWORD dwMilliseconds)
157 {
158 // select is a sort of overkill
159 usleep(dwMilliseconds * 1000); // Convert to microseconds
160 }
161
162 inline THREAD ThreadCreate(void (*start_address )(void *), int stack_size, void *args)
163 {
164 THREAD id;
165
166 if (pthread_create(&id, NULL, (void *(*)(void *))start_address, args) == 0) {
167 return id;
168 } else {
169 return 0;
170 }
171 }
172
173 inline void ThreadExit(void)
174 {
175 pthread_kill(pthread_self(), 15); // 9?
176 }
177
178 inline MUTEX MutexCreate(void)
179 {
180 MUTEX mutex;
181
182 mutex = (MUTEX)malloc(sizeof(pthread_mutex_t));
183 if (mutex != NULL)
184 pthread_mutex_init(mutex, NULL);
185 return mutex;
186 }
187
188 inline void MutexDestroy(MUTEX mutex)
189 {
190 if (mutex != NULL) {
191 pthread_mutex_destroy(mutex);
192 free(mutex);
193 }
194 }
195
196 inline BOOL MutexLock(MUTEX mutex, DWORD dwTimeOut)
197 {
198 int i;
199 int ret = FALSE;
200
201 if (mutex != NULL) {
202 // FIXME: hack, always waiting a bit longer
203 for (i = (dwTimeOut / 50) + 1; i > 0; i--) {
204 if (pthread_mutex_trylock(mutex) != EBUSY) {
205 ret = TRUE;
206 break;
207 }
208 ThreadSleep(50);
209 }
210 }
211 return ret;
212 }
213
214 inline void MutexUnlock(MUTEX mutex)
215 {
216 if (mutex != NULL) {
217 pthread_mutex_unlock(mutex);
218 }
219 }
220
221 inline CONDITION ConditionCreate(BOOL bBroadcast)
222 {
223 CONDITION cond;
224
225 cond = (CONDITION)malloc(sizeof(struct condition_t));
226 if (cond != NULL) {
227 pthread_cond_init(&cond->cond, NULL);
228 pthread_mutex_init(&cond->mutex, NULL);
229 cond->broadcast = bBroadcast;
230 }
231
232 return cond;
233 }
234
235 inline void ConditionDestroy(CONDITION cond)
236 {
237 if (cond != NULL)
238 {
239 pthread_cond_destroy(&cond->cond);
240 pthread_mutex_destroy(&cond->mutex);
241 free(cond);
242 }
243 }
244
245 inline void ConditionSet(CONDITION cond)
246 {
247 if (cond != NULL)
248 {
249 pthread_mutex_lock(&cond->mutex);
250 if (cond->broadcast == TRUE)
251 {
252 pthread_cond_broadcast(&cond->cond);
253 }
254 else
255 {
256 pthread_cond_signal(&cond->cond);
257 }
258 pthread_mutex_unlock(&cond->mutex);
259 }
260 }
261
262 inline BOOL ConditionWait(CONDITION cond, DWORD dwTimeOut)
263 {
264 BOOL ret = FALSE;
265
266 if (cond != NULL)
267 {
268 int retcode;
269
270 pthread_mutex_lock(&cond->mutex);
271
272 if (dwTimeOut != INFINITE)
273 {
274 struct timeval now;
275 struct timespec timeout;
276
277 gettimeofday(&now, NULL);
278 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
279 timeout.tv_nsec = ( now.tv_usec + ( dwTimeOut % 1000 ) ) * 1000;
280 while (retcode != ETIMEDOUT) {
281 retcode = pthread_cond_timedwait(&cond->cond, &cond->mutex, &timeout);
282 }
283 }
284 else
285 {
286 retcode = pthread_cond_wait(&cond->cond, &cond->mutex);
287 }
288
289 pthread_mutex_unlock(&cond->mutex);
290
291 if (retcode == 0)
292 {
293 ret = TRUE;
294 }
295 }
296
297 return ret;
298 }
299
300 #endif /* _WIN32 */
301
302 #endif /* _nms_threads_h_ */