VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.5 KB
Line 
1/* $Id: semevent-win.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Event Semaphore, 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/mem.h"
55#include "internal/strict.h"
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61struct RTSEMEVENTINTERNAL
62{
63 /** Magic value (RTSEMEVENT_MAGIC). */
64 uint32_t u32Magic;
65 /** The event handle. */
66 HANDLE hev;
67#ifdef RTSEMEVENT_STRICT
68 /** Signallers. */
69 RTLOCKVALRECSHRD Signallers;
70 /** Indicates that lock validation should be performed. */
71 bool volatile fEverHadSignallers;
72#endif
73 /** The creation flags. */
74 uint32_t fFlags;
75};
76
77
78
79RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
80{
81 return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
82}
83
84
85RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
86{
87 AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
88 Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
89
90 struct RTSEMEVENTINTERNAL *pThis;
91 if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
92 pThis = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(*pThis));
93 else
94 pThis = (struct RTSEMEVENTINTERNAL *)rtMemBaseAlloc(sizeof(*pThis));
95 if (!pThis)
96 return VERR_NO_MEMORY;
97
98 /*
99 * Create the semaphore.
100 * (Auto reset, not signaled, private event object.)
101 */
102 pThis->hev = CreateEvent(NULL, FALSE, FALSE, NULL);
103 if (pThis->hev != NULL) /* not INVALID_HANDLE_VALUE */
104 {
105 pThis->u32Magic = RTSEMEVENT_MAGIC;
106 pThis->fFlags = fFlags;
107#ifdef RTSEMEVENT_STRICT
108 if (!pszNameFmt)
109 {
110 static uint32_t volatile s_iSemEventAnon = 0;
111 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
112 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
113 "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
114 }
115 else
116 {
117 va_list va;
118 va_start(va, pszNameFmt);
119 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
120 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
121 pszNameFmt, va);
122 va_end(va);
123 }
124 pThis->fEverHadSignallers = false;
125#else
126 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
127#endif
128
129 *phEventSem = pThis;
130 return VINF_SUCCESS;
131 }
132
133 DWORD dwErr = GetLastError();
134 if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
135 RTMemFree(pThis);
136 else
137 rtMemBaseFree(pThis);
138 return RTErrConvertFromWin32(dwErr);
139}
140
141
142RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
143{
144 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
145 if (pThis == NIL_RTSEMEVENT)
146 return VINF_SUCCESS;
147 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
148 AssertReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE);
149
150 /*
151 * Invalidate the handle and close the semaphore.
152 */
153 int rc = VINF_SUCCESS;
154 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC, RTSEMEVENT_MAGIC), VERR_INVALID_HANDLE);
155 if (CloseHandle(pThis->hev))
156 {
157#ifdef RTSEMEVENT_STRICT
158 RTLockValidatorRecSharedDelete(&pThis->Signallers);
159#endif
160 if (!(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
161 RTMemFree(pThis);
162 else
163 rtMemBaseFree(pThis);
164 }
165 else
166 {
167 DWORD dwErr = GetLastError();
168 rc = RTErrConvertFromWin32(dwErr);
169 AssertMsgFailed(("Destroy hEventSem %p failed, lasterr=%u (%Rrc)\n", pThis, dwErr, rc));
170 /* Leak it. */
171 }
172
173 return rc;
174}
175
176
177RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
178{
179 /*
180 * Validate input.
181 */
182 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
183 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
184 AssertReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE);
185
186#ifdef RTSEMEVENT_STRICT
187 if (pThis->fEverHadSignallers)
188 {
189 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
190 if (RT_FAILURE(rc9))
191 return rc9;
192 }
193#endif
194
195 /*
196 * Signal the object.
197 */
198 if (SetEvent(pThis->hev))
199 return VINF_SUCCESS;
200 DWORD dwErr = GetLastError();
201 AssertMsgFailed(("Signaling hEventSem %p failed, lasterr=%d\n", pThis, dwErr));
202 return RTErrConvertFromWin32(dwErr);
203}
204
205
206/** Goto avoidance. */
207DECL_FORCE_INLINE(int) rtSemEventWaitHandleStatus(struct RTSEMEVENTINTERNAL *pThis, DWORD rc)
208{
209 switch (rc)
210 {
211 case WAIT_OBJECT_0: return VINF_SUCCESS;
212 case WAIT_TIMEOUT: return VERR_TIMEOUT;
213 case WAIT_IO_COMPLETION: return VERR_INTERRUPTED;
214 case WAIT_ABANDONED: return VERR_SEM_OWNER_DIED;
215 default:
216 AssertMsgFailed(("%u\n", rc));
217 case WAIT_FAILED:
218 {
219 int rc2 = RTErrConvertFromWin32(GetLastError());
220 AssertMsgFailed(("Wait on hEventSem %p failed, rc=%d lasterr=%d\n", pThis, rc, GetLastError()));
221 if (rc2)
222 return rc2;
223
224 AssertMsgFailed(("WaitForSingleObject(event) -> rc=%d while converted lasterr=%d\n", rc, rc2));
225 RT_NOREF_PV(pThis);
226 return VERR_INTERNAL_ERROR;
227 }
228 }
229}
230
231
232#undef RTSemEventWaitNoResume
233RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
234{
235 /*
236 * Validate input.
237 */
238 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
239 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
240 AssertReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE);
241
242 /*
243 * Wait for condition.
244 */
245#ifdef RTSEMEVENT_STRICT
246 RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
247 ? RTThreadSelfAutoAdopt()
248 : RTThreadSelf();
249 if (pThis->fEverHadSignallers)
250 {
251 DWORD rc = WaitForSingleObjectEx(pThis->hev,
252 0 /*Timeout*/,
253 TRUE /*fAlertable*/);
254 if (rc != WAIT_TIMEOUT || cMillies == 0)
255 return rtSemEventWaitHandleStatus(pThis, rc);
256 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, NULL /*pSrcPos*/, false,
257 cMillies, RTTHREADSTATE_EVENT, true);
258 if (RT_FAILURE(rc9))
259 return rc9;
260 }
261#else
262 RTTHREAD hThreadSelf = RTThreadSelf();
263#endif
264 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
265 DWORD rc = WaitForSingleObjectEx(pThis->hev,
266 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
267 TRUE /*fAlertable*/);
268 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
269 return rtSemEventWaitHandleStatus(pThis, rc);
270}
271
272
273RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
274{
275#ifdef RTSEMEVENT_STRICT
276 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
277 AssertPtrReturnVoid(pThis);
278 AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
279
280 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
281 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
282#else
283 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
284#endif
285}
286
287
288RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
289{
290#ifdef RTSEMEVENT_STRICT
291 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
292 AssertPtrReturnVoid(pThis);
293 AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
294
295 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
296 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
297#else
298 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
299#endif
300}
301
302
303RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
304{
305#ifdef RTSEMEVENT_STRICT
306 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
307 AssertPtrReturnVoid(pThis);
308 AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
309
310 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
311#else
312 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
313#endif
314}
315
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