VirtualBox

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

Last change on this file since 86186 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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