VirtualBox

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

Last change on this file since 106518 was 106497, checked in by vboxsync, 4 months ago

iprt/r3: switch fall thru and LARGE_INTEGER init. jiraref:VBP-1171

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.7 KB
Line 
1/* $Id: semmutex-win.cpp 106497 2024-10-19 03:11:08Z vboxsync $ */
2/** @file
3 * IPRT - Mutex Semaphores, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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 RT_FALL_THRU();
259 case WAIT_FAILED:
260 {
261 int rc2 = RTErrConvertFromWin32(GetLastError());
262 AssertMsgFailed(("Wait on hMutexSem %p failed, rc=%d lasterr=%d\n", hMutexSem, rc, GetLastError()));
263 if (rc2 != VINF_SUCCESS)
264 return rc2;
265
266 AssertMsgFailed(("WaitForSingleObject(event) -> rc=%d while converted lasterr=%d\n", rc, rc2));
267 return VERR_INTERNAL_ERROR;
268 }
269 }
270}
271
272
273#undef RTSemMutexRequestNoResume
274RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
275{
276#ifndef RTSEMMUTEX_STRICT
277 return rtSemMutexRequestNoResume(hMutexSem, cMillies, NULL);
278#else
279 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
280 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
281#endif
282}
283
284
285RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
286{
287 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
288 return rtSemMutexRequestNoResume(hMutexSem, cMillies, &SrcPos);
289}
290
291
292RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
293{
294 /*
295 * Validate.
296 */
297 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
298 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
299 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
300
301 /*
302 * Check ownership and recursions.
303 */
304 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
305 RTNATIVETHREAD hNativeOwner;
306 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
307 if (RT_UNLIKELY(hNativeOwner != hNativeSelf))
308 {
309 AssertMsgFailed(("Not owner of mutex %p!! hNativeSelf=%RTntrd Owner=%RTntrd cRecursions=%d\n",
310 pThis, hNativeSelf, hNativeOwner, pThis->cRecursions));
311 return VERR_NOT_OWNER;
312 }
313 if (pThis->cRecursions > 1)
314 {
315#ifdef RTSEMMUTEX_STRICT
316 int rc9 = RTLockValidatorRecExclUnwind(&pThis->ValidatorRec);
317 if (RT_FAILURE(rc9))
318 return rc9;
319#endif
320 ASMAtomicDecU32(&pThis->cRecursions);
321 return VINF_SUCCESS;
322 }
323
324 /*
325 * Unlock mutex semaphore.
326 */
327#ifdef RTSEMMUTEX_STRICT
328 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorRec, false);
329 if (RT_FAILURE(rc9))
330 return rc9;
331#endif
332 ASMAtomicWriteU32(&pThis->cRecursions, 0);
333 ASMAtomicWriteHandle(&pThis->hNativeOwner, NIL_RTNATIVETHREAD);
334
335 if (ReleaseMutex(pThis->hMtx))
336 return VINF_SUCCESS;
337
338 int rc = RTErrConvertFromWin32(GetLastError());
339 AssertMsgFailed(("%p/%p, rc=%Rrc lasterr=%d\n", pThis, pThis->hMtx, rc, GetLastError()));
340 return rc;
341}
342
343
344RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
345{
346 /*
347 * Validate.
348 */
349 RTSEMMUTEXINTERNAL *pThis = hMutexSem;
350 AssertPtrReturn(pThis, false);
351 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
352
353 RTNATIVETHREAD hNativeOwner;
354 ASMAtomicReadHandle(&pThis->hNativeOwner, &hNativeOwner);
355 return hNativeOwner != NIL_RTNATIVETHREAD;
356}
357
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