VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/semeventmulti-win.cpp@ 76409

Last change on this file since 76409 was 69111, checked in by vboxsync, 7 years ago

(C) year

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