VirtualBox

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

Last change on this file was 103141, checked in by vboxsync, 4 months ago

Runtime: Some warning fixes about externally visible functions which should be static, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.5 KB
RevLine 
[1]1/* $Id: semmutex-posix.cpp 103141 2024-01-31 15:03:29Z vboxsync $ */
2/** @file
[8245]3 * IPRT - Mutex Semaphore, POSIX.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[5999]11 *
[96407]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 *
[5999]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]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
[5999]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.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[1]35 */
36
[57358]37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[1]41#include <iprt/semaphore.h>
[25373]42#include "internal/iprt.h"
43
[1]44#include <iprt/alloc.h>
45#include <iprt/asm.h>
[25373]46#include <iprt/assert.h>
[1]47#include <iprt/err.h>
[25373]48#include <iprt/lockvalidator.h>
49#include <iprt/thread.h>
50#include "internal/magics.h"
[8651]51#include "internal/strict.h"
[1]52
53#include <errno.h>
54#include <pthread.h>
55#include <unistd.h>
56#include <sys/time.h>
57
58
[57358]59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
[1]62/** Posix internal representation of a Mutex semaphore. */
63struct RTSEMMUTEXINTERNAL
64{
65 /** pthread mutex. */
66 pthread_mutex_t Mutex;
67 /** The owner of the mutex. */
68 volatile pthread_t Owner;
69 /** Nesting count. */
70 volatile uint32_t cNesting;
[25373]71 /** Magic value (RTSEMMUTEX_MAGIC). */
72 uint32_t u32Magic;
73#ifdef RTSEMMUTEX_STRICT
74 /** Lock validator record associated with this mutex. */
[25607]75 RTLOCKVALRECEXCL ValidatorRec;
[25373]76#endif
[1]77};
78
[63004]79#if defined(RT_OS_DARWIN) || defined(RT_OS_NETBSD)
[43558]80/**
[63052]81 * This function is a crude approximation of pthread_mutex_timedlock.
[43558]82 */
[103141]83static int rtSemFallbackPthreadMutexTimedlock(pthread_mutex_t *mutex, RTMSINTERVAL cMillies)
[43558]84{
[63052]85 struct timespec ts;
86 int rc;
87
88 rc = pthread_mutex_trylock(mutex);
89 if (rc != EBUSY)
90 return rc;
91
92 ts.tv_sec = cMillies / 1000;
93 ts.tv_nsec = (cMillies % 1000) * 1000000;
94
95 while (ts.tv_sec > 0 || ts.tv_nsec > 0)
[43558]96 {
[63052]97 struct timespec delta, remaining;
98
99 if (ts.tv_sec > 0)
[43558]100 {
[63052]101 delta.tv_sec = 1;
102 delta.tv_nsec = 0;
103 ts.tv_sec--;
104 }
105 else
106 {
107 delta.tv_sec = 0;
108 delta.tv_nsec = ts.tv_nsec;
109 ts.tv_nsec = 0;
110 }
[63549]111
[63052]112 nanosleep(&delta, &remaining);
[1]113
[63052]114 rc = pthread_mutex_trylock(mutex);
115 if (rc != EBUSY)
116 return rc;
[43560]117
[63052]118 if (RT_UNLIKELY(remaining.tv_nsec > 0 || remaining.tv_sec > 0))
119 {
120 ts.tv_sec += remaining.tv_sec;
121 ts.tv_nsec += remaining.tv_nsec;
122 if (ts.tv_nsec >= 1000000000)
[43560]123 {
[63052]124 ts.tv_nsec -= 1000000000;
125 ts.tv_sec++;
[43560]126 }
[63052]127 }
128 }
[43560]129
[63052]130 return ETIMEDOUT;
[43558]131}
132#endif
133
134
[25711]135#undef RTSemMutexCreate
136RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
137{
138 return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
139}
[1]140
[25378]141
[25711]142RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
143 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
[1]144{
[25711]145 AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
[1]146
147 /*
148 * Allocate semaphore handle.
149 */
[25711]150 int rc;
[25373]151 struct RTSEMMUTEXINTERNAL *pThis = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
152 if (pThis)
[1]153 {
154 /*
155 * Create the semaphore.
156 */
[61751]157 rc = pthread_mutex_init(&pThis->Mutex, NULL);
[1]158 if (!rc)
159 {
[61751]160 pThis->Owner = (pthread_t)-1;
161 pThis->cNesting = 0;
162 pThis->u32Magic = RTSEMMUTEX_MAGIC;
163#ifdef RTSEMMUTEX_STRICT
164 if (!pszNameFmt)
[1]165 {
[61751]166 static uint32_t volatile s_iMutexAnon = 0;
167 RTLockValidatorRecExclInit(&pThis->ValidatorRec, hClass, uSubClass, pThis,
168 !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL),
169 "RTSemMutex-%u", ASMAtomicIncU32(&s_iMutexAnon) - 1);
170 }
171 else
172 {
173 va_list va;
174 va_start(va, pszNameFmt);
175 RTLockValidatorRecExclInitV(&pThis->ValidatorRec, hClass, uSubClass, pThis,
176 !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL), pszNameFmt, va);
177 va_end(va);
178 }
[62564]179#else
180 RT_NOREF_PV(hClass); RT_NOREF_PV(uSubClass); RT_NOREF_PV(pszNameFmt);
[25373]181#endif
[1]182
[61751]183 *phMutexSem = pThis;
184 return VINF_SUCCESS;
[1]185 }
[25373]186 RTMemFree(pThis);
[1]187 }
188 else
189 rc = VERR_NO_MEMORY;
190
191 return rc;
192}
193
194
[25721]195RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
[1]196{
197 /*
198 * Validate input.
199 */
[25721]200 if (hMutexSem == NIL_RTSEMMUTEX)
[25373]201 return VINF_SUCCESS;
[25721]202 struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25373]203 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
204 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
[1]205
206 /*
207 * Try destroy it.
208 */
[25373]209 int rc = pthread_mutex_destroy(&pThis->Mutex);
[1]210 if (rc)
211 {
[25721]212 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", hMutexSem, rc));
[1]213 return RTErrConvertFromErrno(rc);
214 }
215
216 /*
217 * Free the memory and be gone.
218 */
[25373]219 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD);
220 pThis->Owner = (pthread_t)-1;
221 pThis->cNesting = UINT32_MAX;
222#ifdef RTSEMMUTEX_STRICT
[25607]223 RTLockValidatorRecExclDelete(&pThis->ValidatorRec);
[25373]224#endif
225 RTMemTmpFree(pThis);
[1]226
227 return VINF_SUCCESS;
228}
229
230
[25711]231RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass)
232{
233#ifdef RTSEMMUTEX_STRICT
234 /*
235 * Validate.
236 */
237 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
238 AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
239 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
240
241 return RTLockValidatorRecExclSetSubClass(&pThis->ValidatorRec, uSubClass);
242#else
[62564]243 RT_NOREF_PV(hMutexSem); RT_NOREF_PV(uSubClass);
[25711]244 return RTLOCKVAL_SUB_CLASS_INVALID;
245#endif
246}
247
248
[25724]249DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, PCRTLOCKVALSRCPOS pSrcPos)
[1]250{
251 /*
252 * Validate input.
253 */
[25721]254 struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25373]255 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
256 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
[1]257
258 /*
259 * Check if nested request.
260 */
[25373]261 pthread_t Self = pthread_self();
262 if ( pThis->Owner == Self
263 && pThis->cNesting > 0)
[1]264 {
[25614]265#ifdef RTSEMMUTEX_STRICT
266 int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorRec, pSrcPos);
267 if (RT_FAILURE(rc9))
268 return rc9;
269#endif
[25373]270 ASMAtomicIncU32(&pThis->cNesting);
[1]271 return VINF_SUCCESS;
272 }
273
274 /*
275 * Lock it.
276 */
[25614]277 RTTHREAD hThreadSelf = NIL_RTTHREAD;
[25467]278 if (cMillies != 0)
279 {
280#ifdef RTSEMMUTEX_STRICT
[25614]281 hThreadSelf = RTThreadSelfAutoAdopt();
[25638]282 int rc9 = RTLockValidatorRecExclCheckOrderAndBlocking(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true,
[25685]283 cMillies, RTTHREADSTATE_MUTEX, true);
[25467]284 if (RT_FAILURE(rc9))
285 return rc9;
[25614]286#else
287 hThreadSelf = RTThreadSelf();
[25638]288 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_MUTEX, true);
[62564]289 RT_NOREF_PV(pSrcPos);
[25478]290#endif
[25467]291 }
292
[1]293 if (cMillies == RT_INDEFINITE_WAIT)
294 {
295 /* take mutex */
[25373]296 int rc = pthread_mutex_lock(&pThis->Mutex);
[25467]297 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
[1]298 if (rc)
299 {
[25721]300 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", hMutexSem, rc)); NOREF(rc);
[1]301 return RTErrConvertFromErrno(rc);
302 }
303 }
304 else
305 {
[63052]306 int rc;
307#if !defined(RT_OS_DARWIN) && !defined(RT_OS_NETBSD)
[43559]308 struct timespec ts = {0,0};
[63052]309# if defined(RT_OS_HAIKU)
[43363]310 struct timeval tv = {0,0};
311 gettimeofday(&tv, NULL);
312 ts.tv_sec = tv.tv_sec;
[63029]313 ts.tv_nsec = tv.tv_usec * 1000;
[63052]314# else
[1]315 clock_gettime(CLOCK_REALTIME, &ts);
[63052]316# endif
[1]317 if (cMillies != 0)
318 {
[63029]319 ts.tv_nsec += (cMillies % 1000) * 1000000;
320 ts.tv_sec += cMillies / 1000;
321 if (ts.tv_nsec >= 1000000000)
[1]322 {
[63029]323 ts.tv_nsec -= 1000000000;
[1]324 ts.tv_sec++;
325 }
326 }
327
328 /* take mutex */
[63052]329 rc = pthread_mutex_timedlock(&pThis->Mutex, &ts);
[43558]330#else
[63052]331 /*
332 * When there's no pthread_mutex_timedlock() use a crude sleep
333 * and retry approximation. Since the sleep interval is
334 * relative, we don't need to convert to the absolute time
335 * here only to convert back to relative in the fallback
336 * function.
337 */
338 rc = rtSemFallbackPthreadMutexTimedlock(&pThis->Mutex, cMillies);
[43558]339#endif
[25467]340 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
[1]341 if (rc)
342 {
[25721]343 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", hMutexSem, rc)); NOREF(rc);
[1]344 return RTErrConvertFromErrno(rc);
345 }
346 }
347
348 /*
349 * Set the owner and nesting.
350 */
[25373]351 pThis->Owner = Self;
352 ASMAtomicWriteU32(&pThis->cNesting, 1);
[8649]353#ifdef RTSEMMUTEX_STRICT
[25614]354 RTLockValidatorRecExclSetOwner(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true);
[8649]355#endif
[1]356
357 return VINF_SUCCESS;
358}
359
360
[25711]361#undef RTSemMutexRequest
[25724]362RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
[1]363{
[25373]364#ifndef RTSEMMUTEX_STRICT
[25721]365 return rtSemMutexRequest(hMutexSem, cMillies, NULL);
[25373]366#else
[25607]367 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
[25721]368 return rtSemMutexRequest(hMutexSem, cMillies, &SrcPos);
[25373]369#endif
370}
371
372
[25724]373RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
[25373]374{
[25607]375 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
[25721]376 return rtSemMutexRequest(hMutexSem, cMillies, &SrcPos);
[25373]377}
378
379
[25711]380#undef RTSemMutexRequestNoResume
[25724]381RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
[25373]382{
[25478]383 /* (EINTR isn't returned by the wait functions we're using.) */
[25373]384#ifndef RTSEMMUTEX_STRICT
[25721]385 return rtSemMutexRequest(hMutexSem, cMillies, NULL);
[25373]386#else
[25607]387 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
[25721]388 return rtSemMutexRequest(hMutexSem, cMillies, &SrcPos);
[25373]389#endif
[1]390}
391
392
[25724]393RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
[25373]394{
[25607]395 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
[25721]396 return rtSemMutexRequest(hMutexSem, cMillies, &SrcPos);
[25373]397}
398
399
[25721]400RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
[1]401{
402 /*
403 * Validate input.
404 */
[25721]405 struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25373]406 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
407 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
[1]408
[25614]409#ifdef RTSEMMUTEX_STRICT
410 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorRec, pThis->cNesting == 1);
411 if (RT_FAILURE(rc9))
412 return rc9;
413#endif
414
[1]415 /*
416 * Check if nested.
417 */
[25373]418 pthread_t Self = pthread_self();
419 if (RT_UNLIKELY( pThis->Owner != Self
420 || pThis->cNesting == 0))
[1]421 {
422 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
[25373]423 pThis, Self, pThis->Owner, pThis->cNesting));
[1]424 return VERR_NOT_OWNER;
425 }
426
427 /*
428 * If nested we'll just pop a nesting.
429 */
[25373]430 if (pThis->cNesting > 1)
[1]431 {
[25373]432 ASMAtomicDecU32(&pThis->cNesting);
[1]433 return VINF_SUCCESS;
434 }
435
436 /*
437 * Clear the state. (cNesting == 1)
438 */
[25373]439 pThis->Owner = (pthread_t)-1;
[25624]440 ASMAtomicWriteU32(&pThis->cNesting, 0);
[1]441
442 /*
443 * Unlock mutex semaphore.
444 */
[25373]445 int rc = pthread_mutex_unlock(&pThis->Mutex);
446 if (RT_UNLIKELY(rc))
[1]447 {
[25721]448 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", hMutexSem, rc)); NOREF(rc);
[1]449 return RTErrConvertFromErrno(rc);
450 }
451
452 return VINF_SUCCESS;
453}
454
[25624]455
[25721]456RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
[25624]457{
458 /*
459 * Validate.
460 */
[25721]461 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25628]462 AssertPtrReturn(pThis, false);
463 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
[25624]464
465 return pThis->Owner != (pthread_t)-1;
466}
467
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use