VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/semmutex-win.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: 11.6 KB
Line 
1/* $Id: semmutex-win.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Mutex Semaphores, Windows.
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#define LOG_GROUP RTLOGGROUP_SEMAPHORE
42#include <iprt/win/windows.h>
43
44#include <iprt/semaphore.h>
45#include "internal/iprt.h"
46
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include <iprt/err.h>
50#include <iprt/lockvalidator.h>
51#include <iprt/mem.h>
52#include <iprt/thread.h>
53#include "internal/magics.h"
54#include "internal/strict.h"
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60/** Posix internal representation of a Mutex semaphore. */
61struct RTSEMMUTEXINTERNAL
62{
63 /** Magic value (RTSEMMUTEX_MAGIC). */
64 uint32_t u32Magic;
65 /** Recursion count. */
66 uint32_t volatile cRecursions;
67 /** The owner thread. */
68 RTNATIVETHREAD volatile hNativeOwner;
69 /** The mutex handle. */
70 HANDLE hMtx;
71#ifdef RTSEMMUTEX_STRICT
72 /** Lock validator record associated with this mutex. */
73 RTLOCKVALRECEXCL ValidatorRec;
74#endif
75};
76
77
78
79#undef RTSemMutexCreate
80RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
81{
82 return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
83}
84
85
86RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
87 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
88{
89 AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
90
91 /*
92 * Create the semaphore.
93 */
94 int rc;
95 HANDLE hMtx = CreateMutex(NULL, FALSE, NULL);
96 if (hMtx)
97 {
98 RTSEMMUTEXINTERNAL *pThis = (RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(*pThis));
99 if (pThis)
100 {
101 pThis->u32Magic = RTSEMMUTEX_MAGIC;
102 pThis->hMtx = hMtx;
103 pThis->hNativeOwner = NIL_RTNATIVETHREAD;
104 pThis->cRecursions = 0;
105#ifdef RTSEMMUTEX_STRICT
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 }
121#else
122 RT_NOREF_PV(hClass); RT_NOREF_PV(uSubClass); RT_NOREF_PV(pszNameFmt);
123#endif
124 *phMutexSem = pThis;
125 return VINF_SUCCESS;
126 }
127
128 rc = VERR_NO_MEMORY;
129 }
130 else
131 rc = RTErrConvertFromWin32(GetLastError());
132 return rc;
133}
134
135
136RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
137{
138 /*
139 * Validate.
140 */
141 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
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 /*
148 * Close semaphore handle.
149 */
150 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
151 HANDLE hMtx = pThis->hMtx;
152 ASMAtomicWritePtr(&pThis->hMtx, INVALID_HANDLE_VALUE);
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
162 RTLockValidatorRecExclDelete(&pThis->ValidatorRec);
163#endif
164 RTMemFree(pThis);
165 return rc;
166}
167
168
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
181 RT_NOREF_PV(hMutexSem); RT_NOREF_PV(uSubClass);
182 return RTLOCKVAL_SUB_CLASS_INVALID;
183#endif
184}
185
186
187/**
188 * Internal worker for RTSemMutexRequestNoResume and it's debug companion.
189 *
190 * @returns Same as RTSEmMutexRequestNoResume
191 * @param hMutexSem The mutex handle.
192 * @param cMillies The number of milliseconds to wait.
193 * @param pSrcPos The source position of the caller.
194 */
195DECL_FORCE_INLINE(int) rtSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, PCRTLOCKVALSRCPOS pSrcPos)
196{
197 /*
198 * Validate.
199 */
200 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
202 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
203
204 /*
205 * Check for recursive entry.
206 */
207 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
208 RTNATIVETHREAD hNativeOwner;
209 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
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 /*
222 * Lock mutex semaphore.
223 */
224 RTTHREAD hThreadSelf = NIL_RTTHREAD;
225 if (cMillies > 0)
226 {
227#ifdef RTSEMMUTEX_STRICT
228 hThreadSelf = RTThreadSelfAutoAdopt();
229 int rc9 = RTLockValidatorRecExclCheckOrderAndBlocking(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true,
230 cMillies, RTTHREADSTATE_MUTEX, true);
231 if (RT_FAILURE(rc9))
232 return rc9;
233#else
234 hThreadSelf = RTThreadSelf();
235 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_MUTEX, true);
236 RT_NOREF_PV(pSrcPos);
237#endif
238 }
239 DWORD rc = WaitForSingleObjectEx(pThis->hMtx,
240 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
241 TRUE /*fAlertable*/);
242 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_MUTEX);
243 switch (rc)
244 {
245 case WAIT_OBJECT_0:
246#ifdef RTSEMMUTEX_STRICT
247 RTLockValidatorRecExclSetOwner(&pThis->ValidatorRec, hThreadSelf, pSrcPos, true);
248#endif
249 ASMAtomicWriteHandle(&pThis->hNativeOwner, hNativeSelf);
250 ASMAtomicWriteU32(&pThis->cRecursions, 1);
251 return VINF_SUCCESS;
252
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:
257 AssertMsgFailed(("%u\n", rc));
258 case WAIT_FAILED:
259 {
260 int rc2 = RTErrConvertFromWin32(GetLastError());
261 AssertMsgFailed(("Wait on hMutexSem %p failed, rc=%d lasterr=%d\n", hMutexSem, rc, GetLastError()));
262 if (rc2 != VINF_SUCCESS)
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
271
272#undef RTSemMutexRequestNoResume
273RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
274{
275#ifndef RTSEMMUTEX_STRICT
276 return rtSemMutexRequestNoResume(hMutexSem, cMillies, NULL);
277#else
278 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
279 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
280#endif
281}
282
283
284RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
285{
286 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
287 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
288}
289
290
291RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
292{
293 /*
294 * Validate.
295 */
296 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
297 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
298 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
299
300 /*
301 * Check ownership and recursions.
302 */
303 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
304 RTNATIVETHREAD hNativeOwner;
305 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
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 {
314#ifdef RTSEMMUTEX_STRICT
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
327 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorRec, false);
328 if (RT_FAILURE(rc9))
329 return rc9;
330#endif
331 ASMAtomicWriteU32(&pThis->cRecursions, 0);
332 ASMAtomicWriteHandle(&pThis->hNativeOwner, NIL_RTNATIVETHREAD);
333
334 if (ReleaseMutex(pThis->hMtx))
335 return VINF_SUCCESS;
336
337 int rc = RTErrConvertFromWin32(GetLastError());
338 AssertMsgFailed(("%p/%p, rc=%Rrc lasterr=%d\n", pThis, pThis->hMtx, rc, GetLastError()));
339 return rc;
340}
341
342
343RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
344{
345 /*
346 * Validate.
347 */
348 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
349 AssertPtrReturn(pThis, false);
350 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
351
352 RTNATIVETHREAD hNativeOwner;
353 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
354 return hNativeOwner != NIL_RTNATIVETHREAD;
355}
356
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use