VirtualBox

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

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

RT_OS_* and RT_ARCH_* for Runtime/ and Support/

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