Coverage Report

Created: 2026-11-12 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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