VirtualBox

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

Last change on this file since 8155 was 8155, checked in by vboxsync, 16 years ago

The Big Sun Rebranding Header Change

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