VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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