/src/dcmtk/ofstd/libsrc/ofthread.cc
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (C) 2000-2021, OFFIS e.V. |
4 | | * All rights reserved. See COPYRIGHT file for details. |
5 | | * |
6 | | * This software and supporting documentation were developed by |
7 | | * |
8 | | * OFFIS e.V. |
9 | | * R&D Division Health |
10 | | * Escherweg 2 |
11 | | * D-26121 Oldenburg, Germany |
12 | | * |
13 | | * |
14 | | * Module: ofstd |
15 | | * |
16 | | * Author: Marco Eichelberg |
17 | | * |
18 | | * Purpose: Provides operating system independent abstractions for basic |
19 | | * multi-thread concepts: threads, thread specific data, |
20 | | * semaphores, mutexes and read/write locks. The implementation |
21 | | * of these classes supports the Solaris, POSIX and Win32 |
22 | | * multi-thread APIs. |
23 | | * |
24 | | */ |
25 | | |
26 | | #include "dcmtk/config/osconfig.h" |
27 | | |
28 | | /* if WITH_THREADS is undefined, we don't even attempt to implement a thread interface. */ |
29 | | #ifdef WITH_THREADS |
30 | | |
31 | | #include "dcmtk/ofstd/ofstd.h" |
32 | | |
33 | | #ifdef _DARWIN_C_SOURCE |
34 | | #define DARWIN_INTERFACE |
35 | | extern "C" { |
36 | | #include <dispatch/dispatch.h> |
37 | | } |
38 | | #endif /* _DARWIN_C_SOURCE */ |
39 | | |
40 | | #ifdef HAVE_WINDOWS_H |
41 | | #define WINDOWS_INTERFACE |
42 | | #define WIN32_LEAN_AND_MEAN |
43 | | |
44 | | extern "C" { |
45 | | #include <windows.h> |
46 | | #include <process.h> |
47 | | } |
48 | | |
49 | | #elif defined(HAVE_THREAD_H) && defined(HAVE_SYNCH_H) |
50 | | #define SOLARIS_INTERFACE |
51 | | extern "C" { |
52 | | #include <thread.h> |
53 | | #include <synch.h> /* for read/write locks, semaphores and mutexes */ |
54 | | } |
55 | | |
56 | | #elif defined(HAVE_PTHREAD_H) && defined(HAVE_SEMAPHORE_H) |
57 | | #define POSIX_INTERFACE |
58 | | #if !defined(HAVE_PTHREAD_RWLOCK) || defined(__ANDROID__) |
59 | | // not all POSIX pthread implementations provide read/write locks |
60 | | // the android implementation seems to be insufficient |
61 | | #define POSIX_INTERFACE_WITHOUT_RWLOCK |
62 | | #endif |
63 | | extern "C" { |
64 | | #include <pthread.h> /* for threads, read/write locks and mutexes*/ |
65 | | #include <semaphore.h> /* for semaphores */ |
66 | | } |
67 | | #endif |
68 | | |
69 | | #endif /* WITH_THREADS */ |
70 | | |
71 | | #include "dcmtk/ofstd/ofthread.h" |
72 | | #include "dcmtk/ofstd/ofconsol.h" |
73 | | #include "dcmtk/ofstd/ofstring.h" |
74 | | #include <cerrno> |
75 | | |
76 | | // The Posix interfaces are not always correctly declared as volatile, |
77 | | // so we need a two-step cast from our internal representation |
78 | | // as a volatile void * to the Posix representation such as pthread_key_t * |
79 | | |
80 | 1.78M | #define OFthread_cast(x,y) OFreinterpret_cast(x, OFconst_cast(void *, y)) |
81 | | |
82 | | /* ------------------------------------------------------------------------- */ |
83 | | |
84 | | /* Thread stub function - called by the thread creation system function. |
85 | | * Calls the run() method of the OFString class and returns. |
86 | | */ |
87 | | |
88 | | |
89 | | #ifdef HAVE_WINDOWS_H |
90 | | unsigned int __stdcall thread_stub(void *arg) |
91 | | { |
92 | | OFstatic_cast(OFThread *, arg)->run(); |
93 | | return 0; // thread terminates |
94 | | } |
95 | | #else |
96 | | void *thread_stub(void *arg) |
97 | 0 | { |
98 | 0 | OFstatic_cast(OFThread *, arg)->run(); |
99 | 0 | return NULL; // thread terminates |
100 | 0 | } |
101 | | #endif |
102 | | |
103 | | /* ------------------------------------------------------------------------- */ |
104 | | |
105 | | #ifdef WINDOWS_INTERFACE |
106 | | const int OFThread::busy = -1; |
107 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
108 | | const int OFThread::busy = ESRCH; |
109 | | #else |
110 | | const int OFThread::busy = -2; |
111 | | #endif |
112 | | |
113 | | OFThread::OFThread() |
114 | | #ifdef WINDOWS_INTERFACE |
115 | | : theThreadHandle(0) |
116 | | , theThread(0) |
117 | | #else |
118 | 0 | : theThread(0) |
119 | | #endif |
120 | 0 | { |
121 | 0 | } |
122 | | |
123 | | OFThread::~OFThread() |
124 | 0 | { |
125 | | #ifdef WINDOWS_INTERFACE |
126 | | CloseHandle(OFreinterpret_cast(HANDLE, theThreadHandle)); |
127 | | #endif |
128 | 0 | } |
129 | | |
130 | | int OFThread::start() |
131 | 0 | { |
132 | | #ifdef WINDOWS_INTERFACE |
133 | | unsigned int tid = 0; |
134 | | theThreadHandle = _beginthreadex(NULL, 0, thread_stub, OFstatic_cast(void *, this), 0, &tid); |
135 | | if (theThreadHandle == 0) return errno; else |
136 | | { |
137 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
138 | | theThread = OFreinterpret_cast(void *, tid); |
139 | | #else |
140 | | theThread = tid; |
141 | | #endif |
142 | | return 0; |
143 | | } |
144 | | #elif defined(POSIX_INTERFACE) |
145 | | pthread_t tid = 0; |
146 | 0 | int result = pthread_create(&tid, NULL, thread_stub, OFstatic_cast(void *, this)); |
147 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
148 | | if (0 == result) theThread = OFstatic_cast(void *, tid); else theThread = 0; |
149 | | #else |
150 | 0 | if (0 == result) theThread = OFstatic_cast(unsigned long, tid); else theThread = 0; |
151 | 0 | #endif |
152 | 0 | return result; |
153 | | #elif defined(SOLARIS_INTERFACE) |
154 | | thread_t tid=0; |
155 | | int result = thr_create(NULL, 0, thread_stub, OFstatic_cast(void *, this), 0, &tid); |
156 | | if (0 == result) theThread = OFstatic_cast(unsigned long, tid); else theThread = 0; |
157 | | return result; |
158 | | #else |
159 | | return -1; |
160 | | #endif |
161 | 0 | } |
162 | | |
163 | | int OFThread::join() |
164 | 0 | { |
165 | | #ifdef WINDOWS_INTERFACE |
166 | | if (WaitForSingleObject(OFreinterpret_cast(HANDLE, theThreadHandle), INFINITE) == WAIT_OBJECT_0) return 0; |
167 | | else return OFstatic_cast(int, GetLastError()); |
168 | | #elif defined(POSIX_INTERFACE) |
169 | 0 | void *retcode=NULL; |
170 | 0 | return pthread_join(OFstatic_cast(pthread_t, theThread), &retcode); |
171 | | #elif defined(SOLARIS_INTERFACE) |
172 | | void *retcode=NULL; |
173 | | return thr_join(OFstatic_cast(thread_t, theThread), NULL, &retcode); |
174 | | #else |
175 | | return -1; |
176 | | #endif |
177 | 0 | } |
178 | | |
179 | | unsigned long OFThread::threadID() |
180 | 0 | { |
181 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
182 | | // dangerous - we cast a pointer type to unsigned long and hope that it |
183 | | // remains valid after casting back to a pointer type. |
184 | | return OFreinterpret_cast(unsigned long, theThread); |
185 | | #else |
186 | 0 | return theThread; |
187 | 0 | #endif |
188 | 0 | } |
189 | | |
190 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
191 | | OFBool OFThread::equal(unsigned long tID) |
192 | | #else |
193 | | OFBool OFThread::equal(unsigned long /* tID */ ) |
194 | | #endif |
195 | 0 | { |
196 | | #ifdef WINDOWS_INTERFACE |
197 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
198 | | if (theThread == OFreinterpret_cast(void *, tID)) return OFTrue; else return OFFalse; |
199 | | #else |
200 | | if (theThread == tID) return OFTrue; else return OFFalse; |
201 | | #endif |
202 | | #elif defined(POSIX_INTERFACE) |
203 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
204 | | // dangerous - we cast an unsigned long back to a pointer type and hope that it is still valid |
205 | | if (pthread_equal(OFstatic_cast(pthread_t, theThread), OFreinterpret_cast(pthread_t, tID))) return OFTrue; else return OFFalse; |
206 | | #else |
207 | 0 | if (pthread_equal(OFstatic_cast(pthread_t, theThread), OFstatic_cast(pthread_t, tID))) return OFTrue; else return OFFalse; |
208 | 0 | #endif |
209 | | #elif defined(SOLARIS_INTERFACE) |
210 | | if (OFstatic_cast(thread_t, theThread) == OFstatic_cast(thread_t, tID)) return OFTrue; else return OFFalse; |
211 | | #else |
212 | | return 0; |
213 | | #endif |
214 | 0 | } |
215 | | |
216 | | void OFThread::thread_exit() |
217 | 0 | { |
218 | | #ifdef WINDOWS_INTERFACE |
219 | | _endthreadex(0); |
220 | | #elif defined(POSIX_INTERFACE) |
221 | 0 | pthread_exit(NULL); |
222 | | #elif defined(SOLARIS_INTERFACE) |
223 | | thr_exit(NULL); |
224 | | #else |
225 | | #endif |
226 | 0 | return; // will never be reached |
227 | 0 | } |
228 | | |
229 | | unsigned long OFThread::self() |
230 | 0 | { |
231 | | #ifdef WINDOWS_INTERFACE |
232 | | return OFstatic_cast(unsigned long, GetCurrentThreadId()); |
233 | | #elif defined(POSIX_INTERFACE) |
234 | | #ifdef HAVE_POINTER_TYPE_PTHREAD_T |
235 | | return OFreinterpret_cast(unsigned long, pthread_self()); |
236 | | #else |
237 | 0 | return OFstatic_cast(unsigned long, pthread_self()); |
238 | 0 | #endif |
239 | | #elif defined(SOLARIS_INTERFACE) |
240 | | return OFstatic_cast(unsigned long, thr_self()); |
241 | | #else |
242 | | return 0; |
243 | | #endif |
244 | 0 | } |
245 | | |
246 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
247 | | void OFThread::errorstr(OFString& description, int code) |
248 | | #else |
249 | | void OFThread::errorstr(OFString& description, int /* code */ ) |
250 | | #endif |
251 | 0 | { |
252 | | #ifdef WINDOWS_INTERFACE |
253 | | if (code == OFThread::busy) description = "another thread already waiting for join"; else |
254 | | { |
255 | | LPVOID buf; |
256 | | FormatMessage( |
257 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
258 | | NULL, OFstatic_cast(DWORD, code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
259 | | OFreinterpret_cast(LPTSTR, &buf), 0, NULL); |
260 | | if (buf) description = OFstatic_cast(const char *, buf); |
261 | | LocalFree(buf); |
262 | | } |
263 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
264 | | char buf[256]; |
265 | 0 | const char *str = OFStandard::strerror(code, buf, sizeof(buf)); |
266 | 0 | if (str) description = str; else description.clear(); |
267 | | #else |
268 | | description = "error: threads not implemented"; |
269 | | #endif |
270 | 0 | return; |
271 | 0 | } |
272 | | |
273 | | /* ------------------------------------------------------------------------- */ |
274 | | |
275 | | |
276 | | OFThreadSpecificData::OFThreadSpecificData() |
277 | 0 | : theKey(NULL) |
278 | 0 | { |
279 | | #ifdef WINDOWS_INTERFACE |
280 | | DWORD *key = new DWORD; |
281 | | if (key) |
282 | | { |
283 | | *key = TlsAlloc(); |
284 | | if (*key == OFstatic_cast(DWORD, -1)) delete key; |
285 | | else theKey=key; |
286 | | } |
287 | | #elif defined(POSIX_INTERFACE) |
288 | | pthread_key_t *key = new pthread_key_t; |
289 | 0 | if (key) |
290 | 0 | { |
291 | 0 | if (pthread_key_create(key, NULL)) delete key; |
292 | 0 | else theKey=key; |
293 | 0 | } |
294 | | #elif defined(SOLARIS_INTERFACE) |
295 | | thread_key_t *key = new thread_key_t; |
296 | | if (key) |
297 | | { |
298 | | if (thr_keycreate(key, NULL)) delete key; |
299 | | else theKey=key; |
300 | | } |
301 | | #else |
302 | | #endif |
303 | 0 | } |
304 | | |
305 | | OFThreadSpecificData::~OFThreadSpecificData() |
306 | 0 | { |
307 | | #ifdef WINDOWS_INTERFACE |
308 | | if (theKey) TlsFree(* OFthread_cast(DWORD *, theKey)); |
309 | | #elif defined(POSIX_INTERFACE) |
310 | 0 | delete OFthread_cast(pthread_key_t *, theKey); |
311 | | #elif defined(SOLARIS_INTERFACE) |
312 | | delete OFthread_cast(thread_key_t *, theKey); |
313 | | #else |
314 | | #endif |
315 | 0 | theKey = NULL; |
316 | 0 | } |
317 | | |
318 | | OFBool OFThreadSpecificData::initialized() const |
319 | 0 | { |
320 | 0 | #ifdef WITH_THREADS |
321 | 0 | if (theKey) return OFTrue; else return OFFalse; |
322 | | #else |
323 | | return OFFalse; // thread specific data is not supported if we are working in a single-thread environment |
324 | | #endif |
325 | 0 | } |
326 | | |
327 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
328 | | int OFThreadSpecificData::set(void *value) |
329 | | #else |
330 | | int OFThreadSpecificData::set(void * /* value */ ) |
331 | | #endif |
332 | 0 | { |
333 | | #ifdef WINDOWS_INTERFACE |
334 | | if (theKey) |
335 | | { |
336 | | if (0 == TlsSetValue(*(OFthread_cast(DWORD *, theKey)), value)) return OFstatic_cast(int, GetLastError()); else return 0; |
337 | | } else return ERROR_INVALID_HANDLE; |
338 | | #elif defined(POSIX_INTERFACE) |
339 | 0 | if (theKey) return pthread_setspecific(* OFthread_cast(pthread_key_t *, theKey), value); else return EINVAL; |
340 | | #elif defined(SOLARIS_INTERFACE) |
341 | | if (theKey) return thr_setspecific(* OFthread_cast(thread_key_t *, theKey), value); else return EINVAL; |
342 | | #else |
343 | | return -1; |
344 | | #endif |
345 | 0 | } |
346 | | |
347 | | int OFThreadSpecificData::get(void *&value) |
348 | 0 | { |
349 | | #ifdef WINDOWS_INTERFACE |
350 | | if (theKey) |
351 | | { |
352 | | value = TlsGetValue(*(OFthread_cast(DWORD *, theKey))); |
353 | | return 0; |
354 | | } else { |
355 | | value = NULL; |
356 | | return ERROR_INVALID_HANDLE; |
357 | | } |
358 | | #elif defined(POSIX_INTERFACE) |
359 | 0 | if (theKey) |
360 | 0 | { |
361 | 0 | value = pthread_getspecific(* OFthread_cast(pthread_key_t *, theKey)); |
362 | 0 | return 0; |
363 | 0 | } else { |
364 | 0 | value = NULL; |
365 | 0 | return EINVAL; |
366 | 0 | } |
367 | | #elif defined(SOLARIS_INTERFACE) |
368 | | value = NULL; |
369 | | if (theKey) return thr_getspecific(* OFthread_cast(thread_key_t *, theKey), &value); else return EINVAL; |
370 | | #else |
371 | | value = NULL; |
372 | | return -1; |
373 | | #endif |
374 | 0 | } |
375 | | |
376 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
377 | | void OFThreadSpecificData::errorstr(OFString& description, int code) |
378 | | #else |
379 | | void OFThreadSpecificData::errorstr(OFString& description, int /* code */ ) |
380 | | #endif |
381 | 0 | { |
382 | | #ifdef WINDOWS_INTERFACE |
383 | | LPVOID buf; |
384 | | FormatMessage( |
385 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
386 | | NULL, OFstatic_cast(DWORD, code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
387 | | OFreinterpret_cast(LPTSTR, &buf), 0, NULL); |
388 | | if (buf) description = OFstatic_cast(const char *, buf); |
389 | | LocalFree(buf); |
390 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
391 | | char buf[256]; |
392 | 0 | const char *str = OFStandard::strerror(code, buf, sizeof(buf)); |
393 | 0 | if (str) description = str; else description.clear(); |
394 | | #else |
395 | | description = "error: thread specific data not implemented"; |
396 | | #endif |
397 | 0 | return; |
398 | 0 | } |
399 | | |
400 | | /* ------------------------------------------------------------------------- */ |
401 | | |
402 | | #ifdef WINDOWS_INTERFACE |
403 | | const int OFSemaphore::busy = -1; |
404 | | #elif defined(DARWIN_INTERFACE) |
405 | | const int OFSemaphore::busy = EAGAIN; |
406 | | #elif defined(POSIX_INTERFACE) |
407 | | const int OFSemaphore::busy = EAGAIN; // Posix returns EAGAIN instead of EBUSY in trywait. |
408 | | #elif defined(SOLARIS_INTERFACE) |
409 | | const int OFSemaphore::busy = EBUSY; |
410 | | #else |
411 | | const int OFSemaphore::busy = -2; |
412 | | #endif |
413 | | |
414 | | |
415 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) || defined(DARWIN_INTERFACE) |
416 | | OFSemaphore::OFSemaphore(unsigned int numResources) |
417 | | #else |
418 | | OFSemaphore::OFSemaphore(unsigned int /* numResources */ ) |
419 | | #endif |
420 | 0 | : theSemaphore(NULL) |
421 | 0 | { |
422 | | #ifdef WINDOWS_INTERFACE |
423 | | theSemaphore = OFstatic_cast(void *, CreateSemaphore(NULL, numResources, numResources, NULL)); |
424 | | #elif defined(DARWIN_INTERFACE) |
425 | | dispatch_semaphore_t *sem = new dispatch_semaphore_t; |
426 | | if (sem) |
427 | | { |
428 | | *sem = dispatch_semaphore_create(numResources); |
429 | | if (*sem == NULL) delete sem; |
430 | | else theSemaphore = sem; |
431 | | } |
432 | | #elif defined(POSIX_INTERFACE) |
433 | | sem_t *sem = new sem_t; |
434 | 0 | if (sem) |
435 | 0 | { |
436 | 0 | if (sem_init(sem, 0, numResources) == -1) delete sem; |
437 | 0 | else theSemaphore = sem; |
438 | 0 | } |
439 | | #elif defined(SOLARIS_INTERFACE) |
440 | | sema_t *sem = new sema_t; |
441 | | if (sem) |
442 | | { |
443 | | if (sema_init(sem, numResources, USYNC_THREAD, NULL)) delete sem; |
444 | | else theSemaphore = sem; |
445 | | } |
446 | | #else |
447 | | #endif |
448 | 0 | } |
449 | | |
450 | | OFSemaphore::~OFSemaphore() |
451 | 0 | { |
452 | | #ifdef WINDOWS_INTERFACE |
453 | | CloseHandle(OFthread_cast(HANDLE, theSemaphore)); |
454 | | #elif defined(DARWIN_INTERFACE) |
455 | | delete OFthread_cast(dispatch_semaphore_t *, theSemaphore); |
456 | | #elif defined(POSIX_INTERFACE) |
457 | 0 | if (theSemaphore) sem_destroy(OFthread_cast(sem_t *, theSemaphore)); |
458 | 0 | delete OFthread_cast(sem_t *, theSemaphore); |
459 | | #elif defined(SOLARIS_INTERFACE) |
460 | | if (theSemaphore) sema_destroy(OFthread_cast(sema_t *, theSemaphore)); |
461 | | delete OFthread_cast(sema_t *, theSemaphore); |
462 | | #else |
463 | | #endif |
464 | 0 | theSemaphore = NULL; |
465 | 0 | } |
466 | | |
467 | | OFBool OFSemaphore::initialized() const |
468 | 0 | { |
469 | 0 | #ifdef WITH_THREADS |
470 | 0 | if (theSemaphore) return OFTrue; else return OFFalse; |
471 | | #else |
472 | | return OFTrue; |
473 | | #endif |
474 | 0 | } |
475 | | |
476 | | int OFSemaphore::wait() |
477 | 0 | { |
478 | | #ifdef WINDOWS_INTERFACE |
479 | | if (WaitForSingleObject(OFthread_cast(HANDLE, theSemaphore), INFINITE) == WAIT_OBJECT_0) return 0; |
480 | | else return OFstatic_cast(int, GetLastError()); |
481 | | #elif defined(DARWIN_INTERFACE) |
482 | | if (theSemaphore) |
483 | | { |
484 | | // Always succeeds (returns zero) if the timeout is DISPATCH_TIME_FOREVER. |
485 | | return dispatch_semaphore_wait(*OFthread_cast(dispatch_semaphore_t *, theSemaphore), DISPATCH_TIME_FOREVER); |
486 | | } else return EINVAL; |
487 | | #elif defined(POSIX_INTERFACE) |
488 | 0 | if (theSemaphore) |
489 | 0 | { |
490 | 0 | if (sem_wait(OFthread_cast(sem_t *, theSemaphore))) return errno; else return 0; |
491 | 0 | } else return EINVAL; |
492 | | #elif defined(SOLARIS_INTERFACE) |
493 | | if (theSemaphore) return sema_wait(OFthread_cast(sema_t *, theSemaphore)); else return EINVAL; |
494 | | #else |
495 | | return -1; |
496 | | #endif |
497 | 0 | } |
498 | | |
499 | | int OFSemaphore::trywait() |
500 | 0 | { |
501 | | #ifdef WINDOWS_INTERFACE |
502 | | DWORD result = WaitForSingleObject(OFthread_cast(HANDLE, theSemaphore), 0); |
503 | | if (result == WAIT_OBJECT_0) return 0; |
504 | | else if (result == WAIT_TIMEOUT) return OFSemaphore::busy; |
505 | | else return OFstatic_cast(int, GetLastError()); |
506 | | #elif defined(DARWIN_INTERFACE) |
507 | | if (theSemaphore) |
508 | | { |
509 | | if (dispatch_semaphore_wait(*OFthread_cast(dispatch_semaphore_t *, theSemaphore), DISPATCH_TIME_NOW) != 0) |
510 | | return EAGAIN; |
511 | | else |
512 | | return 0; |
513 | | } else return EINVAL; |
514 | | #elif defined(POSIX_INTERFACE) |
515 | 0 | if (theSemaphore) |
516 | 0 | { |
517 | 0 | if (sem_trywait(OFthread_cast(sem_t *, theSemaphore))) return errno; else return 0; // may return EAGAIN |
518 | 0 | } else return EINVAL; |
519 | | #elif defined(SOLARIS_INTERFACE) |
520 | | if (theSemaphore) return sema_trywait(OFthread_cast(sema_t *, theSemaphore)); else return EINVAL; // may return EBUSY |
521 | | #else |
522 | | return -1; |
523 | | #endif |
524 | 0 | } |
525 | | |
526 | | int OFSemaphore::post() |
527 | 0 | { |
528 | | #ifdef WINDOWS_INTERFACE |
529 | | if (ReleaseSemaphore(OFthread_cast(HANDLE, theSemaphore), 1, NULL)) return 0; else return OFstatic_cast(int, GetLastError()); |
530 | | #elif defined(DARWIN_INTERFACE) |
531 | | if (theSemaphore) |
532 | | { |
533 | | // Always succeeds. |
534 | | dispatch_semaphore_signal(*OFthread_cast(dispatch_semaphore_t *, theSemaphore)); |
535 | | return 0; |
536 | | } else return EINVAL; |
537 | | #elif defined(POSIX_INTERFACE) |
538 | 0 | if (theSemaphore) |
539 | 0 | { |
540 | 0 | if (sem_post(OFthread_cast(sem_t *, theSemaphore))) return errno; else return 0; |
541 | 0 | } else return EINVAL; |
542 | | #elif defined(SOLARIS_INTERFACE) |
543 | | if (theSemaphore) return sema_post(OFthread_cast(sema_t *, theSemaphore)); else return EINVAL; |
544 | | #else |
545 | | return -1; |
546 | | #endif |
547 | 0 | } |
548 | | |
549 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) || defined(DARWIN_INTERFACE) |
550 | | void OFSemaphore::errorstr(OFString& description, int code) |
551 | | #else |
552 | | void OFSemaphore::errorstr(OFString& description, int /* code */ ) |
553 | | #endif |
554 | 0 | { |
555 | | #ifdef WINDOWS_INTERFACE |
556 | | if (code == OFSemaphore::busy) description = "semaphore is already locked"; else |
557 | | { |
558 | | LPVOID buf; |
559 | | FormatMessage( |
560 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
561 | | NULL, OFstatic_cast(DWORD, code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
562 | | OFreinterpret_cast(LPTSTR, &buf), 0, NULL); |
563 | | if (buf) description = OFreinterpret_cast(const char *, buf); |
564 | | LocalFree(buf); |
565 | | } |
566 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) || defined(DARWIN_INTERFACE) |
567 | | char buf[256]; |
568 | 0 | const char *str = OFStandard::strerror(code, buf, sizeof(buf)); |
569 | 0 | if (str) description = str; else description.clear(); |
570 | | #else |
571 | | description = "error: semaphore not implemented"; |
572 | | #endif |
573 | 0 | return; |
574 | 0 | } |
575 | | |
576 | | /* ------------------------------------------------------------------------- */ |
577 | | |
578 | | |
579 | | #ifdef WINDOWS_INTERFACE |
580 | | const int OFMutex::busy = -1; |
581 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
582 | | const int OFMutex::busy = EBUSY; |
583 | | #else |
584 | | const int OFMutex::busy = -2; |
585 | | #endif |
586 | | |
587 | | OFMutex::OFMutex() |
588 | 18 | : theMutex(NULL) |
589 | 18 | { |
590 | | #ifdef WINDOWS_INTERFACE |
591 | | #ifdef USE_WIN32_CREATE_MUTEX |
592 | | theMutex = OFstatic_cast(void *, CreateMutex(NULL, FALSE, NULL)); |
593 | | #else |
594 | | CRITICAL_SECTION *critSec = new CRITICAL_SECTION; |
595 | | InitializeCriticalSection(critSec); |
596 | | theMutex = OFstatic_cast(void *, critSec); |
597 | | #endif |
598 | | #elif defined(POSIX_INTERFACE) |
599 | | pthread_mutex_t *mtx = new pthread_mutex_t; |
600 | 18 | if (mtx) |
601 | 18 | { |
602 | 18 | if (pthread_mutex_init(mtx, NULL)) delete mtx; |
603 | 18 | else theMutex = mtx; |
604 | 18 | } |
605 | | #elif defined(SOLARIS_INTERFACE) |
606 | | mutex_t *mtx = new mutex_t; |
607 | | if (mtx) |
608 | | { |
609 | | if (mutex_init(mtx, USYNC_THREAD, NULL)) delete mtx; |
610 | | else theMutex = mtx; |
611 | | } |
612 | | #else |
613 | | #endif |
614 | 18 | } |
615 | | |
616 | | |
617 | | OFMutex::~OFMutex() |
618 | 0 | { |
619 | | #ifdef WINDOWS_INTERFACE |
620 | | #ifdef USE_WIN32_CREATE_MUTEX |
621 | | CloseHandle(OFthread_cast(HANDLE, theMutex)); |
622 | | #else |
623 | | CRITICAL_SECTION *critSec = OFthread_cast(CRITICAL_SECTION *, theMutex); |
624 | | DeleteCriticalSection(critSec); |
625 | | delete critSec; |
626 | | #endif |
627 | | #elif defined(POSIX_INTERFACE) |
628 | 0 | if (theMutex) pthread_mutex_destroy(OFthread_cast(pthread_mutex_t *, theMutex)); |
629 | 0 | delete OFthread_cast(pthread_mutex_t *, theMutex); |
630 | | #elif defined(SOLARIS_INTERFACE) |
631 | | if (theMutex) mutex_destroy(OFthread_cast(mutex_t *, theMutex)); |
632 | | delete OFthread_cast(mutex_t *, theMutex); |
633 | | #else |
634 | | #endif |
635 | 0 | theMutex = NULL; |
636 | 0 | } |
637 | | |
638 | | |
639 | | OFBool OFMutex::initialized() const |
640 | 0 | { |
641 | 0 | #ifdef WITH_THREADS |
642 | 0 | if (theMutex) return OFTrue; else return OFFalse; |
643 | | #else |
644 | | return OFTrue; |
645 | | #endif |
646 | 0 | } |
647 | | |
648 | | |
649 | | int OFMutex::lock() |
650 | 0 | { |
651 | | #ifdef WINDOWS_INTERFACE |
652 | | #ifdef USE_WIN32_CREATE_MUTEX |
653 | | if (WaitForSingleObject(OFthread_cast(HANDLE, theMutex), INFINITE) == WAIT_OBJECT_0) return 0; |
654 | | else return OFstatic_cast(int, GetLastError()); |
655 | | #else |
656 | | EnterCriticalSection(OFthread_cast(CRITICAL_SECTION *, theMutex)); |
657 | | return 0; |
658 | | #endif |
659 | | #elif defined(POSIX_INTERFACE) |
660 | 0 | if (theMutex) return pthread_mutex_lock(OFthread_cast(pthread_mutex_t *, theMutex)); else return EINVAL; |
661 | | #elif defined(SOLARIS_INTERFACE) |
662 | | if (theMutex) return mutex_lock(OFthread_cast(mutex_t *, theMutex)); else return EINVAL; |
663 | | #else |
664 | | return -1; |
665 | | #endif |
666 | 0 | } |
667 | | |
668 | | int OFMutex::trylock() |
669 | 0 | { |
670 | | #ifdef WINDOWS_INTERFACE |
671 | | #ifdef USE_WIN32_CREATE_MUTEX |
672 | | DWORD result = WaitForSingleObject(OFthread_cast(HANDLE, theMutex), 0); |
673 | | if (result == WAIT_OBJECT_0) return 0; |
674 | | else if (result == WAIT_TIMEOUT) return OFMutex::busy; |
675 | | else return OFstatic_cast(int, GetLastError()); |
676 | | #else |
677 | | if (TryEnterCriticalSection(OFthread_cast(CRITICAL_SECTION *, theMutex))) return 0; |
678 | | else return OFMutex::busy; |
679 | | #endif |
680 | | #elif defined(POSIX_INTERFACE) |
681 | 0 | if (theMutex) return pthread_mutex_trylock(OFthread_cast(pthread_mutex_t *, theMutex)); else return EINVAL; // may return EBUSY. |
682 | | #elif defined(SOLARIS_INTERFACE) |
683 | | if (theMutex) return mutex_trylock(OFthread_cast(mutex_t *, theMutex)); else return EINVAL; // may return EBUSY. |
684 | | #else |
685 | | return -1; |
686 | | #endif |
687 | 0 | } |
688 | | |
689 | | int OFMutex::unlock() |
690 | 0 | { |
691 | | #ifdef WINDOWS_INTERFACE |
692 | | #ifdef USE_WIN32_CREATE_MUTEX |
693 | | if (ReleaseMutex(OFthread_cast(HANDLE, theMutex))) return 0; else return OFstatic_cast(int, GetLastError()); |
694 | | #else |
695 | | LeaveCriticalSection(OFthread_cast(CRITICAL_SECTION *, theMutex)); |
696 | | return 0; |
697 | | #endif |
698 | | #elif defined(POSIX_INTERFACE) |
699 | 0 | if (theMutex) return pthread_mutex_unlock(OFthread_cast(pthread_mutex_t *, theMutex)); else return EINVAL; |
700 | | #elif defined(SOLARIS_INTERFACE) |
701 | | if (theMutex) return mutex_unlock(OFthread_cast(mutex_t *, theMutex)); else return EINVAL; |
702 | | #else |
703 | | return -1; |
704 | | #endif |
705 | 0 | } |
706 | | |
707 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
708 | | void OFMutex::errorstr(OFString& description, int code) |
709 | | #else |
710 | | void OFMutex::errorstr(OFString& description, int /* code */ ) |
711 | | #endif |
712 | 0 | { |
713 | | #ifdef WINDOWS_INTERFACE |
714 | | if (code == OFMutex::busy) description = "mutex is already locked"; else |
715 | | { |
716 | | LPVOID buf; |
717 | | FormatMessage( |
718 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
719 | | NULL, OFstatic_cast(DWORD, code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
720 | | OFreinterpret_cast(LPTSTR, &buf), 0, NULL); |
721 | | if (buf) description = OFreinterpret_cast(const char *, buf); |
722 | | LocalFree(buf); |
723 | | } |
724 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
725 | | char buf[256]; |
726 | 0 | const char *str = OFStandard::strerror(code, buf, sizeof(buf)); |
727 | 0 | if (str) description = str; else description.clear(); |
728 | | #else |
729 | | description = "error: mutex not implemented"; |
730 | | #endif |
731 | 0 | return; |
732 | 0 | } |
733 | | |
734 | | /* ------------------------------------------------------------------------- */ |
735 | | |
736 | | // On Windows, use the slim read/write lock interface (SRW locks) if |
737 | | // both function and prototype are present (which is not the case for some MinGW versions) |
738 | | // and we have not explicitly been instructed to use the old implementation |
739 | | #if (defined(WINDOWS_INTERFACE)) && (defined(HAVE_PROTOTYPE_TRYACQUIRESRWLOCKSHARED)) && (! defined(USE_WIN32_READ_WRITE_LOCK_HELPER)) |
740 | | #define USE_WIN32_SRW_INTERFACE |
741 | | #endif |
742 | | |
743 | | /* ------------------------------------------------------------------------- */ |
744 | | |
745 | | #if (defined(WINDOWS_INTERFACE) && (! defined(USE_WIN32_SRW_INTERFACE))) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
746 | | |
747 | | class OFReadWriteLockHelper |
748 | | { |
749 | | public: |
750 | | OFReadWriteLockHelper(): accessMutex(), usageSemaphore(1), numReaders(0) {} |
751 | | ~OFReadWriteLockHelper() {} |
752 | | |
753 | | OFMutex accessMutex; |
754 | | OFSemaphore usageSemaphore; |
755 | | int numReaders; |
756 | | private: |
757 | | /* undefined */ OFReadWriteLockHelper(const OFReadWriteLockHelper& arg); |
758 | | /* undefined */ OFReadWriteLockHelper& operator=(const OFReadWriteLockHelper& arg); |
759 | | }; |
760 | | |
761 | | #endif |
762 | | |
763 | | /* ------------------------------------------------------------------------- */ |
764 | | |
765 | | |
766 | | #if defined(WINDOWS_INTERFACE) |
767 | | const int OFReadWriteLock::busy = -1; |
768 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
769 | | const int OFReadWriteLock::busy = EBUSY; |
770 | | #else |
771 | | const int OFReadWriteLock::busy = -2; |
772 | | #endif |
773 | | |
774 | | OFReadWriteLock::OFReadWriteLock() |
775 | 24 | : theLock(NULL) |
776 | 24 | { |
777 | | #ifdef USE_WIN32_SRW_INTERFACE |
778 | | SRWLOCK *srwLock = new SRWLOCK; |
779 | | InitializeSRWLock(srwLock); |
780 | | theLock = srwLock; |
781 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
782 | | OFReadWriteLockHelper *rwl = new OFReadWriteLockHelper(); |
783 | | if ((rwl->accessMutex.initialized()) && (rwl->usageSemaphore.initialized())) theLock=rwl; |
784 | | else delete rwl; |
785 | | #elif defined(POSIX_INTERFACE) |
786 | | pthread_rwlock_t *rwl = new pthread_rwlock_t; |
787 | 24 | if (rwl) |
788 | 24 | { |
789 | 24 | if (pthread_rwlock_init(rwl, NULL)) delete rwl; |
790 | 24 | else theLock = rwl; |
791 | 24 | } |
792 | | #elif defined(SOLARIS_INTERFACE) |
793 | | rwlock_t *rwl = new rwlock_t; |
794 | | if (rwl) |
795 | | { |
796 | | if (rwlock_init(rwl, USYNC_THREAD, NULL)) delete rwl; |
797 | | else theLock = rwl; |
798 | | } |
799 | | #else |
800 | | #endif |
801 | 24 | } |
802 | | |
803 | | OFReadWriteLock::~OFReadWriteLock() |
804 | 0 | { |
805 | | #ifdef USE_WIN32_SRW_INTERFACE |
806 | | delete OFthread_cast(SRWLOCK *, theLock); |
807 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
808 | | delete OFthread_cast(OFReadWriteLockHelper *, theLock); |
809 | | #elif defined(POSIX_INTERFACE) |
810 | 0 | if (theLock) pthread_rwlock_destroy(OFthread_cast(pthread_rwlock_t *, theLock)); |
811 | 0 | delete OFthread_cast(pthread_rwlock_t *, theLock); |
812 | | #elif defined(SOLARIS_INTERFACE) |
813 | | if (theLock) rwlock_destroy(OFthread_cast(rwlock_t *, theLock)); |
814 | | delete OFthread_cast(rwlock_t *, theLock); |
815 | | #else |
816 | | #endif |
817 | 0 | theLock = NULL; |
818 | 0 | } |
819 | | |
820 | | OFBool OFReadWriteLock::initialized() const |
821 | 46 | { |
822 | 46 | #ifdef WITH_THREADS |
823 | 46 | if (theLock) return OFTrue; else return OFFalse; |
824 | | #else |
825 | | return OFTrue; |
826 | | #endif |
827 | 46 | } |
828 | | |
829 | | int OFReadWriteLock::rdlock() |
830 | 893k | { |
831 | | #ifdef USE_WIN32_SRW_INTERFACE |
832 | | if (theLock) |
833 | | { |
834 | | AcquireSRWLockShared(OFthread_cast(SRWLOCK *, theLock)); |
835 | | return 0; |
836 | | } else return EINVAL; |
837 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
838 | | if (theLock) |
839 | | { |
840 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
841 | | int result =0; |
842 | | while (1) |
843 | | { |
844 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
845 | | if (rwl->numReaders >= 0) // we can grant the read lock |
846 | | { |
847 | | if (rwl->numReaders == 0) |
848 | | { |
849 | | if (0 != (result = rwl->usageSemaphore.wait())) |
850 | | { |
851 | | rwl->accessMutex.unlock(); |
852 | | return result; |
853 | | } |
854 | | } |
855 | | (rwl->numReaders)++; |
856 | | return rwl->accessMutex.unlock(); |
857 | | } |
858 | | // we cannot grant the read lock, block thread. |
859 | | if (0 != (result = rwl->accessMutex.unlock())) return result; |
860 | | if (0 != (result = rwl->usageSemaphore.wait())) return result; |
861 | | if (0 != (result = rwl->usageSemaphore.post())) return result; |
862 | | } |
863 | | } else return EINVAL; |
864 | | #elif defined(POSIX_INTERFACE) |
865 | 893k | if (theLock) return pthread_rwlock_rdlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; |
866 | | #elif defined(SOLARIS_INTERFACE) |
867 | | if (theLock) return rw_rdlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; |
868 | | #else |
869 | | return -1; |
870 | | #endif |
871 | 893k | } |
872 | | |
873 | | int OFReadWriteLock::wrlock() |
874 | 20 | { |
875 | | #ifdef USE_WIN32_SRW_INTERFACE |
876 | | if (theLock) |
877 | | { |
878 | | AcquireSRWLockExclusive(OFthread_cast(SRWLOCK *, theLock)); |
879 | | return 0; |
880 | | } else return EINVAL; |
881 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
882 | | if (theLock) |
883 | | { |
884 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
885 | | int result =0; |
886 | | while (1) |
887 | | { |
888 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
889 | | if (rwl->numReaders == 0) // we can grant the write lock |
890 | | { |
891 | | if (0 != (result = rwl->usageSemaphore.wait())) |
892 | | { |
893 | | rwl->accessMutex.unlock(); |
894 | | return result; |
895 | | } |
896 | | rwl->numReaders = -1; |
897 | | return rwl->accessMutex.unlock(); |
898 | | } |
899 | | |
900 | | // we cannot grant the write lock, block thread. |
901 | | if (0 != (result = rwl->accessMutex.unlock())) return result; |
902 | | if (0 != (result = rwl->usageSemaphore.wait())) return result; |
903 | | if (0 != (result = rwl->usageSemaphore.post())) return result; |
904 | | } |
905 | | } else return EINVAL; |
906 | | #elif defined(POSIX_INTERFACE) |
907 | 20 | if (theLock) return pthread_rwlock_wrlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; |
908 | | #elif defined(SOLARIS_INTERFACE) |
909 | | if (theLock) return rw_wrlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; |
910 | | #else |
911 | | return -1; |
912 | | #endif |
913 | 20 | } |
914 | | |
915 | | |
916 | | int OFReadWriteLock::tryrdlock() |
917 | 0 | { |
918 | | #ifdef USE_WIN32_SRW_INTERFACE |
919 | | if (theLock) |
920 | | { |
921 | | return TryAcquireSRWLockShared(OFthread_cast(SRWLOCK *, theLock)) ? 0 : OFReadWriteLock::busy; |
922 | | } else return EINVAL; |
923 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
924 | | if (theLock) |
925 | | { |
926 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
927 | | int result =0; |
928 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
929 | | if (rwl->numReaders >= 0) // we can grant the read lock |
930 | | { |
931 | | if (rwl->numReaders == 0) |
932 | | { |
933 | | if (0 != (result = rwl->usageSemaphore.wait())) |
934 | | { |
935 | | rwl->accessMutex.unlock(); |
936 | | return result; |
937 | | } |
938 | | } |
939 | | (rwl->numReaders)++; |
940 | | return rwl->accessMutex.unlock(); |
941 | | } |
942 | | result = rwl->accessMutex.unlock(); |
943 | | if (result) return result; else return OFReadWriteLock::busy; |
944 | | } else return EINVAL; |
945 | | #elif defined(POSIX_INTERFACE) |
946 | 0 | if (theLock) return pthread_rwlock_tryrdlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; // may return EBUSY. |
947 | | #elif defined(SOLARIS_INTERFACE) |
948 | | if (theLock) return rw_tryrdlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; // may return EBUSY. |
949 | | #else |
950 | | return -1; |
951 | | #endif |
952 | 0 | } |
953 | | |
954 | | int OFReadWriteLock::trywrlock() |
955 | 0 | { |
956 | | #ifdef USE_WIN32_SRW_INTERFACE |
957 | | if (theLock) |
958 | | { |
959 | | return TryAcquireSRWLockExclusive(OFthread_cast(SRWLOCK *, theLock)) ? 0 : OFReadWriteLock::busy; |
960 | | } else return EINVAL; |
961 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
962 | | if (theLock) |
963 | | { |
964 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
965 | | int result =0; |
966 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
967 | | if (rwl->numReaders == 0) // we can grant the write lock |
968 | | { |
969 | | if (0 != (result = rwl->usageSemaphore.wait())) |
970 | | { |
971 | | rwl->accessMutex.unlock(); |
972 | | return result; |
973 | | } |
974 | | rwl->numReaders = -1; |
975 | | return rwl->accessMutex.unlock(); |
976 | | } |
977 | | result = rwl->accessMutex.unlock(); |
978 | | if (result) return result; else return OFReadWriteLock::busy; |
979 | | } else return EINVAL; |
980 | | #elif defined(POSIX_INTERFACE) |
981 | 0 | if (theLock) return pthread_rwlock_trywrlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; // may return EBUSY. |
982 | | #elif defined(SOLARIS_INTERFACE) |
983 | | if (theLock) return rw_trywrlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; // may return EBUSY. |
984 | | #else |
985 | | return -1; |
986 | | #endif |
987 | 0 | } |
988 | | |
989 | | |
990 | | int OFReadWriteLock::rdunlock() |
991 | 893k | { |
992 | | #ifdef USE_WIN32_SRW_INTERFACE |
993 | | if (theLock) |
994 | | { |
995 | | ReleaseSRWLockShared(OFthread_cast(SRWLOCK *, theLock)); |
996 | | return 0; |
997 | | } else return EINVAL; |
998 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
999 | | if (theLock) |
1000 | | { |
1001 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
1002 | | int result =0; |
1003 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
1004 | | if (rwl->numReaders == -1) rwl->numReaders = 0; else (rwl->numReaders)--; |
1005 | | if ((rwl->numReaders == 0) && (0 != (result = rwl->usageSemaphore.post()))) |
1006 | | { |
1007 | | rwl->accessMutex.unlock(); |
1008 | | return result; |
1009 | | } |
1010 | | return rwl->accessMutex.unlock(); |
1011 | | } else return EINVAL; |
1012 | | #elif defined(POSIX_INTERFACE) |
1013 | 893k | if (theLock) return pthread_rwlock_unlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; |
1014 | | #elif defined(SOLARIS_INTERFACE) |
1015 | | if (theLock) return rw_unlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; |
1016 | | #else |
1017 | | return -1; |
1018 | | #endif |
1019 | 893k | } |
1020 | | |
1021 | | int OFReadWriteLock::wrunlock() |
1022 | 20 | { |
1023 | | #ifdef USE_WIN32_SRW_INTERFACE |
1024 | | if (theLock) |
1025 | | { |
1026 | | ReleaseSRWLockExclusive(OFthread_cast(SRWLOCK *, theLock)); |
1027 | | return 0; |
1028 | | } else return EINVAL; |
1029 | | #elif defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE_WITHOUT_RWLOCK) |
1030 | | if (theLock) |
1031 | | { |
1032 | | OFReadWriteLockHelper *rwl = OFthread_cast(OFReadWriteLockHelper *, theLock); |
1033 | | int result =0; |
1034 | | if (0 != (result = rwl->accessMutex.lock())) return result; // lock mutex |
1035 | | if (rwl->numReaders == -1) rwl->numReaders = 0; else (rwl->numReaders)--; |
1036 | | if ((rwl->numReaders == 0) && (0 != (result = rwl->usageSemaphore.post()))) |
1037 | | { |
1038 | | rwl->accessMutex.unlock(); |
1039 | | return result; |
1040 | | } |
1041 | | return rwl->accessMutex.unlock(); |
1042 | | } else return EINVAL; |
1043 | | #elif defined(POSIX_INTERFACE) |
1044 | 20 | if (theLock) return pthread_rwlock_unlock(OFthread_cast(pthread_rwlock_t *, theLock)); else return EINVAL; |
1045 | | #elif defined(SOLARIS_INTERFACE) |
1046 | | if (theLock) return rw_unlock(OFthread_cast(rwlock_t *, theLock)); else return EINVAL; |
1047 | | #else |
1048 | | return -1; |
1049 | | #endif |
1050 | 20 | } |
1051 | | |
1052 | | #if defined(WINDOWS_INTERFACE) || defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
1053 | | void OFReadWriteLock::errorstr(OFString& description, int code) |
1054 | | #else |
1055 | | void OFReadWriteLock::errorstr(OFString& description, int /* code */ ) |
1056 | | #endif |
1057 | 0 | { |
1058 | | #ifdef WINDOWS_INTERFACE |
1059 | | if (code == OFSemaphore::busy) description = "read/write lock is already locked"; else |
1060 | | { |
1061 | | LPVOID buf; |
1062 | | FormatMessage( |
1063 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
1064 | | NULL, OFstatic_cast(DWORD, code), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
1065 | | OFreinterpret_cast(LPTSTR, &buf), 0, NULL); |
1066 | | if (buf) description = OFreinterpret_cast(const char *, buf); |
1067 | | LocalFree(buf); |
1068 | | } |
1069 | | #elif defined(POSIX_INTERFACE) || defined(SOLARIS_INTERFACE) |
1070 | | char buf[256]; |
1071 | 0 | const char *str = OFStandard::strerror(code, buf, sizeof(buf)); |
1072 | 0 | if (str) description = str; else description.clear(); |
1073 | | #else |
1074 | | description = "error: read/write lock not implemented"; |
1075 | | #endif |
1076 | 0 | return; |
1077 | 0 | } |
1078 | | |
1079 | | |
1080 | | OFReadWriteLocker::OFReadWriteLocker(OFReadWriteLock& lock) |
1081 | 46 | : theLock(lock) |
1082 | 46 | , locked(OFFalse) |
1083 | 46 | , isWriteLock(OFFalse) |
1084 | 46 | { |
1085 | 46 | } |
1086 | | |
1087 | | OFReadWriteLocker::~OFReadWriteLocker() |
1088 | 46 | { |
1089 | 46 | if (locked) |
1090 | 46 | { |
1091 | 46 | if (isWriteLock) theLock.wrunlock(); else theLock.rdunlock(); |
1092 | 46 | } |
1093 | 46 | } |
1094 | | |
1095 | | #ifdef DEBUG |
1096 | | #define lockWarn(name, locked) \ |
1097 | | if (locked == OFTrue) \ |
1098 | | { \ |
1099 | | ofConsole.lockCout() << "OFReadWriteLocker::" name "(): Already locked?!" << OFendl; \ |
1100 | | ofConsole.unlockCout(); \ |
1101 | | } |
1102 | | #else |
1103 | | #define lockWarn(name, locked) |
1104 | | #endif |
1105 | | |
1106 | | int OFReadWriteLocker::rdlock() |
1107 | 28 | { |
1108 | 28 | lockWarn("rdlock", locked); |
1109 | 28 | int ret = theLock.rdlock(); |
1110 | 28 | if (ret == 0) |
1111 | 28 | { |
1112 | 28 | locked = OFTrue; |
1113 | 28 | isWriteLock = OFFalse; |
1114 | 28 | } |
1115 | 28 | return ret; |
1116 | 28 | } |
1117 | | |
1118 | | int OFReadWriteLocker::wrlock() |
1119 | 18 | { |
1120 | 18 | lockWarn("wrlock", locked); |
1121 | 18 | int ret = theLock.wrlock(); |
1122 | 18 | if (ret == 0) |
1123 | 18 | { |
1124 | 18 | locked = OFTrue; |
1125 | 18 | isWriteLock = OFTrue; |
1126 | 18 | } |
1127 | 18 | return ret; |
1128 | 18 | } |
1129 | | |
1130 | | int OFReadWriteLocker::tryrdlock() |
1131 | 0 | { |
1132 | 0 | lockWarn("tryrdlock", locked); |
1133 | 0 | int ret = theLock.tryrdlock(); |
1134 | 0 | if (ret == 0) |
1135 | 0 | { |
1136 | 0 | locked = OFTrue; |
1137 | 0 | isWriteLock = OFFalse; |
1138 | 0 | } |
1139 | 0 | return ret; |
1140 | 0 | } |
1141 | | |
1142 | | int OFReadWriteLocker::trywrlock() |
1143 | 0 | { |
1144 | 0 | lockWarn("trywrlock", locked); |
1145 | 0 | int ret = theLock.trywrlock(); |
1146 | 0 | if (ret == 0) |
1147 | 0 | { |
1148 | 0 | locked = OFTrue; |
1149 | 0 | isWriteLock = OFTrue; |
1150 | 0 | } |
1151 | 0 | return ret; |
1152 | 0 | } |
1153 | | |
1154 | | int OFReadWriteLocker::unlock() |
1155 | 0 | { |
1156 | | #ifdef DEBUG |
1157 | | if (locked == OFFalse) |
1158 | | { |
1159 | | ofConsole.lockCout() << "OFReadWriteLocker::unlock(): Nothing to unlock?!" << OFendl; |
1160 | | ofConsole.unlockCout(); |
1161 | | } |
1162 | | #endif |
1163 | |
|
1164 | 0 | int ret = 0; |
1165 | 0 | if (isWriteLock) ret = theLock.wrunlock(); else ret = theLock.rdunlock(); |
1166 | 0 | if (ret == 0) |
1167 | 0 | locked = OFFalse; |
1168 | 0 | return ret; |
1169 | 0 | } |
1170 | | |