[1] | 1 | /* $Id: semmutex-linux.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[8245] | 3 | * IPRT - Mutex Semaphore, Linux (2.6.x+).
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[76553] | 7 | * Copyright (C) 2006-2019 Oracle Corporation
|
---|
[1] | 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
|
---|
[5999] | 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.
|
---|
[1] | 25 | */
|
---|
| 26 |
|
---|
[57358] | 27 |
|
---|
| 28 | /*********************************************************************************************************************************
|
---|
| 29 | * Header Files *
|
---|
| 30 | *********************************************************************************************************************************/
|
---|
[1] | 31 | #include <iprt/semaphore.h>
|
---|
[25373] | 32 | #include "internal/iprt.h"
|
---|
| 33 |
|
---|
[1] | 34 | #include <iprt/alloc.h>
|
---|
| 35 | #include <iprt/asm.h>
|
---|
[25373] | 36 | #include <iprt/assert.h>
|
---|
[1] | 37 | #include <iprt/err.h>
|
---|
[25373] | 38 | #include <iprt/lockvalidator.h>
|
---|
| 39 | #include <iprt/thread.h>
|
---|
[22959] | 40 | #include <iprt/time.h>
|
---|
[1816] | 41 | #include "internal/magics.h"
|
---|
[8651] | 42 | #include "internal/strict.h"
|
---|
[1] | 43 |
|
---|
| 44 | #include <errno.h>
|
---|
[822] | 45 | #include <limits.h>
|
---|
[1] | 46 | #include <pthread.h>
|
---|
| 47 | #include <unistd.h>
|
---|
| 48 | #include <sys/time.h>
|
---|
[822] | 49 | #include <sys/syscall.h>
|
---|
[849] | 50 | #if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
|
---|
| 51 | # include <linux/futex.h>
|
---|
| 52 | #else
|
---|
| 53 | # define FUTEX_WAIT 0
|
---|
| 54 | # define FUTEX_WAKE 1
|
---|
[6738] | 55 | #endif
|
---|
[1] | 56 |
|
---|
| 57 |
|
---|
[57358] | 58 | /*********************************************************************************************************************************
|
---|
| 59 | * Structures and Typedefs *
|
---|
| 60 | *********************************************************************************************************************************/
|
---|
[822] | 61 | /**
|
---|
[6727] | 62 | * Linux internal representation of a Mutex semaphore.
|
---|
| 63 | */
|
---|
| 64 | struct RTSEMMUTEXINTERNAL
|
---|
| 65 | {
|
---|
| 66 | /** The futex state variable.
|
---|
| 67 | * 0 means unlocked.
|
---|
| 68 | * 1 means locked, no waiters.
|
---|
| 69 | * 2 means locked, one or more waiters.
|
---|
| 70 | */
|
---|
| 71 | int32_t volatile iState;
|
---|
[6745] | 72 | /** Nesting count. */
|
---|
[25715] | 73 | uint32_t volatile cNestings;
|
---|
[6727] | 74 | /** The owner of the mutex. */
|
---|
[6745] | 75 | pthread_t volatile Owner;
|
---|
[25373] | 76 | /** Magic value (RTSEMMUTEX_MAGIC). */
|
---|
| 77 | uint32_t volatile u32Magic;
|
---|
| 78 | #ifdef RTSEMMUTEX_STRICT
|
---|
| 79 | /** Lock validator record associated with this mutex. */
|
---|
[25607] | 80 | RTLOCKVALRECEXCL ValidatorRec;
|
---|
[25373] | 81 | #endif
|
---|
[6727] | 82 | };
|
---|
[1] | 83 |
|
---|
[822] | 84 |
|
---|
[25378] | 85 |
|
---|
[1] | 86 | /**
|
---|
[822] | 87 | * Wrapper for the futex syscall.
|
---|
[1] | 88 | */
|
---|
[822] | 89 | static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
|
---|
[1] | 90 | {
|
---|
[822] | 91 | errno = 0;
|
---|
| 92 | long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
|
---|
| 93 | if (rc < 0)
|
---|
| 94 | {
|
---|
| 95 | Assert(rc == -1);
|
---|
| 96 | rc = -errno;
|
---|
| 97 | }
|
---|
| 98 | return rc;
|
---|
| 99 | }
|
---|
[1] | 100 |
|
---|
| 101 |
|
---|
[25711] | 102 | #undef RTSemMutexCreate
|
---|
| 103 | RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
|
---|
[1] | 104 | {
|
---|
[25711] | 105 | return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 |
|
---|
| 109 | RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
|
---|
| 110 | RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
|
---|
| 111 | {
|
---|
| 112 | AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
|
---|
| 113 |
|
---|
[1] | 114 | /*
|
---|
| 115 | * Allocate semaphore handle.
|
---|
| 116 | */
|
---|
[6747] | 117 | struct RTSEMMUTEXINTERNAL *pThis = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
|
---|
| 118 | if (pThis)
|
---|
[1] | 119 | {
|
---|
[25715] | 120 | pThis->u32Magic = RTSEMMUTEX_MAGIC;
|
---|
| 121 | pThis->iState = 0;
|
---|
| 122 | pThis->Owner = (pthread_t)~0;
|
---|
| 123 | pThis->cNestings = 0;
|
---|
[25373] | 124 | #ifdef RTSEMMUTEX_STRICT
|
---|
[25831] | 125 | if (!pszNameFmt)
|
---|
| 126 | {
|
---|
| 127 | static uint32_t volatile s_iMutexAnon = 0;
|
---|
| 128 | RTLockValidatorRecExclInit(&pThis->ValidatorRec, hClass, uSubClass, pThis,
|
---|
| 129 | !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL),
|
---|
| 130 | "RTSemMutex-%u", ASMAtomicIncU32(&s_iMutexAnon) - 1);
|
---|
| 131 | }
|
---|
| 132 | else
|
---|
| 133 | {
|
---|
| 134 | va_list va;
|
---|
| 135 | va_start(va, pszNameFmt);
|
---|
| 136 | RTLockValidatorRecExclInitV(&pThis->ValidatorRec, hClass, uSubClass, pThis,
|
---|
| 137 | !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL), pszNameFmt, va);
|
---|
| 138 | va_end(va);
|
---|
| 139 | }
|
---|
[63417] | 140 | #else
|
---|
| 141 | RT_NOREF(hClass, uSubClass, pszNameFmt);
|
---|
[25373] | 142 | #endif
|
---|
[1] | 143 |
|
---|
[25711] | 144 | *phMutexSem = pThis;
|
---|
[6727] | 145 | return VINF_SUCCESS;
|
---|
| 146 | }
|
---|
[1] | 147 |
|
---|
[6727] | 148 | return VERR_NO_MEMORY;
|
---|
| 149 | }
|
---|
[1] | 150 |
|
---|
| 151 |
|
---|
[25721] | 152 | RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
|
---|
[6727] | 153 | {
|
---|
| 154 | /*
|
---|
| 155 | * Validate input.
|
---|
| 156 | */
|
---|
[25721] | 157 | if (hMutexSem == NIL_RTSEMMUTEX)
|
---|
[25373] | 158 | return VINF_SUCCESS;
|
---|
[25721] | 159 | struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
|
---|
[6747] | 160 | AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
|
---|
[25373] | 161 | AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC,
|
---|
[25721] | 162 | ("hMutexSem=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
|
---|
[6746] | 163 | VERR_INVALID_HANDLE);
|
---|
[1] | 164 |
|
---|
[6727] | 165 | /*
|
---|
| 166 | * Invalidate the semaphore and wake up anyone waiting on it.
|
---|
| 167 | */
|
---|
[25373] | 168 | ASMAtomicWriteU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD);
|
---|
[6747] | 169 | if (ASMAtomicXchgS32(&pThis->iState, 0) > 0)
|
---|
[6727] | 170 | {
|
---|
[6747] | 171 | sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
|
---|
[6727] | 172 | usleep(1000);
|
---|
| 173 | }
|
---|
[25715] | 174 | pThis->Owner = (pthread_t)~0;
|
---|
| 175 | pThis->cNestings = 0;
|
---|
[25373] | 176 | #ifdef RTSEMMUTEX_STRICT
|
---|
[25607] | 177 | RTLockValidatorRecExclDelete(&pThis->ValidatorRec);
|
---|
[25373] | 178 | #endif
|
---|
[6727] | 179 |
|
---|
| 180 | /*
|
---|
| 181 | * Free the semaphore memory and be gone.
|
---|
| 182 | */
|
---|
[6747] | 183 | RTMemFree(pThis);
|
---|
[6727] | 184 | return VINF_SUCCESS;
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 |
|
---|
[25711] | 188 | RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass)
|
---|
| 189 | {
|
---|
| 190 | #ifdef RTSEMMUTEX_STRICT
|
---|
| 191 | /*
|
---|
| 192 | * Validate.
|
---|
| 193 | */
|
---|
| 194 | RTSEMMUTEXINTERNAL *pThis = hMutexSem;
|
---|
| 195 | AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
|
---|
| 196 | AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
|
---|
| 197 |
|
---|
| 198 | return RTLockValidatorRecExclSetSubClass(&pThis->ValidatorRec, uSubClass);
|
---|
| 199 | #else
|
---|
[63417] | 200 | RT_NOREF(hMutexSem, uSubClass);
|
---|
[25711] | 201 | return RTLOCKVAL_SUB_CLASS_INVALID;
|
---|
| 202 | #endif
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 |
|
---|
[25724] | 206 | DECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fAutoResume, PCRTLOCKVALSRCPOS pSrcPos)
|
---|
[6727] | 207 | {
|
---|
[63417] | 208 | RT_NOREF(pSrcPos);
|
---|
| 209 |
|
---|
[6727] | 210 | /*
|
---|
| 211 | * Validate input.
|
---|
| 212 | */
|
---|
[25721] | 213 | struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
|
---|
[25373] | 214 | AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
|
---|
| 215 | AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
|
---|
[6727] | 216 |
|
---|
| 217 | /*
|
---|
| 218 | * Check if nested request.
|
---|
| 219 | */
|
---|
| 220 | pthread_t Self = pthread_self();
|
---|
[6747] | 221 | if ( pThis->Owner == Self
|
---|
[25715] | 222 | && pThis->cNestings > 0)
|
---|
[6727] | 223 | {
|
---|
[25614] | 224 | #ifdef RTSEMMUTEX_STRICT
|
---|
| 225 | int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorRec, pSrcPos);
|
---|
| 226 | if (RT_FAILURE(rc9))
|
---|
| 227 | return rc9;
|
---|
| 228 | #endif
|
---|
[25715] | 229 | ASMAtomicIncU32(&pThis->cNestings);
|
---|
[6727] | 230 | return VINF_SUCCESS;
|
---|
| 231 | }
|
---|
[25614] | 232 |
|
---|
| 233 | #ifdef RTSEMMUTEX_STRICT
|
---|
| 234 | RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
|
---|
| 235 | if (cMillies)
|
---|
| 236 | {
|
---|
[25685] | 237 | int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorRec, hThreadSelf, pSrcPos, cMillies);
|
---|
[25614] | 238 | if (RT_FAILURE(rc9))
|
---|
| 239 | return rc9;
|
---|
| 240 | }
|
---|
| 241 | #else
|
---|
[25373] | 242 | RTTHREAD hThreadSelf = RTThreadSelf();
|
---|
| 243 | #endif
|
---|
[6727] | 244 |
|
---|
| 245 | /*
|
---|
| 246 | * Convert timeout value.
|
---|
| 247 | */
|
---|
| 248 | struct timespec ts;
|
---|
| 249 | struct timespec *pTimeout = NULL;
|
---|
[22957] | 250 | uint64_t u64End = 0; /* shut up gcc */
|
---|
[6727] | 251 | if (cMillies != RT_INDEFINITE_WAIT)
|
---|
| 252 | {
|
---|
| 253 | ts.tv_sec = cMillies / 1000;
|
---|
[25652] | 254 | ts.tv_nsec = (cMillies % 1000) * UINT32_C(1000000);
|
---|
| 255 | u64End = RTTimeSystemNanoTS() + cMillies * UINT64_C(1000000);
|
---|
[6727] | 256 | pTimeout = &ts;
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | /*
|
---|
| 260 | * Lock the mutex.
|
---|
[6748] | 261 | * Optimize for the uncontended case (makes 1-2 ns difference).
|
---|
[6727] | 262 | */
|
---|
[6747] | 263 | if (RT_UNLIKELY(!ASMAtomicCmpXchgS32(&pThis->iState, 1, 0)))
|
---|
[6727] | 264 | {
|
---|
[6737] | 265 | for (;;)
|
---|
[6731] | 266 | {
|
---|
[6747] | 267 | int32_t iOld = ASMAtomicXchgS32(&pThis->iState, 2);
|
---|
[6737] | 268 |
|
---|
[6727] | 269 | /*
|
---|
[6737] | 270 | * Was the lock released in the meantime? This is unlikely (but possible)
|
---|
| 271 | */
|
---|
| 272 | if (RT_UNLIKELY(iOld == 0))
|
---|
| 273 | break;
|
---|
| 274 |
|
---|
| 275 | /*
|
---|
[6727] | 276 | * Go to sleep.
|
---|
| 277 | */
|
---|
[25373] | 278 | if (pTimeout && ( pTimeout->tv_sec || pTimeout->tv_nsec ))
|
---|
[25467] | 279 | {
|
---|
| 280 | #ifdef RTSEMMUTEX_STRICT
|
---|
[25638] | 281 | int rc9 = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true,
|
---|
[25685] | 282 | cMillies, RTTHREADSTATE_MUTEX, true);
|
---|
[25467] | 283 | if (RT_FAILURE(rc9))
|
---|
| 284 | return rc9;
|
---|
[25618] | 285 | #else
|
---|
[25638] | 286 | RTThreadBlocking(hThreadSelf, RTTHREADSTATE_MUTEX, true);
|
---|
[25478] | 287 | #endif
|
---|
[25467] | 288 | }
|
---|
| 289 |
|
---|
[6747] | 290 | long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
|
---|
[25467] | 291 |
|
---|
| 292 | RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
|
---|
[25373] | 293 | if (RT_UNLIKELY(pThis->u32Magic != RTSEMMUTEX_MAGIC))
|
---|
[6727] | 294 | return VERR_SEM_DESTROYED;
|
---|
| 295 |
|
---|
| 296 | /*
|
---|
| 297 | * Act on the wakup code.
|
---|
| 298 | */
|
---|
| 299 | if (rc == -ETIMEDOUT)
|
---|
| 300 | {
|
---|
| 301 | Assert(pTimeout);
|
---|
| 302 | return VERR_TIMEOUT;
|
---|
| 303 | }
|
---|
[6731] | 304 | if (rc == 0)
|
---|
| 305 | /* we'll leave the loop now unless another thread is faster */;
|
---|
[6727] | 306 | else if (rc == -EWOULDBLOCK)
|
---|
| 307 | /* retry with new value. */;
|
---|
| 308 | else if (rc == -EINTR)
|
---|
| 309 | {
|
---|
| 310 | if (!fAutoResume)
|
---|
| 311 | return VERR_INTERRUPTED;
|
---|
| 312 | }
|
---|
| 313 | else
|
---|
| 314 | {
|
---|
| 315 | /* this shouldn't happen! */
|
---|
| 316 | AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
|
---|
| 317 | return RTErrConvertFromErrno(rc);
|
---|
| 318 | }
|
---|
[22957] | 319 |
|
---|
| 320 | /* adjust the relative timeout */
|
---|
| 321 | if (pTimeout)
|
---|
| 322 | {
|
---|
[22958] | 323 | int64_t i64Diff = u64End - RTTimeSystemNanoTS();
|
---|
| 324 | if (i64Diff < 1000)
|
---|
[22957] | 325 | {
|
---|
| 326 | rc = VERR_TIMEOUT;
|
---|
| 327 | break;
|
---|
| 328 | }
|
---|
[25652] | 329 | ts.tv_sec = (uint64_t)i64Diff / UINT32_C(1000000000);
|
---|
| 330 | ts.tv_nsec = (uint64_t)i64Diff % UINT32_C(1000000000);
|
---|
[22957] | 331 | }
|
---|
[6737] | 332 | }
|
---|
[6727] | 333 |
|
---|
[6737] | 334 | /*
|
---|
| 335 | * When leaving this loop, iState is set to 2. This means that we gained the
|
---|
[6748] | 336 | * lock and there are _possibly_ some waiters. We don't know exactly as another
|
---|
[6738] | 337 | * thread might entered this loop at nearly the same time. Therefore we will
|
---|
[6737] | 338 | * call futex_wakeup once too often (if _no_ other thread entered this loop).
|
---|
| 339 | * The key problem is the simple futex_wait test for x != y (iState != 2) in
|
---|
| 340 | * our case).
|
---|
| 341 | */
|
---|
[6727] | 342 | }
|
---|
| 343 |
|
---|
| 344 | /*
|
---|
| 345 | * Set the owner and nesting.
|
---|
| 346 | */
|
---|
[6747] | 347 | pThis->Owner = Self;
|
---|
[25715] | 348 | ASMAtomicWriteU32(&pThis->cNestings, 1);
|
---|
[8651] | 349 | #ifdef RTSEMMUTEX_STRICT
|
---|
[25614] | 350 | RTLockValidatorRecExclSetOwner(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true);
|
---|
[8651] | 351 | #endif
|
---|
[6727] | 352 | return VINF_SUCCESS;
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 |
|
---|
[25715] | 356 | #undef RTSemMutexRequest
|
---|
[25724] | 357 | RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
|
---|
[6727] | 358 | {
|
---|
[25373] | 359 | #ifndef RTSEMMUTEX_STRICT
|
---|
[25721] | 360 | int rc = rtSemMutexRequest(hMutexSem, cMillies, true, NULL);
|
---|
[25478] | 361 | #else
|
---|
[25607] | 362 | RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
|
---|
[25721] | 363 | int rc = rtSemMutexRequest(hMutexSem, cMillies, true, &SrcPos);
|
---|
[25478] | 364 | #endif
|
---|
[6727] | 365 | Assert(rc != VERR_INTERRUPTED);
|
---|
| 366 | return rc;
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 |
|
---|
[25724] | 370 | RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
|
---|
[6727] | 371 | {
|
---|
[25607] | 372 | RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
|
---|
[25721] | 373 | int rc = rtSemMutexRequest(hMutexSem, cMillies, true, &SrcPos);
|
---|
[25373] | 374 | Assert(rc != VERR_INTERRUPTED);
|
---|
| 375 | return rc;
|
---|
[6727] | 376 | }
|
---|
| 377 |
|
---|
| 378 |
|
---|
[25715] | 379 | #undef RTSemMutexRequestNoResume
|
---|
[25724] | 380 | RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
|
---|
[6727] | 381 | {
|
---|
[25373] | 382 | #ifndef RTSEMMUTEX_STRICT
|
---|
[25721] | 383 | return rtSemMutexRequest(hMutexSem, cMillies, false, NULL);
|
---|
[25373] | 384 | #else
|
---|
[25607] | 385 | RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
|
---|
[25721] | 386 | return rtSemMutexRequest(hMutexSem, cMillies, false, &SrcPos);
|
---|
[25373] | 387 | #endif
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 |
|
---|
[25724] | 391 | RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
|
---|
[25373] | 392 | {
|
---|
[25607] | 393 | RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
|
---|
[25721] | 394 | return rtSemMutexRequest(hMutexSem, cMillies, false, &SrcPos);
|
---|
[25373] | 395 | }
|
---|
| 396 |
|
---|
| 397 |
|
---|
[25721] | 398 | RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
|
---|
[25373] | 399 | {
|
---|
[6727] | 400 | /*
|
---|
| 401 | * Validate input.
|
---|
| 402 | */
|
---|
[25721] | 403 | struct RTSEMMUTEXINTERNAL *pThis = hMutexSem;
|
---|
[25373] | 404 | AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
|
---|
| 405 | AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
|
---|
[6727] | 406 |
|
---|
[25614] | 407 | #ifdef RTSEMMUTEX_STRICT
|
---|
[25715] | 408 | int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorRec, pThis->cNestings == 1);
|
---|
[25614] | 409 | if (RT_FAILURE(rc9))
|
---|
| 410 | return rc9;
|
---|
| 411 | #endif
|
---|
| 412 |
|
---|
[6727] | 413 | /*
|
---|
| 414 | * Check if nested.
|
---|
| 415 | */
|
---|
| 416 | pthread_t Self = pthread_self();
|
---|
[6747] | 417 | if (RT_UNLIKELY( pThis->Owner != Self
|
---|
[25715] | 418 | || pThis->cNestings == 0))
|
---|
[6727] | 419 | {
|
---|
[25715] | 420 | AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNestings=%d\n",
|
---|
| 421 | pThis, Self, pThis->Owner, pThis->cNestings));
|
---|
[6727] | 422 | return VERR_NOT_OWNER;
|
---|
| 423 | }
|
---|
| 424 |
|
---|
| 425 | /*
|
---|
| 426 | * If nested we'll just pop a nesting.
|
---|
| 427 | */
|
---|
[25715] | 428 | if (pThis->cNestings > 1)
|
---|
[6727] | 429 | {
|
---|
[25715] | 430 | ASMAtomicDecU32(&pThis->cNestings);
|
---|
[6727] | 431 | return VINF_SUCCESS;
|
---|
| 432 | }
|
---|
| 433 |
|
---|
| 434 | /*
|
---|
[25715] | 435 | * Clear the state. (cNestings == 1)
|
---|
[6727] | 436 | */
|
---|
[6747] | 437 | pThis->Owner = (pthread_t)~0;
|
---|
[25715] | 438 | ASMAtomicWriteU32(&pThis->cNestings, 0);
|
---|
[6727] | 439 |
|
---|
| 440 | /*
|
---|
| 441 | * Release the mutex.
|
---|
| 442 | */
|
---|
[6747] | 443 | int32_t iNew = ASMAtomicDecS32(&pThis->iState);
|
---|
[6748] | 444 | if (RT_UNLIKELY(iNew != 0))
|
---|
[6727] | 445 | {
|
---|
| 446 | /* somebody is waiting, try wake up one of them. */
|
---|
[6747] | 447 | ASMAtomicXchgS32(&pThis->iState, 0);
|
---|
| 448 | (void)sys_futex(&pThis->iState, FUTEX_WAKE, 1, NULL, NULL, 0);
|
---|
[6727] | 449 | }
|
---|
| 450 | return VINF_SUCCESS;
|
---|
| 451 | }
|
---|
| 452 |
|
---|
[25624] | 453 |
|
---|
[25721] | 454 | RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
|
---|
[25624] | 455 | {
|
---|
| 456 | /*
|
---|
| 457 | * Validate.
|
---|
| 458 | */
|
---|
[25721] | 459 | RTSEMMUTEXINTERNAL *pThis = hMutexSem;
|
---|
[25628] | 460 | AssertPtrReturn(pThis, false);
|
---|
| 461 | AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
|
---|
[25624] | 462 |
|
---|
| 463 | return pThis->Owner != (pthread_t)~0;
|
---|
| 464 | }
|
---|
| 465 |
|
---|