VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/semeventmulti-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: 13.0 KB
Line 
1/* $Id: semeventmulti-win.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphore, Windows.
4 *
5 * @remarks This file is identical to semevent-win.cpp except for the 2nd
6 * CreateEvent parameter, the reset function and the "Multi" infix.
7 */
8
9/*
10 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * The contents of this file may alternatively be used under the terms
29 * of the Common Development and Distribution License Version 1.0
30 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31 * in the VirtualBox distribution, in which case the provisions of the
32 * CDDL are applicable instead of those of the GPL.
33 *
34 * You may elect to license modified versions of this file under the
35 * terms and conditions of either the GPL or the CDDL or both.
36 *
37 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38 */
39
40
41/*********************************************************************************************************************************
42* Header Files *
43*********************************************************************************************************************************/
44#define LOG_GROUP RTLOGGROUP_SEMAPHORE
45#include <iprt/win/windows.h>
46
47#include <iprt/semaphore.h>
48#include "internal/iprt.h"
49
50#include <iprt/asm.h>
51#include <iprt/assert.h>
52#include <iprt/err.h>
53#include <iprt/lockvalidator.h>
54#include <iprt/mem.h>
55#include <iprt/thread.h>
56#include <iprt/time.h>
57#include "internal/magics.h"
58#include "internal/strict.h"
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64struct RTSEMEVENTMULTIINTERNAL
65{
66 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
67 uint32_t u32Magic;
68 /** The event handle. */
69 HANDLE hev;
70#ifdef RTSEMEVENT_STRICT
71 /** Signallers. */
72 RTLOCKVALRECSHRD Signallers;
73 /** Indicates that lock validation should be performed. */
74 bool volatile fEverHadSignallers;
75#endif
76};
77
78
79
80RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
81{
82 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
83}
84
85
86RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
87 const char *pszNameFmt, ...)
88{
89 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
90
91 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(*pThis));
92 if (!pThis)
93 return VERR_NO_MEMORY;
94
95 /*
96 * Create the semaphore.
97 * (Manual reset, not signaled, private event object.)
98 */
99 pThis->hev = CreateEvent(NULL, TRUE, FALSE, NULL);
100 if (pThis->hev != NULL) /* not INVALID_HANDLE_VALUE */
101 {
102 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
103#ifdef RTSEMEVENT_STRICT
104 if (!pszNameFmt)
105 {
106 static uint32_t volatile s_iSemEventMultiAnon = 0;
107 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
108 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
109 "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1);
110 }
111 else
112 {
113 va_list va;
114 va_start(va, pszNameFmt);
115 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
116 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
117 pszNameFmt, va);
118 va_end(va);
119 }
120 pThis->fEverHadSignallers = false;
121#else
122 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
123#endif
124
125 *phEventMultiSem = pThis;
126 return VINF_SUCCESS;
127 }
128
129 DWORD dwErr = GetLastError();
130 RTMemFree(pThis);
131 return RTErrConvertFromWin32(dwErr);
132}
133
134
135RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
136{
137 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
138 if (pThis == NIL_RTSEMEVENT) /* don't bitch */
139 return VINF_SUCCESS;
140 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
141 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
142
143 /*
144 * Invalidate the handle and close the semaphore.
145 */
146 int rc = VINF_SUCCESS;
147 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC, RTSEMEVENTMULTI_MAGIC), VERR_INVALID_HANDLE);
148 if (CloseHandle(pThis->hev))
149 {
150#ifdef RTSEMEVENT_STRICT
151 RTLockValidatorRecSharedDelete(&pThis->Signallers);
152#endif
153 RTMemFree(pThis);
154 }
155 else
156 {
157 DWORD dwErr = GetLastError();
158 rc = RTErrConvertFromWin32(dwErr);
159 AssertMsgFailed(("Destroy hEventMultiSem %p failed, lasterr=%u (%Rrc)\n", pThis, dwErr, rc));
160 /* Leak it. */
161 }
162
163 return rc;
164}
165
166
167RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
168{
169 /*
170 * Validate input.
171 */
172 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
174 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
175
176#ifdef RTSEMEVENT_STRICT
177 if (pThis->fEverHadSignallers)
178 {
179 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
180 if (RT_FAILURE(rc9))
181 return rc9;
182 }
183#endif
184
185 /*
186 * Signal the object.
187 */
188 if (SetEvent(pThis->hev))
189 return VINF_SUCCESS;
190 DWORD dwErr = GetLastError();
191 AssertMsgFailed(("Signaling hEventMultiSem %p failed, lasterr=%d\n", pThis, dwErr));
192 return RTErrConvertFromWin32(dwErr);
193}
194
195
196RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
197{
198 /*
199 * Validate input.
200 */
201 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
202 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
203 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
204
205 /*
206 * Reset the object.
207 */
208 if (ResetEvent(pThis->hev))
209 return VINF_SUCCESS;
210 DWORD dwErr = GetLastError();
211 AssertMsgFailed(("Resetting hEventMultiSem %p failed, lasterr=%d\n", pThis, dwErr));
212 return RTErrConvertFromWin32(dwErr);
213}
214
215
216/** Goto avoidance. */
217DECL_FORCE_INLINE(int)
218rtSemEventWaitHandleStatus(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, DWORD rc)
219{
220 switch (rc)
221 {
222 case WAIT_OBJECT_0: return VINF_SUCCESS;
223 case WAIT_TIMEOUT: return VERR_TIMEOUT;
224 case WAIT_IO_COMPLETION: return fFlags & RTSEMWAIT_FLAGS_RESUME ? VERR_TIMEOUT : VERR_INTERRUPTED;
225 case WAIT_ABANDONED: return VERR_SEM_OWNER_DIED;
226 default:
227 AssertMsgFailed(("%u\n", rc));
228 case WAIT_FAILED:
229 {
230 int rc2 = RTErrConvertFromWin32(GetLastError());
231 AssertMsgFailed(("Wait on hEventMultiSem %p failed, rc=%d lasterr=%d\n", pThis, rc, GetLastError()));
232 if (rc2)
233 return rc2;
234
235 AssertMsgFailed(("WaitForSingleObject(event) -> rc=%d while converted lasterr=%d\n", rc, rc2));
236 RT_NOREF_PV(pThis);
237 return VERR_INTERNAL_ERROR;
238 }
239 }
240}
241
242
243DECLINLINE(int) rtSemEventMultiWinWait(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
244 PCRTLOCKVALSRCPOS pSrcPos)
245{
246 /*
247 * Validate input.
248 */
249 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
250 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
251 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
252 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
253
254 /*
255 * Convert the timeout to a millisecond count.
256 */
257 uint64_t uAbsDeadline;
258 DWORD dwMsTimeout;
259 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
260 {
261 dwMsTimeout = INFINITE;
262 uAbsDeadline = UINT64_MAX;
263 }
264 else
265 {
266 if (fFlags & RTSEMWAIT_FLAGS_NANOSECS)
267 uTimeout = uTimeout < UINT64_MAX - UINT32_C(1000000) / 2
268 ? (uTimeout + UINT32_C(1000000) / 2) / UINT32_C(1000000)
269 : UINT64_MAX / UINT32_C(1000000);
270 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
271 {
272 uAbsDeadline = uTimeout;
273 uint64_t u64Now = RTTimeSystemMilliTS();
274 if (u64Now < uTimeout)
275 uTimeout -= u64Now;
276 else
277 uTimeout = 0;
278 }
279 else if (fFlags & RTSEMWAIT_FLAGS_RESUME)
280 uAbsDeadline = RTTimeSystemMilliTS() + uTimeout;
281 else
282 uAbsDeadline = UINT64_MAX;
283
284 dwMsTimeout = uTimeout < UINT32_MAX
285 ? (DWORD)uTimeout
286 : INFINITE;
287 }
288
289 /*
290 * Do the wait.
291 */
292 DWORD rc;
293#ifdef RTSEMEVENT_STRICT
294 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
295 if (pThis->fEverHadSignallers)
296 {
297 do
298 rc = WaitForSingleObjectEx(pThis->hev, 0 /*Timeout*/, TRUE /*fAlertable*/);
299 while (rc == WAIT_IO_COMPLETION && (fFlags & RTSEMWAIT_FLAGS_RESUME));
300 if (rc != WAIT_TIMEOUT || dwMsTimeout == 0)
301 return rtSemEventWaitHandleStatus(pThis, fFlags, rc);
302 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
303 dwMsTimeout, RTTHREADSTATE_EVENT_MULTI, true);
304 if (RT_FAILURE(rc9))
305 return rc9;
306 }
307#else
308 RTTHREAD hThreadSelf = RTThreadSelf();
309 RT_NOREF_PV(pSrcPos);
310#endif
311 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
312 rc = WaitForSingleObjectEx(pThis->hev, dwMsTimeout, TRUE /*fAlertable*/);
313 if (rc == WAIT_IO_COMPLETION && (fFlags & RTSEMWAIT_FLAGS_RESUME))
314 {
315 while ( rc == WAIT_IO_COMPLETION
316 && RTTimeSystemMilliTS() < uAbsDeadline)
317 rc = WaitForSingleObjectEx(pThis->hev, dwMsTimeout, TRUE /*fAlertable*/);
318
319 }
320 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
321 return rtSemEventWaitHandleStatus(pThis, fFlags, rc);
322}
323
324
325
326#undef RTSemEventMultiWaitEx
327RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
328{
329#ifndef RTSEMEVENT_STRICT
330 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, NULL);
331#else
332 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
333 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
334#endif
335}
336
337
338RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
339 RTHCUINTPTR uId, RT_SRC_POS_DECL)
340{
341 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
342 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
343}
344
345
346
347RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
348{
349#ifdef RTSEMEVENT_STRICT
350 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
351 AssertPtrReturnVoid(pThis);
352 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
353
354 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
355 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
356#else
357 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
358#endif
359}
360
361
362RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
363{
364#ifdef RTSEMEVENT_STRICT
365 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
366 AssertPtrReturnVoid(pThis);
367 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
368
369 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
370 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
371#else
372 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
373#endif
374}
375
376
377RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
378{
379#ifdef RTSEMEVENT_STRICT
380 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
381 AssertPtrReturnVoid(pThis);
382 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
383
384 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
385#else
386 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
387#endif
388}
389
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use