VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.5 KB
Line 
1/* $Id: semrw-posix.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Read-Write Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/semaphore.h>
42#include "internal/iprt.h"
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/err.h>
47#include <iprt/lockvalidator.h>
48#include <iprt/mem.h>
49#include <iprt/thread.h>
50
51#include <errno.h>
52#include <pthread.h>
53#include <unistd.h>
54#include <sys/time.h>
55
56#include "internal/magics.h"
57#include "internal/strict.h"
58
59
60/*********************************************************************************************************************************
61* Defined Constants And Macros *
62*********************************************************************************************************************************/
63/** @todo move this to r3/posix/something.h. */
64#ifdef RT_OS_SOLARIS
65# define ATOMIC_GET_PTHREAD_T(ppvVar, pThread) ASMAtomicReadSize(ppvVar, pThread)
66# define ATOMIC_SET_PTHREAD_T(ppvVar, pThread) ASMAtomicWriteSize(ppvVar, pThread)
67#else
68AssertCompileSize(pthread_t, sizeof(void *));
69# define ATOMIC_GET_PTHREAD_T(ppvVar, pThread) do { *(pThread) = (pthread_t)ASMAtomicReadPtr((void * volatile *)ppvVar); } while (0)
70# define ATOMIC_SET_PTHREAD_T(ppvVar, pThread) ASMAtomicWritePtr((void * volatile *)ppvVar, (void *)pThread)
71#endif
72
73
74/*********************************************************************************************************************************
75* Structures and Typedefs *
76*********************************************************************************************************************************/
77/** Posix internal representation of a read-write semaphore. */
78struct RTSEMRWINTERNAL
79{
80 /** The usual magic. (RTSEMRW_MAGIC) */
81 uint32_t u32Magic;
82 /** The number of readers.
83 * (For preventing screwing up the lock on linux). */
84 uint32_t volatile cReaders;
85 /** Number of write recursions. */
86 uint32_t cWrites;
87 /** Number of read recursions by the writer. */
88 uint32_t cWriterReads;
89 /** The write owner of the lock. */
90 volatile pthread_t Writer;
91 /** pthread rwlock. */
92 pthread_rwlock_t RWLock;
93#ifdef RTSEMRW_STRICT
94 /** The validator record for the writer. */
95 RTLOCKVALRECEXCL ValidatorWrite;
96 /** The validator record for the readers. */
97 RTLOCKVALRECSHRD ValidatorRead;
98#endif
99};
100
101
102
103#undef RTSemRWCreate
104RTDECL(int) RTSemRWCreate(PRTSEMRW phRWSem)
105{
106 return RTSemRWCreateEx(phRWSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW");
107}
108
109
110RTDECL(int) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags,
111 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
112{
113 AssertReturn(!(fFlags & ~RTSEMRW_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
114
115 /*
116 * Allocate handle.
117 */
118 int rc;
119 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
120 if (pThis)
121 {
122 /*
123 * Create the rwlock.
124 */
125 rc = pthread_rwlock_init(&pThis->RWLock, NULL);
126 if (!rc)
127 {
128 pThis->u32Magic = RTSEMRW_MAGIC;
129 pThis->cReaders = 0;
130 pThis->cWrites = 0;
131 pThis->cWriterReads = 0;
132 pThis->Writer = (pthread_t)-1;
133#ifdef RTSEMRW_STRICT
134 bool const fLVEnabled = !(fFlags & RTSEMRW_FLAGS_NO_LOCK_VAL);
135 if (!pszNameFmt)
136 {
137 static uint32_t volatile s_iSemRWAnon = 0;
138 uint32_t i = ASMAtomicIncU32(&s_iSemRWAnon) - 1;
139 RTLockValidatorRecExclInit(&pThis->ValidatorWrite, hClass, uSubClass, pThis,
140 fLVEnabled, "RTSemRW-%u", i);
141 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, hClass, uSubClass, pThis,
142 false /*fSignaller*/, fLVEnabled, "RTSemRW-%u", i);
143 }
144 else
145 {
146 va_list va;
147 va_start(va, pszNameFmt);
148 RTLockValidatorRecExclInitV(&pThis->ValidatorWrite, hClass, uSubClass, pThis,
149 fLVEnabled, pszNameFmt, va);
150 va_end(va);
151 va_start(va, pszNameFmt);
152 RTLockValidatorRecSharedInitV(&pThis->ValidatorRead, hClass, uSubClass, pThis,
153 false /*fSignaller*/, fLVEnabled, pszNameFmt, va);
154 va_end(va);
155 }
156 RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core);
157#else
158 RT_NOREF_PV(hClass); RT_NOREF_PV(uSubClass); RT_NOREF_PV(pszNameFmt);
159#endif
160 *phRWSem = pThis;
161 return VINF_SUCCESS;
162 }
163
164 rc = RTErrConvertFromErrno(rc);
165 RTMemFree(pThis);
166 }
167 else
168 rc = VERR_NO_MEMORY;
169
170 return rc;
171}
172
173
174RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem)
175{
176 /*
177 * Validate input, nil handle is fine.
178 */
179 struct RTSEMRWINTERNAL *pThis = hRWSem;
180 if (pThis == NIL_RTSEMRW)
181 return VINF_SUCCESS;
182 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
183 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
184 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
185 VERR_INVALID_HANDLE);
186 Assert(pThis->Writer == (pthread_t)-1);
187 Assert(!pThis->cReaders);
188 Assert(!pThis->cWrites);
189 Assert(!pThis->cWriterReads);
190
191 /*
192 * Try destroy it.
193 */
194 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
195 int rc = pthread_rwlock_destroy(&pThis->RWLock);
196 if (!rc)
197 {
198#ifdef RTSEMRW_STRICT
199 RTLockValidatorRecSharedDelete(&pThis->ValidatorRead);
200 RTLockValidatorRecExclDelete(&pThis->ValidatorWrite);
201#endif
202 RTMemFree(pThis);
203 rc = VINF_SUCCESS;
204 }
205 else
206 {
207 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMRW_MAGIC);
208 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", hRWSem, rc));
209 rc = RTErrConvertFromErrno(rc);
210 }
211
212 return rc;
213}
214
215
216RTDECL(uint32_t) RTSemRWSetSubClass(RTSEMRW hRWSem, uint32_t uSubClass)
217{
218#ifdef RTSEMRW_STRICT
219 /*
220 * Validate handle.
221 */
222 struct RTSEMRWINTERNAL *pThis = hRWSem;
223 AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
224 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
225
226 RTLockValidatorRecSharedSetSubClass(&pThis->ValidatorRead, uSubClass);
227 return RTLockValidatorRecExclSetSubClass(&pThis->ValidatorWrite, uSubClass);
228#else
229 RT_NOREF_PV(hRWSem); RT_NOREF_PV(uSubClass);
230 return RTLOCKVAL_SUB_CLASS_INVALID;
231#endif
232}
233
234
235DECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies, PCRTLOCKVALSRCPOS pSrcPos)
236{
237 /*
238 * Validate input.
239 */
240 struct RTSEMRWINTERNAL *pThis = hRWSem;
241 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
242 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
243 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
244 VERR_INVALID_HANDLE);
245
246 /*
247 * Check if it's the writer (implement write+read recursion).
248 */
249 pthread_t Self = pthread_self();
250 pthread_t Writer;
251 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
252 if (Writer == Self)
253 {
254#ifdef RTSEMRW_STRICT
255 int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
256 if (RT_FAILURE(rc9))
257 return rc9;
258#endif
259 Assert(pThis->cWriterReads < INT32_MAX);
260 pThis->cWriterReads++;
261 return VINF_SUCCESS;
262 }
263
264 /*
265 * Try lock it.
266 */
267 RTTHREAD hThreadSelf = NIL_RTTHREAD;
268 if (cMillies > 0)
269 {
270#ifdef RTSEMRW_STRICT
271 hThreadSelf = RTThreadSelfAutoAdopt();
272 int rc9 = RTLockValidatorRecSharedCheckOrderAndBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true,
273 cMillies, RTTHREADSTATE_RW_READ, true);
274 if (RT_FAILURE(rc9))
275 return rc9;
276#else
277 hThreadSelf = RTThreadSelf();
278 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, true);
279 RT_NOREF_PV(pSrcPos);
280#endif
281 }
282
283 if (cMillies == RT_INDEFINITE_WAIT)
284 {
285 /* take rwlock */
286 int rc = pthread_rwlock_rdlock(&pThis->RWLock);
287 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
288 if (rc)
289 {
290 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", hRWSem, rc));
291 return RTErrConvertFromErrno(rc);
292 }
293 }
294 else
295 {
296#ifdef RT_OS_DARWIN
297 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
298 return VERR_NOT_IMPLEMENTED;
299
300#else /* !RT_OS_DARWIN */
301 /*
302 * Get current time and calc end of wait time.
303 */
304 struct timespec ts = {0,0};
305 clock_gettime(CLOCK_REALTIME, &ts);
306 if (cMillies != 0)
307 {
308 ts.tv_nsec += (cMillies % 1000) * 1000000;
309 ts.tv_sec += cMillies / 1000;
310 if (ts.tv_nsec >= 1000000000)
311 {
312 ts.tv_nsec -= 1000000000;
313 ts.tv_sec++;
314 }
315 }
316
317 /* take rwlock */
318 int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
319 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
320 if (rc)
321 {
322 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", hRWSem, rc));
323 return RTErrConvertFromErrno(rc);
324 }
325#endif /* !RT_OS_DARWIN */
326 }
327
328 ASMAtomicIncU32(&pThis->cReaders);
329#ifdef RTSEMRW_STRICT
330 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
331#endif
332 return VINF_SUCCESS;
333}
334
335
336#undef RTSemRWRequestRead
337RTDECL(int) RTSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
338{
339#ifndef RTSEMRW_STRICT
340 return rtSemRWRequestRead(hRWSem, cMillies, NULL);
341#else
342 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
343 return rtSemRWRequestRead(hRWSem, cMillies, &SrcPos);
344#endif
345}
346
347
348RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
349{
350 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
351 return rtSemRWRequestRead(hRWSem, cMillies, &SrcPos);
352}
353
354
355#undef RTSemRWRequestReadNoResume
356RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
357{
358 /* EINTR isn't returned by the wait functions we're using. */
359#ifndef RTSEMRW_STRICT
360 return rtSemRWRequestRead(hRWSem, cMillies, NULL);
361#else
362 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
363 return rtSemRWRequestRead(hRWSem, cMillies, &SrcPos);
364#endif
365}
366
367
368RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
369{
370 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
371 return rtSemRWRequestRead(hRWSem, cMillies, &SrcPos);
372}
373
374
375RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem)
376{
377 /*
378 * Validate input.
379 */
380 struct RTSEMRWINTERNAL *pThis = hRWSem;
381 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
382 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
383 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
384 VERR_INVALID_HANDLE);
385
386 /*
387 * Check if it's the writer.
388 */
389 pthread_t Self = pthread_self();
390 pthread_t Writer;
391 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
392 if (Writer == Self)
393 {
394 AssertMsgReturn(pThis->cWriterReads > 0, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
395#ifdef RTSEMRW_STRICT
396 int rc9 = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
397 if (RT_FAILURE(rc9))
398 return rc9;
399#endif
400 pThis->cWriterReads--;
401 return VINF_SUCCESS;
402 }
403
404 /*
405 * Try unlock it.
406 */
407#ifdef RTSEMRW_STRICT
408 int rc9 = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, RTThreadSelf());
409 if (RT_FAILURE(rc9))
410 return rc9;
411#endif
412#ifdef RT_OS_LINUX /* glibc (at least 2.8) may screw up when unlocking a lock we don't own. */
413 if (ASMAtomicReadU32(&pThis->cReaders) == 0)
414 {
415 AssertMsgFailed(("Not owner of %p\n", pThis));
416 return VERR_NOT_OWNER;
417 }
418#endif
419 ASMAtomicDecU32(&pThis->cReaders);
420 int rc = pthread_rwlock_unlock(&pThis->RWLock);
421 if (rc)
422 {
423 ASMAtomicIncU32(&pThis->cReaders);
424 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", hRWSem, rc));
425 return RTErrConvertFromErrno(rc);
426 }
427 return VINF_SUCCESS;
428}
429
430
431DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies, PCRTLOCKVALSRCPOS pSrcPos)
432{
433 /*
434 * Validate input.
435 */
436 struct RTSEMRWINTERNAL *pThis = hRWSem;
437 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
438 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
439 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
440 VERR_INVALID_HANDLE);
441
442 /*
443 * Recursion?
444 */
445 pthread_t Self = pthread_self();
446 pthread_t Writer;
447 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
448 if (Writer == Self)
449 {
450#ifdef RTSEMRW_STRICT
451 int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorWrite, pSrcPos);
452 if (RT_FAILURE(rc9))
453 return rc9;
454#endif
455 Assert(pThis->cWrites < INT32_MAX);
456 pThis->cWrites++;
457 return VINF_SUCCESS;
458 }
459
460 /*
461 * Try lock it.
462 */
463 RTTHREAD hThreadSelf = NIL_RTTHREAD;
464 if (cMillies)
465 {
466#ifdef RTSEMRW_STRICT
467 hThreadSelf = RTThreadSelfAutoAdopt();
468 int rc9 = RTLockValidatorRecExclCheckOrderAndBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
469 cMillies, RTTHREADSTATE_RW_WRITE, true);
470 if (RT_FAILURE(rc9))
471 return rc9;
472#else
473 hThreadSelf = RTThreadSelf();
474 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, true);
475 RT_NOREF_PV(pSrcPos);
476#endif
477 }
478
479 if (cMillies == RT_INDEFINITE_WAIT)
480 {
481 /* take rwlock */
482 int rc = pthread_rwlock_wrlock(&pThis->RWLock);
483 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
484 if (rc)
485 {
486 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", hRWSem, rc));
487 return RTErrConvertFromErrno(rc);
488 }
489 }
490 else
491 {
492#ifdef RT_OS_DARWIN
493 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
494 return VERR_NOT_IMPLEMENTED;
495#else /* !RT_OS_DARWIN */
496 /*
497 * Get current time and calc end of wait time.
498 */
499 struct timespec ts = {0,0};
500 clock_gettime(CLOCK_REALTIME, &ts);
501 if (cMillies != 0)
502 {
503 ts.tv_nsec += (cMillies % 1000) * 1000000;
504 ts.tv_sec += cMillies / 1000;
505 if (ts.tv_nsec >= 1000000000)
506 {
507 ts.tv_nsec -= 1000000000;
508 ts.tv_sec++;
509 }
510 }
511
512 /* take rwlock */
513 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
514 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
515 if (rc)
516 {
517 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", hRWSem, rc));
518 return RTErrConvertFromErrno(rc);
519 }
520#endif /* !RT_OS_DARWIN */
521 }
522
523 ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
524 pThis->cWrites = 1;
525 Assert(!pThis->cReaders);
526#ifdef RTSEMRW_STRICT
527 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
528#endif
529 return VINF_SUCCESS;
530}
531
532
533#undef RTSemRWRequestWrite
534RTDECL(int) RTSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
535{
536#ifndef RTSEMRW_STRICT
537 return rtSemRWRequestWrite(hRWSem, cMillies, NULL);
538#else
539 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
540 return rtSemRWRequestWrite(hRWSem, cMillies, &SrcPos);
541#endif
542}
543
544
545RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
546{
547 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
548 return rtSemRWRequestWrite(hRWSem, cMillies, &SrcPos);
549}
550
551
552#undef RTSemRWRequestWriteNoResume
553RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies)
554{
555 /* EINTR isn't returned by the wait functions we're using. */
556#ifndef RTSEMRW_STRICT
557 return rtSemRWRequestWrite(hRWSem, cMillies, NULL);
558#else
559 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
560 return rtSemRWRequestWrite(hRWSem, cMillies, &SrcPos);
561#endif
562}
563
564
565RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
566{
567 /* EINTR isn't returned by the wait functions we're using. */
568 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
569 return rtSemRWRequestWrite(hRWSem, cMillies, &SrcPos);
570}
571
572
573RTDECL(int) RTSemRWReleaseWrite(RTSEMRW hRWSem)
574{
575 /*
576 * Validate input.
577 */
578 struct RTSEMRWINTERNAL *pThis = hRWSem;
579 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
580 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
581 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
582 VERR_INVALID_HANDLE);
583
584 /*
585 * Verify ownership and implement recursion.
586 */
587 pthread_t Self = pthread_self();
588 pthread_t Writer;
589 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
590 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
591 AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
592
593 if (pThis->cWrites > 1)
594 {
595#ifdef RTSEMRW_STRICT
596 int rc9 = RTLockValidatorRecExclUnwind(&pThis->ValidatorWrite);
597 if (RT_FAILURE(rc9))
598 return rc9;
599#endif
600 pThis->cWrites--;
601 return VINF_SUCCESS;
602 }
603
604 /*
605 * Try unlock it.
606 */
607#ifdef RTSEMRW_STRICT
608 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, true);
609 if (RT_FAILURE(rc9))
610 return rc9;
611#endif
612
613 pThis->cWrites--;
614 ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
615 int rc = pthread_rwlock_unlock(&pThis->RWLock);
616 if (rc)
617 {
618 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", hRWSem, rc));
619 return RTErrConvertFromErrno(rc);
620 }
621
622 return VINF_SUCCESS;
623}
624
625
626RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW hRWSem)
627{
628 /*
629 * Validate input.
630 */
631 struct RTSEMRWINTERNAL *pThis = hRWSem;
632 AssertPtrReturn(pThis, false);
633 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
634 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
635 false);
636
637 /*
638 * Check ownership.
639 */
640 pthread_t Self = pthread_self();
641 pthread_t Writer;
642 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
643 return Writer == Self;
644}
645
646
647RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear)
648{
649 /*
650 * Validate handle.
651 */
652 struct RTSEMRWINTERNAL *pThis = hRWSem;
653 AssertPtrReturn(pThis, false);
654 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, false);
655
656 /*
657 * Check write ownership. The writer is also a valid reader.
658 */
659 pthread_t Self = pthread_self();
660 pthread_t Writer;
661 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
662 if (Writer == Self)
663 return true;
664 if (Writer != (pthread_t)-1)
665 return false;
666
667 /*
668 * If there are no readers, we cannot be one of them, can we?
669 */
670 if (ASMAtomicReadU32(&pThis->cReaders) == 0)
671 return false;
672
673#ifdef RTSEMRW_STRICT
674 /*
675 * Ask the lock validator.
676 */
677 NOREF(fWannaHear);
678 return RTLockValidatorRecSharedIsOwner(&pThis->ValidatorRead, NIL_RTTHREAD);
679#else
680 /*
681 * Just tell the caller what he want to hear.
682 */
683 return fWannaHear;
684#endif
685}
686RT_EXPORT_SYMBOL(RTSemRWIsReadOwner);
687
688
689RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW hRWSem)
690{
691 /*
692 * Validate input.
693 */
694 struct RTSEMRWINTERNAL *pThis = hRWSem;
695 AssertPtrReturn(pThis, 0);
696 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
697 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
698 0);
699
700 /*
701 * Return the requested data.
702 */
703 return pThis->cWrites;
704}
705
706
707RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW hRWSem)
708{
709 /*
710 * Validate input.
711 */
712 struct RTSEMRWINTERNAL *pThis = hRWSem;
713 AssertPtrReturn(pThis, 0);
714 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
715 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
716 0);
717
718 /*
719 * Return the requested data.
720 */
721 return pThis->cWriterReads;
722}
723
724
725RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW hRWSem)
726{
727 /*
728 * Validate input.
729 */
730 struct RTSEMRWINTERNAL *pThis = hRWSem;
731 AssertPtrReturn(pThis, 0);
732 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
733 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
734 0);
735
736 /*
737 * Return the requested data.
738 */
739 return pThis->cReaders;
740}
741
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use