VirtualBox

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

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.6 KB
RevLine 
[1]1/* $Id: semmutex-win.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[25381]3 * IPRT - Mutex Semaphores, Windows.
[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
37
[57358]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[1]41#define LOG_GROUP RTLOGGROUP_SEMAPHORE
[62592]42#include <iprt/win/windows.h>
[1]43
44#include <iprt/semaphore.h>
[25382]45#include "internal/iprt.h"
46
[25627]47#include <iprt/asm.h>
[1]48#include <iprt/assert.h>
49#include <iprt/err.h>
[25382]50#include <iprt/lockvalidator.h>
51#include <iprt/mem.h>
52#include <iprt/thread.h>
53#include "internal/magics.h"
[8651]54#include "internal/strict.h"
[1]55
56
[57358]57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
[25382]60/** Posix internal representation of a Mutex semaphore. */
61struct RTSEMMUTEXINTERNAL
62{
63 /** Magic value (RTSEMMUTEX_MAGIC). */
[25624]64 uint32_t u32Magic;
65 /** Recursion count. */
66 uint32_t volatile cRecursions;
67 /** The owner thread. */
68 RTNATIVETHREAD volatile hNativeOwner;
[25382]69 /** The mutex handle. */
[25624]70 HANDLE hMtx;
[25382]71#ifdef RTSEMMUTEX_STRICT
72 /** Lock validator record associated with this mutex. */
[25624]73 RTLOCKVALRECEXCL ValidatorRec;
[25382]74#endif
75};
[1]76
77
78
[25711]79#undef RTSemMutexCreate
80RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
81{
82 return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
83}
[25378]84
[25711]85
86RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
87 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
[1]88{
[25711]89 AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
[25382]90
[1]91 /*
92 * Create the semaphore.
93 */
[25711]94 int rc;
[25382]95 HANDLE hMtx = CreateMutex(NULL, FALSE, NULL);
96 if (hMtx)
[1]97 {
[25382]98 RTSEMMUTEXINTERNAL *pThis = (RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(*pThis));
99 if (pThis)
100 {
[25624]101 pThis->u32Magic = RTSEMMUTEX_MAGIC;
102 pThis->hMtx = hMtx;
103 pThis->hNativeOwner = NIL_RTNATIVETHREAD;
104 pThis->cRecursions = 0;
[25382]105#ifdef RTSEMMUTEX_STRICT
[25831]106 if (!pszNameFmt)
107 {
108 static uint32_t volatile s_iMutexAnon = 0;
109 RTLockValidatorRecExclInit(&pThis->ValidatorRec, hClass, uSubClass, pThis,
110 !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL),
111 "RTSemMutex-%u", ASMAtomicIncU32(&s_iMutexAnon) - 1);
112 }
113 else
114 {
115 va_list va;
116 va_start(va, pszNameFmt);
117 RTLockValidatorRecExclInitV(&pThis->ValidatorRec, hClass, uSubClass, pThis,
118 !(fFlags & RTSEMMUTEX_FLAGS_NO_LOCK_VAL), pszNameFmt, va);
119 va_end(va);
120 }
[62592]121#else
122 RT_NOREF_PV(hClass); RT_NOREF_PV(uSubClass); RT_NOREF_PV(pszNameFmt);
[25382]123#endif
[25711]124 *phMutexSem = pThis;
[25382]125 return VINF_SUCCESS;
126 }
127
128 rc = VERR_NO_MEMORY;
[1]129 }
[25382]130 else
131 rc = RTErrConvertFromWin32(GetLastError());
132 return rc;
[1]133}
134
135
[25721]136RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
[1]137{
138 /*
[25382]139 * Validate.
140 */
[25721]141 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25382]142 if (pThis == NIL_RTSEMMUTEX)
143 return VINF_SUCCESS;
144 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
145 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
146
147 /*
[1]148 * Close semaphore handle.
149 */
[25382]150 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
151 HANDLE hMtx = pThis->hMtx;
[30111]152 ASMAtomicWritePtr(&pThis->hMtx, INVALID_HANDLE_VALUE);
[25382]153
154 int rc = VINF_SUCCESS;
155 if (!CloseHandle(hMtx))
156 {
157 rc = RTErrConvertFromWin32(GetLastError());
158 AssertMsgFailed(("%p rc=%d lasterr=%d\n", pThis->hMtx, rc, GetLastError()));
159 }
160
161#ifdef RTSEMMUTEX_STRICT
[25607]162 RTLockValidatorRecExclDelete(&pThis->ValidatorRec);
[25382]163#endif
164 RTMemFree(pThis);
165 return rc;
[1]166}
167
168
[25711]169RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass)
170{
171#ifdef RTSEMMUTEX_STRICT
172 /*
173 * Validate.
174 */
175 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
176 AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
177 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
178
179 return RTLockValidatorRecExclSetSubClass(&pThis->ValidatorRec, uSubClass);
180#else
[62592]181 RT_NOREF_PV(hMutexSem); RT_NOREF_PV(uSubClass);
[25711]182 return RTLOCKVAL_SUB_CLASS_INVALID;
183#endif
184}
185
186
[25382]187/**
188 * Internal worker for RTSemMutexRequestNoResume and it's debug companion.
189 *
190 * @returns Same as RTSEmMutexRequestNoResume
[25721]191 * @param hMutexSem The mutex handle.
[25478]192 * @param cMillies The number of milliseconds to wait.
193 * @param pSrcPos The source position of the caller.
[25382]194 */
[25724]195DECL_FORCE_INLINE(int) rtSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, PCRTLOCKVALSRCPOS pSrcPos)
[1]196{
197 /*
[25382]198 * Validate.
199 */
[25721]200 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25382]201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
202 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
203
204 /*
[25624]205 * Check for recursive entry.
206 */
207 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
208 RTNATIVETHREAD hNativeOwner;
[25627]209 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
[25624]210 if (hNativeOwner == hNativeSelf)
211 {
212#ifdef RTSEMMUTEX_STRICT
213 int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorRec, pSrcPos);
214 if (RT_FAILURE(rc9))
215 return rc9;
216#endif
217 ASMAtomicIncU32(&pThis->cRecursions);
218 return VINF_SUCCESS;
219 }
220
221 /*
[1]222 * Lock mutex semaphore.
223 */
[25624]224 RTTHREAD hThreadSelf = NIL_RTTHREAD;
[25382]225 if (cMillies > 0)
[25467]226 {
227#ifdef RTSEMMUTEX_STRICT
[25614]228 hThreadSelf = RTThreadSelfAutoAdopt();
[25638]229 int rc9 = RTLockValidatorRecExclCheckOrderAndBlocking(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true,
[25685]230 cMillies, RTTHREADSTATE_MUTEX, true);
[25467]231 if (RT_FAILURE(rc9))
232 return rc9;
[25614]233#else
234 hThreadSelf = RTThreadSelf();
[25638]235 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_MUTEX, true);
[62592]236 RT_NOREF_PV(pSrcPos);
[25478]237#endif
[25467]238 }
[25656]239 DWORD rc = WaitForSingleObjectEx(pThis->hMtx,
240 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
241 TRUE /*fAlertable*/);
[25467]242 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
[1]243 switch (rc)
244 {
[8649]245 case WAIT_OBJECT_0:
246#ifdef RTSEMMUTEX_STRICT
[25624]247 RTLockValidatorRecExclSetOwner(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true);
[8649]248#endif
[25624]249 ASMAtomicWriteHandle(&pThis->hNativeOwner, hNativeSelf);
250 ASMAtomicWriteU32(&pThis->cRecursions, 1);
[8649]251 return VINF_SUCCESS;
252
[1]253 case WAIT_TIMEOUT: return VERR_TIMEOUT;
254 case WAIT_IO_COMPLETION: return VERR_INTERRUPTED;
255 case WAIT_ABANDONED: return VERR_SEM_OWNER_DIED;
256 default:
[25656]257 AssertMsgFailed(("%u\n", rc));
258 case WAIT_FAILED:
[1]259 {
[25656]260 int rc2 = RTErrConvertFromWin32(GetLastError());
[25721]261 AssertMsgFailed(("Wait on hMutexSem %p failed, rc=%d lasterr=%d\n", hMutexSem, rc, GetLastError()));
[25656]262 if (rc2 != VINF_SUCCESS)
[1]263 return rc2;
264
265 AssertMsgFailed(("WaitForSingleObject(event) -> rc=%d while converted lasterr=%d\n", rc, rc2));
266 return VERR_INTERNAL_ERROR;
267 }
268 }
269}
270
[25373]271
[25711]272#undef RTSemMutexRequestNoResume
[25724]273RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
[25373]274{
[25382]275#ifndef RTSEMMUTEX_STRICT
[25721]276 return rtSemMutexRequestNoResume(hMutexSem, cMillies, NULL);
[25382]277#else
[25607]278 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
[25721]279 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
[25382]280#endif
281}
282
283
[25724]284RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
[25382]285{
[25607]286 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
[25721]287 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
[25373]288}
289
290
[25721]291RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
[1]292{
293 /*
[25382]294 * Validate.
295 */
[25721]296 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25382]297 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
298 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
299
[25624]300 /*
301 * Check ownership and recursions.
302 */
303 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
304 RTNATIVETHREAD hNativeOwner;
[25627]305 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
[25624]306 if (RT_UNLIKELY(hNativeOwner != hNativeSelf))
307 {
308 AssertMsgFailed(("Not owner of mutex %p!! hNativeSelf=%RTntrd Owner=%RTntrd cRecursions=%d\n",
309 pThis, hNativeSelf, hNativeOwner, pThis->cRecursions));
310 return VERR_NOT_OWNER;
311 }
312 if (pThis->cRecursions > 1)
313 {
[25614]314#ifdef RTSEMMUTEX_STRICT
[25624]315 int rc9 = RTLockValidatorRecExclUnwind(&pThis->ValidatorRec);
316 if (RT_FAILURE(rc9))
317 return rc9;
318#endif
319 ASMAtomicDecU32(&pThis->cRecursions);
320 return VINF_SUCCESS;
321 }
322
323 /*
324 * Unlock mutex semaphore.
325 */
326#ifdef RTSEMMUTEX_STRICT
[25614]327 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorRec, false);
328 if (RT_FAILURE(rc9))
329 return rc9;
330#endif
[25624]331 ASMAtomicWriteU32(&pThis->cRecursions, 0);
332 ASMAtomicWriteHandle(&pThis->hNativeOwner, NIL_RTNATIVETHREAD);
[25614]333
[25382]334 if (ReleaseMutex(pThis->hMtx))
[1]335 return VINF_SUCCESS;
[25624]336
[25382]337 int rc = RTErrConvertFromWin32(GetLastError());
338 AssertMsgFailed(("%p/%p, rc=%Rrc lasterr=%d\n", pThis, pThis->hMtx, rc, GetLastError()));
339 return rc;
[1]340}
341
[25624]342
[25721]343RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
[25624]344{
345 /*
346 * Validate.
347 */
[25721]348 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
[25628]349 AssertPtrReturn(pThis, false);
350 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
[25624]351
352 RTNATIVETHREAD hNativeOwner;
[25627]353 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
[25658]354 return hNativeOwner != NIL_RTNATIVETHREAD;
[25624]355}
356
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use