VirtualBox

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

Last change on this file since 96124 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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