VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/semrw-generic.cpp@ 4071

Last change on this file since 4071 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:keywords set to Id
File size: 15.6 KB
Line 
1/* $Id: semrw-generic.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
2/** @file
3 * Excerpt from kProfileR3.cpp.
4 */
5
6/*
7 * Copyright (C) 2005-2007 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#if defined(RT_OS_WINDOWS)
23# include <windows.h>
24# include <psapi.h>
25# include <malloc.h>
26# define IN_RING3
27# include <iprt/stdint.h> /* Temporary IPRT convenience */
28# if _MSC_VER >= 1400
29# include <intrin.h>
30# define HAVE_INTRIN
31# endif
32
33#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
34# define KPRF_USE_PTHREAD
35# include <pthread.h>
36# include <stdint.h>
37# define KPRF_USE_MMAN
38# include <sys/mman.h>
39# include <sys/fcntl.h>
40# include <unistd.h>
41# include <stdlib.h>
42# ifndef O_BINARY
43# define O_BINARY 0
44# endif
45
46#elif defined(RT_OS_OS2)
47# define INCL_BASE
48# include <os2s.h>
49# include <stdint.h>
50# include <sys/fmutex.h>
51
52#else
53# error "not ported to this OS..."
54#endif
55
56
57/*
58 * Instantiate the header.
59 */
60#define KPRF_NAME(Suffix) KPrf##Suffix
61#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF##Suffix
62#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
63# define KPRF_DECL_FUNC(type, name) extern "C" __declspec(dllexport) type __cdecl KPRF_NAME(name)
64#else
65# define KPRF_DECL_FUNC(type, name) extern "C" type KPRF_NAME(name)
66#endif
67#if 1
68# ifdef __GNUC__
69# define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0)
70# else
71# define KPRF_ASSERT(expr) do { if (!(expr)) { __asm int 3 \
72 } } while (0)
73# endif
74#else
75# define KPRF_ASSERT(expr) do { } while (0)
76#endif
77
78#include "prfcore.h.h"
79
80
81
82/*******************************************************************************
83* Structures and Typedefs *
84*******************************************************************************/
85/** Mutex lock type. */
86#if defined(KPRF_USE_PTHREAD)
87typedef pthread_mutex_t KPRF_TYPE(,MUTEX);
88#elif defined(RT_OS_WINDOWS)
89typedef CRITICAL_SECTION KPRF_TYPE(,MUTEX);
90#elif defined(RT_OS_OS2)
91typedef struct _fmutex KPRF_TYPE(,MUTEX);
92#endif
93/** Pointer to a mutex lock. */
94typedef KPRF_TYPE(,MUTEX) *KPRF_TYPE(P,MUTEX);
95
96
97#if defined(KPRF_USE_PTHREAD)
98/** Read/Write lock type. */
99typedef pthread_rwlock_t KPRF_TYPE(,RWLOCK);
100#elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
101/** Read/Write lock state. */
102typedef enum KPRF_TYPE(,RWLOCKSTATE)
103{
104 RWLOCK_STATE_UNINITIALIZED = 0,
105 RWLOCK_STATE_SHARED,
106 RWLOCK_STATE_LOCKING,
107 RWLOCK_STATE_EXCLUSIVE,
108 RWLOCK_STATE_32BIT_HACK = 0x7fffffff
109} KPRF_TYPE(,RWLOCKSTATE);
110/** Update the state. */
111#define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \
112 kPrfAtomicSet32((volatile uint32_t *)&(pRWLock)->enmState, (uint32_t)(enmNewState))
113
114/** Read/Write lock type. */
115typedef struct KPRF_TYPE(,RWLOCK)
116{
117 /** This mutex serialize the access and updating of the members
118 * of this structure. */
119 KPRF_TYPE(,MUTEX) Mutex;
120 /** The current number of readers. */
121 uint32_t cReaders;
122 /** The number of readers waiting. */
123 uint32_t cReadersWaiting;
124 /** The current number of waiting writers. */
125 uint32_t cWritersWaiting;
126# if defined(RT_OS_WINDOWS)
127 /** The handle of the event object on which the waiting readers block. (manual reset). */
128 HANDLE hevReaders;
129 /** The handle of the event object on which the waiting writers block. (manual reset). */
130 HANDLE hevWriters;
131# elif defined(RT_OS_OS2)
132 /** The handle of the event semaphore on which the waiting readers block. */
133 HEV hevReaders;
134 /** The handle of the event semaphore on which the waiting writers block. */
135 HEV hevWriters;
136# endif
137 /** The current state of the read-write lock. */
138 KPRF_TYPE(,RWLOCKSTATE) enmState;
139} KPRF_TYPE(,RWLOCK);
140#endif
141/** Pointer to a Read/Write lock. */
142typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK);
143
144
145
146/**
147 * Initializes a mutex.
148 *
149 * @returns 0 on success.
150 * @returns -1 on failure.
151 * @param pMutex The mutex to init.
152 */
153static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex)
154{
155#if defined(KPRF_USE_PTHREAD)
156 if (!pthread_mutex_init(pMutex, NULL));
157 return 0;
158 return -1;
159
160#elif defined(RT_OS_WINDOWS)
161 InitializeCriticalSection(pMutex);
162 return 0;
163
164#elif defined(RT_OS_OS2)
165 if (!_fmutex_create(pMutex, 0))
166 return 0;
167 return -1;
168#endif
169}
170
171/**
172 * Deletes a mutex.
173 *
174 * @param pMutex The mutex to delete.
175 */
176static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex)
177{
178#if defined(KPRF_USE_PTHREAD)
179 pthread_mutex_destroy(pMutex);
180
181#elif defined(RT_OS_WINDOWS)
182 DeleteCriticalSection(pMutex);
183
184#elif defined(RT_OS_OS2)
185 _fmutex_close(pMutex);
186#endif
187}
188
189/**
190 * Locks a mutex.
191 * @param pMutex The mutex lock.
192 */
193static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex)
194{
195#if defined(RT_OS_WINDOWS)
196 EnterCriticalSection(pMutex);
197
198#elif defined(KPRF_USE_PTHREAD)
199 pthread_mutex_lock(pMutex);
200
201#elif defined(RT_OS_OS2)
202 fmutex_request(pMutex);
203#endif
204}
205
206
207/**
208 * Unlocks a mutex.
209 * @param pMutex The mutex lock.
210 */
211static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex)
212{
213#if defined(RT_OS_WINDOWS)
214 LeaveCriticalSection(pMutex);
215
216#elif defined(KPRF_USE_PTHREAD)
217 pthread_mutex_lock(pMutex);
218
219#elif defined(RT_OS_OS2)
220 fmutex_request(pMutex);
221#endif
222}
223
224
225
226/**
227 * Initializes a read-write lock.
228 *
229 * @returns 0 on success.
230 * @returns -1 on failure.
231 * @param pRWLock The read-write lock to initialize.
232 */
233static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock)
234{
235#if defined(KPRF_USE_PTHREAD)
236 if (!pthread_rwlock_init(pRWLock, NULL))
237 return 0;
238 return -1;
239
240#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
241 if (kPrfMutexInit(&pRWLock->Mutex))
242 return -1;
243 pRWLock->cReaders = 0;
244 pRWLock->cReadersWaiting = 0;
245 pRWLock->cWritersWaiting = 0;
246 pRWLock->enmState = RWLOCK_STATE_SHARED;
247# if defined(RT_OS_WINDOWS)
248 pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL);
249 pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL);
250 if ( pRWLock->hevReaders != INVALID_HANDLE_VALUE
251 && pRWLock->hevWriters != INVALID_HANDLE_VALUE)
252 return 0;
253 CloseHandle(pRWLock->hevReaders);
254 CloseHandle(pRWLock->hevWriters);
255
256# elif defined(RT_OS_OS2)
257 APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE);
258 if (!rc)
259 {
260 rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE);
261 if (!rc)
262 return 0;
263 pRWLock->hevWriters = NULLHANDLE;
264 DosCloseEventSem(pRWLock->hevReaders);
265 }
266 pRWLock->hevReaders = NULLHANDLE;
267# endif
268
269 pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
270 kPrfMutexDelete(&pRWLock->Mutex);
271 return -1;
272#endif
273}
274
275
276/**
277 * Deleters a read-write lock.
278 *
279 * @param pRWLock The read-write lock to delete.
280 */
281static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock)
282{
283#if defined(KPRF_USE_PTHREAD)
284 pthread_rwlock_destroy(pRWLock);
285
286#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
287 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
288 return;
289
290 pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
291 kPrfMutexDelete(&pRWLock->Mutex);
292 pRWLock->cReaders = 0;
293 pRWLock->cReadersWaiting = 0;
294 pRWLock->cWritersWaiting = 0;
295# if defined(RT_OS_WINDOWS)
296 CloseHandle(pRWLock->hevReaders);
297 pRWLock->hevReaders = INVALID_HANDLE_VALUE;
298 CloseHandle(pRWLock->hevWriters);
299 pRWLock->hevWriters = INVALID_HANDLE_VALUE;
300
301# elif defined(RT_OS_OS2)
302 DosCloseEventSem(pRWLock->hevReaders);
303 pRWLock->hevReaders = NULLHANDLE;
304 DosCloseEventSem(pRWLock->hevWriters);
305 pRWLock->hevWriters = NULLHANDLE;
306# endif
307#endif
308}
309
310
311/**
312 * Acquires read access to the read-write lock.
313 * @param pRWLock The read-write lock.
314 */
315static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock)
316{
317#if defined(KPRF_USE_PTHREAD)
318 pthread_rwlock_rdlock(pRWLock);
319
320#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
321 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
322 return;
323
324 kPrfMutexAcquire(&pRWLock->Mutex);
325 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
326 {
327 KPRF_ATOMIC_INC32(&pRWLock->cReaders);
328 kPrfMutexRelease(&pRWLock->Mutex);
329 return;
330 }
331
332 for (;;)
333 {
334 /* have to wait */
335 KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting);
336# if defined(RT_OS_WINDOWS)
337 HANDLE hev = pRWLock->hevReaders;
338 ResetEvent(hev);
339
340# elif defined(RT_OS_OS2)
341 HEV hev = pRWLock->hevReaders;
342 ULONG cIgnored;
343 DosResetEventSem(hev, &cIgnored);
344
345# endif
346 kPrfMutexRelease(&pRWLock->Mutex);
347
348# if defined(RT_OS_WINDOWS)
349 switch (WaitForSingleObject(hev, INFINITE))
350 {
351 case WAIT_IO_COMPLETION:
352 case WAIT_TIMEOUT:
353 case WAIT_OBJECT_0:
354 break;
355 case WAIT_ABANDONED:
356 default:
357 return;
358 }
359
360# elif defined(RT_OS_OS2)
361 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
362 {
363 case NO_ERROR:
364 case ERROR_SEM_TIMEOUT:
365 case ERROR_TIMEOUT:
366 case ERROR_INTERRUPT:
367 break;
368 default:
369 return;
370 }
371# endif
372
373 kPrfMutexAcquire(&pRWLock->Mutex);
374 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
375 {
376 KPRF_ATOMIC_INC32(&pRWLock->cReaders);
377 KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting);
378 kPrfMutexRelease(&pRWLock->Mutex);
379 return;
380 }
381 }
382#endif
383}
384
385
386/**
387 * Releases read access to the read-write lock.
388 * @param pRWLock The read-write lock.
389 */
390static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock)
391{
392#if defined(KPRF_USE_PTHREAD)
393 pthread_rwlock_unlock(pRWLock);
394
395#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
396 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
397 return;
398
399 /*
400 * If we're still in the shared state, or if there
401 * are more readers out there, or if there are no
402 * waiting writers, all we have to do is decrement an leave.
403 *
404 * That's the most frequent, thing and should be fast.
405 */
406 kPrfMutexAcquire(&pRWLock->Mutex);
407 KPRF_ATOMIC_DEC32(&pRWLock->cReaders);
408 if ( pRWLock->enmState == RWLOCK_STATE_SHARED
409 || pRWLock->cReaders
410 || !pRWLock->cWritersWaiting)
411 {
412 kPrfMutexRelease(&pRWLock->Mutex);
413 return;
414 }
415
416 /*
417 * Wake up one (or more on OS/2) waiting writers.
418 */
419# if defined(RT_OS_WINDOWS)
420 SetEvent(pRWLock->hevWriters);
421# elif defined(RT_OS_OS2)
422 DosPostEvent(pRWLock->hevwriters);
423# endif
424 kPrfMutexRelease(&pRWLock->Mutex);
425
426#endif
427}
428
429
430/**
431 * Acquires write access to the read-write lock.
432 * @param pRWLock The read-write lock.
433 */
434static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
435{
436#if defined(KPRF_USE_PTHREAD)
437 pthread_rwlock_wrlock(pRWLock);
438
439#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
440 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
441 return;
442
443 kPrfMutexAcquire(&pRWLock->Mutex);
444 if ( !pRWLock->cReaders
445 && ( pRWLock->enmState == RWLOCK_STATE_SHARED
446 || pRWLock->enmState == RWLOCK_STATE_LOCKING)
447 )
448 {
449 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
450 kPrfMutexRelease(&pRWLock->Mutex);
451 return;
452 }
453
454 /*
455 * We'll have to wait.
456 */
457 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
458 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
459 KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting);
460 for (;;)
461 {
462# if defined(RT_OS_WINDOWS)
463 HANDLE hev = pRWLock->hevWriters;
464# elif defined(RT_OS_OS2)
465 HEV hev = pRWLock->hevWriters;
466# endif
467 kPrfMutexRelease(&pRWLock->Mutex);
468# if defined(RT_OS_WINDOWS)
469 switch (WaitForSingleObject(hev, INFINITE))
470 {
471 case WAIT_IO_COMPLETION:
472 case WAIT_TIMEOUT:
473 case WAIT_OBJECT_0:
474 break;
475 case WAIT_ABANDONED:
476 default:
477 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
478 return;
479 }
480
481# elif defined(RT_OS_OS2)
482 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
483 {
484 case NO_ERROR:
485 case ERROR_SEM_TIMEOUT:
486 case ERROR_TIMEOUT:
487 case ERROR_INTERRUPT:
488 break;
489 default:
490 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
491 return;
492 }
493 ULONG cIgnored;
494 DosResetEventSem(hev, &cIgnored);
495# endif
496
497 /*
498 * Try acquire the lock.
499 */
500 kPrfMutexAcquire(&pRWLock->Mutex);
501 if ( !pRWLock->cReaders
502 && ( pRWLock->enmState == RWLOCK_STATE_SHARED
503 || pRWLock->enmState == RWLOCK_STATE_LOCKING)
504 )
505 {
506 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
507 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
508 kPrfMutexRelease(&pRWLock->Mutex);
509 return;
510 }
511 }
512#endif
513}
514
515
516/**
517 * Releases write access to the read-write lock.
518 * @param pRWLock The read-write lock.
519 */
520static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
521{
522#if defined(KPRF_USE_PTHREAD)
523 pthread_rwlock_unlock(pRWLock);
524
525#elif defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
526 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
527 return;
528
529 /*
530 * The common thing is that there are noone waiting.
531 * But, before that usual paranoia.
532 */
533 kPrfMutexAcquire(&pRWLock->Mutex);
534 if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE)
535 {
536 kPrfMutexRelease(&pRWLock->Mutex);
537 return;
538 }
539 if ( !pRWLock->cReadersWaiting
540 && !pRWLock->cWritersWaiting)
541 {
542 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
543 kPrfMutexRelease(&pRWLock->Mutex);
544 return;
545 }
546
547 /*
548 * Someone is waiting, wake them up as we change the state.
549 */
550# if defined(RT_OS_WINDOWS)
551 HANDLE hev = INVALID_HANDLE_VALUE;
552# elif defined(RT_OS_OS2)
553 HEV hev = NULLHANDLE;
554# endif
555
556 if (pRWLock->cWritersWaiting)
557 {
558 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
559 hev = pRWLock->hevWriters;
560 }
561 else
562 {
563 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
564 hev = pRWLock->hevReaders;
565 }
566# if defined(RT_OS_WINDOWS)
567 SetEvent(hev);
568# elif defined(RT_OS_OS2)
569 DosPostEvent(pRWLock->hevwriters);
570# endif
571 kPrfMutexRelease(&pRWLock->Mutex);
572
573#endif
574}
575
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette