VirtualBox

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

Last change on this file since 37043 was 36190, checked in by vboxsync, 14 years ago

IPRT,Drivers: Committed a modified version of the diff_linux_guest_host patch. This mangles the IPRT symbols in kernel space on linux and later other platforms.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 KB
Line 
1/* $Id: semrw-lockless-generic.cpp 36190 2011-03-07 16:28:50Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTSemXRoads, generic implementation.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
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#define RTSEMRW_WITHOUT_REMAPPING
32#define RTASSERT_QUIET
33#include <iprt/semaphore.h>
34#include "internal/iprt.h"
35
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/err.h>
39#include <iprt/lockvalidator.h>
40#include <iprt/mem.h>
41#include <iprt/thread.h>
42
43#include "internal/magics.h"
44#include "internal/strict.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef struct RTSEMRWINTERNAL
51{
52 /** Magic value (RTSEMRW_MAGIC). */
53 uint32_t volatile u32Magic;
54 uint32_t u32Padding; /**< alignment padding.*/
55 /* The state variable.
56 * All accesses are atomic and it bits are defined like this:
57 * Bits 0..14 - cReads.
58 * Bit 15 - Unused.
59 * Bits 16..31 - cWrites. - doesn't make sense here
60 * Bit 31 - fDirection; 0=Read, 1=Write.
61 * Bits 32..46 - cWaitingReads
62 * Bit 47 - Unused.
63 * Bits 48..62 - cWaitingWrites
64 * Bit 63 - Unused.
65 */
66 uint64_t volatile u64State;
67 /** The write owner. */
68 RTNATIVETHREAD volatile hNativeWriter;
69 /** The number of reads made by the current writer. */
70 uint32_t volatile cWriterReads;
71 /** The number of reads made by the current writer. */
72 uint32_t volatile cWriteRecursions;
73
74 /** What the writer threads are blocking on. */
75 RTSEMEVENT hEvtWrite;
76 /** What the read threads are blocking on when waiting for the writer to
77 * finish. */
78 RTSEMEVENTMULTI hEvtRead;
79 /** Indicates whether hEvtRead needs resetting. */
80 bool volatile fNeedReset;
81
82#ifdef RTSEMRW_STRICT
83 /** The validator record for the writer. */
84 RTLOCKVALRECEXCL ValidatorWrite;
85 /** The validator record for the readers. */
86 RTLOCKVALRECSHRD ValidatorRead;
87#endif
88} RTSEMRWINTERNAL;
89
90
91/*******************************************************************************
92* Defined Constants And Macros *
93*******************************************************************************/
94#define RTSEMRW_CNT_BITS 15
95#define RTSEMRW_CNT_MASK UINT64_C(0x00007fff)
96
97#define RTSEMRW_CNT_RD_SHIFT 0
98#define RTSEMRW_CNT_RD_MASK (RTSEMRW_CNT_MASK << RTSEMRW_CNT_RD_SHIFT)
99#define RTSEMRW_CNT_WR_SHIFT 16
100#define RTSEMRW_CNT_WR_MASK (RTSEMRW_CNT_MASK << RTSEMRW_CNT_WR_SHIFT)
101#define RTSEMRW_DIR_SHIFT 31
102#define RTSEMRW_DIR_MASK RT_BIT_64(RTSEMRW_DIR_SHIFT)
103#define RTSEMRW_DIR_READ UINT64_C(0)
104#define RTSEMRW_DIR_WRITE UINT64_C(1)
105
106#define RTSEMRW_WAIT_CNT_RD_SHIFT 32
107#define RTSEMRW_WAIT_CNT_RD_MASK (RTSEMRW_CNT_MASK << RTSEMRW_WAIT_CNT_RD_SHIFT)
108//#define RTSEMRW_WAIT_CNT_WR_SHIFT 48
109//#define RTSEMRW_WAIT_CNT_WR_MASK (RTSEMRW_CNT_MASK << RTSEMRW_WAIT_CNT_WR_SHIFT)
110
111
112RTDECL(int) RTSemRWCreate(PRTSEMRW phRWSem)
113{
114 return RTSemRWCreateEx(phRWSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW");
115}
116RT_EXPORT_SYMBOL(RTSemRWCreate);
117
118
119RTDECL(int) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags,
120 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
121{
122 AssertReturn(!(fFlags & ~RTSEMRW_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
123
124 RTSEMRWINTERNAL *pThis = (RTSEMRWINTERNAL *)RTMemAlloc(sizeof(*pThis));
125 if (!pThis)
126 return VERR_NO_MEMORY;
127
128 int rc = RTSemEventMultiCreate(&pThis->hEvtRead);
129 if (RT_SUCCESS(rc))
130 {
131 rc = RTSemEventCreate(&pThis->hEvtWrite);
132 if (RT_SUCCESS(rc))
133 {
134 pThis->u32Magic = RTSEMRW_MAGIC;
135 pThis->u32Padding = 0;
136 pThis->u64State = 0;
137 pThis->hNativeWriter = NIL_RTNATIVETHREAD;
138 pThis->cWriterReads = 0;
139 pThis->cWriteRecursions = 0;
140 pThis->fNeedReset = false;
141#ifdef RTSEMRW_STRICT
142 bool const fLVEnabled = !(fFlags & RTSEMRW_FLAGS_NO_LOCK_VAL);
143 if (!pszNameFmt)
144 {
145 static uint32_t volatile s_iSemRWAnon = 0;
146 uint32_t i = ASMAtomicIncU32(&s_iSemRWAnon) - 1;
147 RTLockValidatorRecExclInit(&pThis->ValidatorWrite, hClass, uSubClass, pThis,
148 fLVEnabled, "RTSemRW-%u", i);
149 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, hClass, uSubClass, pThis,
150 false /*fSignaller*/, fLVEnabled, "RTSemRW-%u", i);
151 }
152 else
153 {
154 va_list va;
155 va_start(va, pszNameFmt);
156 RTLockValidatorRecExclInitV(&pThis->ValidatorWrite, hClass, uSubClass, pThis,
157 fLVEnabled, pszNameFmt, va);
158 va_end(va);
159 va_start(va, pszNameFmt);
160 RTLockValidatorRecSharedInitV(&pThis->ValidatorRead, hClass, uSubClass, pThis,
161 false /*fSignaller*/, fLVEnabled, pszNameFmt, va);
162 va_end(va);
163 }
164 RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core);
165#endif
166
167 *phRWSem = pThis;
168 return VINF_SUCCESS;
169 }
170 RTSemEventMultiDestroy(pThis->hEvtRead);
171 }
172 return rc;
173}
174RT_EXPORT_SYMBOL(RTSemRWCreateEx);
175
176
177RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem)
178{
179 /*
180 * Validate input.
181 */
182 RTSEMRWINTERNAL *pThis = hRWSem;
183 if (pThis == NIL_RTSEMRW)
184 return VINF_SUCCESS;
185 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
186 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
187 Assert(!(ASMAtomicReadU64(&pThis->u64State) & (RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK)));
188
189 /*
190 * Invalidate the object and free up the resources.
191 */
192 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
193
194 RTSEMEVENTMULTI hEvtRead;
195 ASMAtomicXchgHandle(&pThis->hEvtRead, NIL_RTSEMEVENTMULTI, &hEvtRead);
196 int rc = RTSemEventMultiDestroy(hEvtRead);
197 AssertRC(rc);
198
199 RTSEMEVENT hEvtWrite;
200 ASMAtomicXchgHandle(&pThis->hEvtWrite, NIL_RTSEMEVENT, &hEvtWrite);
201 rc = RTSemEventDestroy(hEvtWrite);
202 AssertRC(rc);
203
204#ifdef RTSEMRW_STRICT
205 RTLockValidatorRecSharedDelete(&pThis->ValidatorRead);
206 RTLockValidatorRecExclDelete(&pThis->ValidatorWrite);
207#endif
208 RTMemFree(pThis);
209 return VINF_SUCCESS;
210}
211RT_EXPORT_SYMBOL(RTSemRWDestroy);
212
213
214RTDECL(uint32_t) RTSemRWSetSubClass(RTSEMRW hRWSem, uint32_t uSubClass)
215{
216#ifdef RTSEMRW_STRICT
217 /*
218 * Validate handle.
219 */
220 struct RTSEMRWINTERNAL *pThis = hRWSem;
221 AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
222 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
223
224 RTLockValidatorRecSharedSetSubClass(&pThis->ValidatorRead, uSubClass);
225 return RTLockValidatorRecExclSetSubClass(&pThis->ValidatorWrite, uSubClass);
226#else
227 return RTLOCKVAL_SUB_CLASS_INVALID;
228#endif
229}
230RT_EXPORT_SYMBOL(RTSemRWSetSubClass);
231
232
233static int rtSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
234{
235 /*
236 * Validate input.
237 */
238 RTSEMRWINTERNAL *pThis = hRWSem;
239 if (pThis == NIL_RTSEMRW)
240 return VINF_SUCCESS;
241 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
242 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
243
244#ifdef RTSEMRW_STRICT
245 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
246 if (cMillies > 0)
247 {
248 int rc9;
249 RTNATIVETHREAD hNativeWriter;
250 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
251 if (hNativeWriter != NIL_RTTHREAD && hNativeWriter == RTThreadNativeSelf())
252 rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies);
253 else
254 rc9 = RTLockValidatorRecSharedCheckOrder(&pThis->ValidatorRead, hThreadSelf, pSrcPos, cMillies);
255 if (RT_FAILURE(rc9))
256 return rc9;
257 }
258#endif
259
260 /*
261 * Get cracking...
262 */
263 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
264 uint64_t u64OldState = u64State;
265
266 for (;;)
267 {
268 if ((u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT))
269 {
270 /* It flows in the right direction, try follow it before it changes. */
271 uint64_t c = (u64State & RTSEMRW_CNT_RD_MASK) >> RTSEMRW_CNT_RD_SHIFT;
272 c++;
273 Assert(c < RTSEMRW_CNT_MASK / 2);
274 u64State &= ~RTSEMRW_CNT_RD_MASK;
275 u64State |= c << RTSEMRW_CNT_RD_SHIFT;
276 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
277 {
278#ifdef RTSEMRW_STRICT
279 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
280#endif
281 break;
282 }
283 }
284 else if ((u64State & (RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK)) == 0)
285 {
286 /* Wrong direction, but we're alone here and can simply try switch the direction. */
287 u64State &= ~(RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK | RTSEMRW_DIR_MASK);
288 u64State |= (UINT64_C(1) << RTSEMRW_CNT_RD_SHIFT) | (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT);
289 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
290 {
291 Assert(!pThis->fNeedReset);
292#ifdef RTSEMRW_STRICT
293 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
294#endif
295 break;
296 }
297 }
298 else
299 {
300 /* Is the writer perhaps doing a read recursion? */
301 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
302 RTNATIVETHREAD hNativeWriter;
303 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
304 if (hNativeSelf == hNativeWriter)
305 {
306#ifdef RTSEMRW_STRICT
307 int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
308 if (RT_FAILURE(rc9))
309 return rc9;
310#endif
311 Assert(pThis->cWriterReads < UINT32_MAX / 2);
312 ASMAtomicIncU32(&pThis->cWriterReads);
313 return VINF_SUCCESS; /* don't break! */
314 }
315
316 /* If the timeout is 0, return already. */
317 if (!cMillies)
318 return VERR_TIMEOUT;
319
320 /* Add ourselves to the queue and wait for the direction to change. */
321 uint64_t c = (u64State & RTSEMRW_CNT_RD_MASK) >> RTSEMRW_CNT_RD_SHIFT;
322 c++;
323 Assert(c < RTSEMRW_CNT_MASK / 2);
324
325 uint64_t cWait = (u64State & RTSEMRW_WAIT_CNT_RD_MASK) >> RTSEMRW_WAIT_CNT_RD_SHIFT;
326 cWait++;
327 Assert(cWait <= c);
328 Assert(cWait < RTSEMRW_CNT_MASK / 2);
329
330 u64State &= ~(RTSEMRW_CNT_RD_MASK | RTSEMRW_WAIT_CNT_RD_MASK);
331 u64State |= (c << RTSEMRW_CNT_RD_SHIFT) | (cWait << RTSEMRW_WAIT_CNT_RD_SHIFT);
332
333 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
334 {
335 for (uint32_t iLoop = 0; ; iLoop++)
336 {
337 int rc;
338#ifdef RTSEMRW_STRICT
339 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true,
340 cMillies, RTTHREADSTATE_RW_READ, false);
341 if (RT_SUCCESS(rc))
342#else
343 RTTHREAD hThreadSelf = RTThreadSelf();
344 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
345#endif
346 {
347 if (fInterruptible)
348 rc = RTSemEventMultiWaitNoResume(pThis->hEvtRead, cMillies);
349 else
350 rc = RTSemEventMultiWait(pThis->hEvtRead, cMillies);
351 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
352 if (pThis->u32Magic != RTSEMRW_MAGIC)
353 return VERR_SEM_DESTROYED;
354 }
355 if (RT_FAILURE(rc))
356 {
357 /* Decrement the counts and return the error. */
358 for (;;)
359 {
360 u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
361 c = (u64State & RTSEMRW_CNT_RD_MASK) >> RTSEMRW_CNT_RD_SHIFT; Assert(c > 0);
362 c--;
363 cWait = (u64State & RTSEMRW_WAIT_CNT_RD_MASK) >> RTSEMRW_WAIT_CNT_RD_SHIFT; Assert(cWait > 0);
364 cWait--;
365 u64State &= ~(RTSEMRW_CNT_RD_MASK | RTSEMRW_WAIT_CNT_RD_MASK);
366 u64State |= (c << RTSEMRW_CNT_RD_SHIFT) | (cWait << RTSEMRW_WAIT_CNT_RD_SHIFT);
367 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
368 break;
369 }
370 return rc;
371 }
372
373 Assert(pThis->fNeedReset);
374 u64State = ASMAtomicReadU64(&pThis->u64State);
375 if ((u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT))
376 break;
377 AssertMsg(iLoop < 1, ("%u\n", iLoop));
378 }
379
380 /* Decrement the wait count and maybe reset the semaphore (if we're last). */
381 for (;;)
382 {
383 u64OldState = u64State;
384
385 cWait = (u64State & RTSEMRW_WAIT_CNT_RD_MASK) >> RTSEMRW_WAIT_CNT_RD_SHIFT;
386 Assert(cWait > 0);
387 cWait--;
388 u64State &= ~RTSEMRW_WAIT_CNT_RD_MASK;
389 u64State |= cWait << RTSEMRW_WAIT_CNT_RD_SHIFT;
390
391 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
392 {
393 if (cWait == 0)
394 {
395 if (ASMAtomicXchgBool(&pThis->fNeedReset, false))
396 {
397 int rc = RTSemEventMultiReset(pThis->hEvtRead);
398 AssertRCReturn(rc, rc);
399 }
400 }
401 break;
402 }
403 u64State = ASMAtomicReadU64(&pThis->u64State);
404 }
405
406#ifdef RTSEMRW_STRICT
407 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
408#endif
409 break;
410 }
411 }
412
413 if (pThis->u32Magic != RTSEMRW_MAGIC)
414 return VERR_SEM_DESTROYED;
415
416 ASMNopPause();
417 u64State = ASMAtomicReadU64(&pThis->u64State);
418 u64OldState = u64State;
419 }
420
421 /* got it! */
422 Assert((ASMAtomicReadU64(&pThis->u64State) & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT));
423 return VINF_SUCCESS;
424
425}
426
427
428RTDECL(int) RTSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
429{
430#ifndef RTSEMRW_STRICT
431 return rtSemRWRequestRead(hRWSem, cMillies, false, NULL);
432#else
433 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
434 return rtSemRWRequestRead(hRWSem, cMillies, false, &SrcPos);
435#endif
436}
437RT_EXPORT_SYMBOL(RTSemRWRequestRead);
438
439
440RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
441{
442 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
443 return rtSemRWRequestRead(hRWSem, cMillies, false, &SrcPos);
444}
445RT_EXPORT_SYMBOL(RTSemRWRequestReadDebug);
446
447
448RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
449{
450#ifndef RTSEMRW_STRICT
451 return rtSemRWRequestRead(hRWSem, cMillies, true, NULL);
452#else
453 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
454 return rtSemRWRequestRead(hRWSem, cMillies, true, &SrcPos);
455#endif
456}
457RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResume);
458
459
460RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
461{
462 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
463 return rtSemRWRequestRead(hRWSem, cMillies, true, &SrcPos);
464}
465RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResumeDebug);
466
467
468
469RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem)
470{
471 /*
472 * Validate handle.
473 */
474 RTSEMRWINTERNAL *pThis = hRWSem;
475 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
476 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
477
478 /*
479 * Check the direction and take action accordingly.
480 */
481 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
482 uint64_t u64OldState = u64State;
483 if ((u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT))
484 {
485#ifdef RTSEMRW_STRICT
486 int rc9 = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, NIL_RTTHREAD);
487 if (RT_FAILURE(rc9))
488 return rc9;
489#endif
490 for (;;)
491 {
492 uint64_t c = (u64State & RTSEMRW_CNT_RD_MASK) >> RTSEMRW_CNT_RD_SHIFT;
493 AssertReturn(c > 0, VERR_NOT_OWNER);
494 c--;
495
496 if ( c > 0
497 || (u64State & RTSEMRW_CNT_RD_MASK) == 0)
498 {
499 /* Don't change the direction. */
500 u64State &= ~RTSEMRW_CNT_RD_MASK;
501 u64State |= c << RTSEMRW_CNT_RD_SHIFT;
502 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
503 break;
504 }
505 else
506 {
507 /* Reverse the direction and signal the reader threads. */
508 u64State &= ~(RTSEMRW_CNT_RD_MASK | RTSEMRW_DIR_MASK);
509 u64State |= RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT;
510 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
511 {
512 int rc = RTSemEventSignal(pThis->hEvtWrite);
513 AssertRC(rc);
514 break;
515 }
516 }
517
518 ASMNopPause();
519 u64State = ASMAtomicReadU64(&pThis->u64State);
520 u64OldState = u64State;
521 }
522 }
523 else
524 {
525 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
526 RTNATIVETHREAD hNativeWriter;
527 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
528 AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
529 AssertReturn(pThis->cWriterReads > 0, VERR_NOT_OWNER);
530#ifdef RTSEMRW_STRICT
531 int rc = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
532 if (RT_FAILURE(rc))
533 return rc;
534#endif
535 ASMAtomicDecU32(&pThis->cWriterReads);
536 }
537
538 return VINF_SUCCESS;
539}
540RT_EXPORT_SYMBOL(RTSemRWReleaseRead);
541
542
543DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
544{
545 /*
546 * Validate input.
547 */
548 RTSEMRWINTERNAL *pThis = hRWSem;
549 if (pThis == NIL_RTSEMRW)
550 return VINF_SUCCESS;
551 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
552 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
553
554#ifdef RTSEMRW_STRICT
555 RTTHREAD hThreadSelf = NIL_RTTHREAD;
556 if (cMillies)
557 {
558 hThreadSelf = RTThreadSelfAutoAdopt();
559 int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies);
560 if (RT_FAILURE(rc9))
561 return rc9;
562 }
563#endif
564
565 /*
566 * Check if we're already the owner and just recursing.
567 */
568 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
569 RTNATIVETHREAD hNativeWriter;
570 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
571 if (hNativeSelf == hNativeWriter)
572 {
573 Assert((ASMAtomicReadU64(&pThis->u64State) & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT));
574#ifdef RTSEMRW_STRICT
575 int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorWrite, pSrcPos);
576 if (RT_FAILURE(rc9))
577 return rc9;
578#endif
579 Assert(pThis->cWriteRecursions < UINT32_MAX / 2);
580 ASMAtomicIncU32(&pThis->cWriteRecursions);
581 return VINF_SUCCESS;
582 }
583
584 /*
585 * Get cracking.
586 */
587 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
588 uint64_t u64OldState = u64State;
589
590 for (;;)
591 {
592 if ( (u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT)
593 || (u64State & (RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK)) != 0)
594 {
595 /* It flows in the right direction, try follow it before it changes. */
596 uint64_t c = (u64State & RTSEMRW_CNT_WR_MASK) >> RTSEMRW_CNT_WR_SHIFT;
597 c++;
598 Assert(c < RTSEMRW_CNT_MASK / 2);
599 u64State &= ~RTSEMRW_CNT_WR_MASK;
600 u64State |= c << RTSEMRW_CNT_WR_SHIFT;
601 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
602 break;
603 }
604 else if ((u64State & (RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK)) == 0)
605 {
606 /* Wrong direction, but we're alone here and can simply try switch the direction. */
607 u64State &= ~(RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK | RTSEMRW_DIR_MASK);
608 u64State |= (UINT64_C(1) << RTSEMRW_CNT_WR_SHIFT) | (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT);
609 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
610 break;
611 }
612 else if (!cMillies)
613 /* Wrong direction and we're not supposed to wait, just return. */
614 return VERR_TIMEOUT;
615 else
616 {
617 /* Add ourselves to the write count and break out to do the wait. */
618 uint64_t c = (u64State & RTSEMRW_CNT_WR_MASK) >> RTSEMRW_CNT_WR_SHIFT;
619 c++;
620 Assert(c < RTSEMRW_CNT_MASK / 2);
621 u64State &= ~RTSEMRW_CNT_WR_MASK;
622 u64State |= c << RTSEMRW_CNT_WR_SHIFT;
623 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
624 break;
625 }
626
627 if (pThis->u32Magic != RTSEMRW_MAGIC)
628 return VERR_SEM_DESTROYED;
629
630 ASMNopPause();
631 u64State = ASMAtomicReadU64(&pThis->u64State);
632 u64OldState = u64State;
633 }
634
635 /*
636 * If we're in write mode now try grab the ownership. Play fair if there
637 * are threads already waiting.
638 */
639 bool fDone = (u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT)
640 && ( ((u64State & RTSEMRW_CNT_WR_MASK) >> RTSEMRW_CNT_WR_SHIFT) == 1
641 || cMillies == 0);
642 if (fDone)
643 ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
644 if (!fDone)
645 {
646 /*
647 * Wait for our turn.
648 */
649 for (uint32_t iLoop = 0; ; iLoop++)
650 {
651 int rc;
652#ifdef RTSEMRW_STRICT
653 if (cMillies)
654 {
655 if (hThreadSelf == NIL_RTTHREAD)
656 hThreadSelf = RTThreadSelfAutoAdopt();
657 rc = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
658 cMillies, RTTHREADSTATE_RW_WRITE, false);
659 }
660 else
661 rc = VINF_SUCCESS;
662 if (RT_SUCCESS(rc))
663#else
664 RTTHREAD hThreadSelf = RTThreadSelf();
665 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
666#endif
667 {
668 if (fInterruptible)
669 rc = RTSemEventWaitNoResume(pThis->hEvtWrite, cMillies);
670 else
671 rc = RTSemEventWait(pThis->hEvtWrite, cMillies);
672 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
673 if (pThis->u32Magic != RTSEMRW_MAGIC)
674 return VERR_SEM_DESTROYED;
675 }
676 if (RT_FAILURE(rc))
677 {
678 /* Decrement the counts and return the error. */
679 for (;;)
680 {
681 u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
682 uint64_t c = (u64State & RTSEMRW_CNT_WR_MASK) >> RTSEMRW_CNT_WR_SHIFT; Assert(c > 0);
683 c--;
684 u64State &= ~RTSEMRW_CNT_WR_MASK;
685 u64State |= c << RTSEMRW_CNT_WR_SHIFT;
686 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
687 break;
688 }
689 return rc;
690 }
691
692 u64State = ASMAtomicReadU64(&pThis->u64State);
693 if ((u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT))
694 {
695 ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
696 if (fDone)
697 break;
698 }
699 AssertMsg(iLoop < 1000, ("%u\n", iLoop)); /* may loop a few times here... */
700 }
701 }
702
703 /*
704 * Got it!
705 */
706 Assert((ASMAtomicReadU64(&pThis->u64State) & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT));
707 ASMAtomicWriteU32(&pThis->cWriteRecursions, 1);
708 Assert(pThis->cWriterReads == 0);
709#ifdef RTSEMRW_STRICT
710 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
711#endif
712
713 return VINF_SUCCESS;
714}
715
716
717RTDECL(int) RTSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
718{
719#ifndef RTSEMRW_STRICT
720 return rtSemRWRequestWrite(hRWSem, cMillies, false, NULL);
721#else
722 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
723 return rtSemRWRequestWrite(hRWSem, cMillies, false, &SrcPos);
724#endif
725}
726RT_EXPORT_SYMBOL(RTSemRWRequestWrite);
727
728
729RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
730{
731 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
732 return rtSemRWRequestWrite(hRWSem, cMillies, false, &SrcPos);
733}
734RT_EXPORT_SYMBOL(RTSemRWRequestWriteDebug);
735
736
737RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
738{
739#ifndef RTSEMRW_STRICT
740 return rtSemRWRequestWrite(hRWSem, cMillies, true, NULL);
741#else
742 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
743 return rtSemRWRequestWrite(hRWSem, cMillies, true, &SrcPos);
744#endif
745}
746RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResume);
747
748
749RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
750{
751 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
752 return rtSemRWRequestWrite(hRWSem, cMillies, true, &SrcPos);
753}
754RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResumeDebug);
755
756
757RTDECL(int) RTSemRWReleaseWrite(RTSEMRW hRWSem)
758{
759
760 /*
761 * Validate handle.
762 */
763 struct RTSEMRWINTERNAL *pThis = hRWSem;
764 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
765 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
766
767 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
768 RTNATIVETHREAD hNativeWriter;
769 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
770 AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
771
772 /*
773 * Unwind a recursion.
774 */
775 if (pThis->cWriteRecursions == 1)
776 {
777 AssertReturn(pThis->cWriterReads == 0, VERR_WRONG_ORDER); /* (must release all read recursions before the final write.) */
778#ifdef RTSEMRW_STRICT
779 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, true);
780 if (RT_FAILURE(rc9))
781 return rc9;
782#endif
783 /*
784 * Update the state.
785 */
786 ASMAtomicWriteU32(&pThis->cWriteRecursions, 0);
787 ASMAtomicWriteHandle(&pThis->hNativeWriter, NIL_RTNATIVETHREAD);
788
789 for (;;)
790 {
791 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
792 uint64_t u64OldState = u64State;
793
794 uint64_t c = (u64State & RTSEMRW_CNT_WR_MASK) >> RTSEMRW_CNT_WR_SHIFT;
795 Assert(c > 0);
796 c--;
797
798 if ( c > 0
799 || (u64State & RTSEMRW_CNT_RD_MASK) == 0)
800 {
801 /* Don't change the direction, wait up the next writer if any. */
802 u64State &= ~RTSEMRW_CNT_WR_MASK;
803 u64State |= c << RTSEMRW_CNT_WR_SHIFT;
804 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
805 {
806 if (c > 0)
807 {
808 int rc = RTSemEventSignal(pThis->hEvtWrite);
809 AssertRC(rc);
810 }
811 break;
812 }
813 }
814 else
815 {
816 /* Reverse the direction and signal the reader threads. */
817 u64State &= ~(RTSEMRW_CNT_WR_MASK | RTSEMRW_DIR_MASK);
818 u64State |= RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT;
819 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
820 {
821 Assert(!pThis->fNeedReset);
822 ASMAtomicWriteBool(&pThis->fNeedReset, true);
823 int rc = RTSemEventMultiSignal(pThis->hEvtRead);
824 AssertRC(rc);
825 break;
826 }
827 }
828
829 ASMNopPause();
830 if (pThis->u32Magic != RTSEMRW_MAGIC)
831 return VERR_SEM_DESTROYED;
832 }
833 }
834 else
835 {
836 Assert(pThis->cWriteRecursions != 0);
837#ifdef RTSEMRW_STRICT
838 int rc9 = RTLockValidatorRecExclUnwind(&pThis->ValidatorWrite);
839 if (RT_FAILURE(rc9))
840 return rc9;
841#endif
842 ASMAtomicDecU32(&pThis->cWriteRecursions);
843 }
844
845 return VINF_SUCCESS;
846}
847RT_EXPORT_SYMBOL(RTSemRWReleaseWrite);
848
849
850RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW hRWSem)
851{
852 /*
853 * Validate handle.
854 */
855 struct RTSEMRWINTERNAL *pThis = hRWSem;
856 AssertPtrReturn(pThis, false);
857 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, false);
858
859 /*
860 * Check ownership.
861 */
862 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
863 RTNATIVETHREAD hNativeWriter;
864 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
865 return hNativeWriter == hNativeSelf;
866}
867RT_EXPORT_SYMBOL(RTSemRWIsWriteOwner);
868
869
870RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear)
871{
872 /*
873 * Validate handle.
874 */
875 struct RTSEMRWINTERNAL *pThis = hRWSem;
876 AssertPtrReturn(pThis, false);
877 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, false);
878
879 /*
880 * Inspect the state.
881 */
882 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
883 if ((u64State & RTSEMRW_DIR_MASK) == (RTSEMRW_DIR_WRITE << RTSEMRW_DIR_SHIFT))
884 {
885 /*
886 * It's in write mode, so we can only be a reader if we're also the
887 * current writer.
888 */
889 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
890 RTNATIVETHREAD hWriter;
891 ASMAtomicUoReadHandle(&pThis->hWriter, &hWriter);
892 return hWriter == hNativeSelf;
893 }
894
895 /*
896 * Read mode. If there are no current readers, then we cannot be a reader.
897 */
898 if (!(u64State & RTSEMRW_CNT_RD_MASK))
899 return false;
900
901#ifdef RTSEMRW_STRICT
902 /*
903 * Ask the lock validator.
904 */
905 return RTLockValidatorRecSharedIsOwner(&pThis->ValidatorRead, NIL_RTTHREAD);
906#else
907 /*
908 * Ok, we don't know, just tell the caller what he want to hear.
909 */
910 return fWannaHear;
911#endif
912}
913RT_EXPORT_SYMBOL(RTSemRWIsReadOwner);
914
915
916RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW hRWSem)
917{
918 /*
919 * Validate handle.
920 */
921 struct RTSEMRWINTERNAL *pThis = hRWSem;
922 AssertPtrReturn(pThis, 0);
923 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, 0);
924
925 /*
926 * Return the requested data.
927 */
928 return pThis->cWriteRecursions;
929}
930RT_EXPORT_SYMBOL(RTSemRWGetWriteRecursion);
931
932
933RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW hRWSem)
934{
935 /*
936 * Validate handle.
937 */
938 struct RTSEMRWINTERNAL *pThis = hRWSem;
939 AssertPtrReturn(pThis, 0);
940 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, 0);
941
942 /*
943 * Return the requested data.
944 */
945 return pThis->cWriterReads;
946}
947RT_EXPORT_SYMBOL(RTSemRWGetWriterReadRecursion);
948
949
950RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW hRWSem)
951{
952 /*
953 * Validate input.
954 */
955 struct RTSEMRWINTERNAL *pThis = hRWSem;
956 AssertPtrReturn(pThis, 0);
957 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
958 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
959 0);
960
961 /*
962 * Return the requested data.
963 */
964 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
965 if ((u64State & RTSEMRW_DIR_MASK) != (RTSEMRW_DIR_READ << RTSEMRW_DIR_SHIFT))
966 return 0;
967 return (u64State & RTSEMRW_CNT_RD_MASK) >> RTSEMRW_CNT_RD_SHIFT;
968}
969RT_EXPORT_SYMBOL(RTSemRWGetReadCount);
970
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