VirtualBox

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

Last change on this file since 34801 was 32970, checked in by vboxsync, 14 years ago

RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug for windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.1 KB
Line 
1/* $Id: semeventmulti-win.cpp 32970 2010-10-07 10:08:00Z 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-2010 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 <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#endif
112
113 *phEventMultiSem = pThis;
114 return VINF_SUCCESS;
115 }
116
117 DWORD dwErr = GetLastError();
118 RTMemFree(pThis);
119 return RTErrConvertFromWin32(dwErr);
120}
121
122
123RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
124{
125 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
126 if (pThis == NIL_RTSEMEVENT) /* don't bitch */
127 return VINF_SUCCESS;
128 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
129 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
130
131 /*
132 * Invalidate the handle and close the semaphore.
133 */
134 int rc = VINF_SUCCESS;
135 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC, RTSEMEVENTMULTI_MAGIC), VERR_INVALID_HANDLE);
136 if (CloseHandle(pThis->hev))
137 {
138#ifdef RTSEMEVENT_STRICT
139 RTLockValidatorRecSharedDelete(&pThis->Signallers);
140#endif
141 RTMemFree(pThis);
142 }
143 else
144 {
145 DWORD dwErr = GetLastError();
146 rc = RTErrConvertFromWin32(dwErr);
147 AssertMsgFailed(("Destroy hEventMultiSem %p failed, lasterr=%u (%Rrc)\n", pThis, dwErr, rc));
148 /* Leak it. */
149 }
150
151 return rc;
152}
153
154
155RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
156{
157 /*
158 * Validate input.
159 */
160 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
161 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
162 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
163
164#ifdef RTSEMEVENT_STRICT
165 if (pThis->fEverHadSignallers)
166 {
167 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
168 if (RT_FAILURE(rc9))
169 return rc9;
170 }
171#endif
172
173 /*
174 * Signal the object.
175 */
176 if (SetEvent(pThis->hev))
177 return VINF_SUCCESS;
178 DWORD dwErr = GetLastError();
179 AssertMsgFailed(("Signaling hEventMultiSem %p failed, lasterr=%d\n", pThis, dwErr));
180 return RTErrConvertFromWin32(dwErr);
181}
182
183
184RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
185{
186 /*
187 * Validate input.
188 */
189 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
190 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
191 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
192
193 /*
194 * Reset the object.
195 */
196 if (ResetEvent(pThis->hev))
197 return VINF_SUCCESS;
198 DWORD dwErr = GetLastError();
199 AssertMsgFailed(("Resetting hEventMultiSem %p failed, lasterr=%d\n", pThis, dwErr));
200 return RTErrConvertFromWin32(dwErr);
201}
202
203
204/** Goto avoidance. */
205DECL_FORCE_INLINE(int)
206rtSemEventWaitHandleStatus(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, DWORD rc)
207{
208 switch (rc)
209 {
210 case WAIT_OBJECT_0: return VINF_SUCCESS;
211 case WAIT_TIMEOUT: return VERR_TIMEOUT;
212 case WAIT_IO_COMPLETION: return fFlags & RTSEMWAIT_FLAGS_RESUME ? VERR_TIMEOUT : VERR_INTERRUPTED;
213 case WAIT_ABANDONED: return VERR_SEM_OWNER_DIED;
214 default:
215 AssertMsgFailed(("%u\n", rc));
216 case WAIT_FAILED:
217 {
218 int rc2 = RTErrConvertFromWin32(GetLastError());
219 AssertMsgFailed(("Wait on hEventMultiSem %p failed, rc=%d lasterr=%d\n", pThis, rc, GetLastError()));
220 if (rc2)
221 return rc2;
222
223 AssertMsgFailed(("WaitForSingleObject(event) -> rc=%d while converted lasterr=%d\n", rc, rc2));
224 return VERR_INTERNAL_ERROR;
225 }
226 }
227}
228
229
230DECLINLINE(int) rtSemEventMultiWinWait(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
231 PCRTLOCKVALSRCPOS pSrcPos)
232{
233 /*
234 * Validate input.
235 */
236 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
237 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
238 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
239 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
240
241 /*
242 * Convert the timeout to a millisecond count.
243 */
244 uint64_t uAbsDeadline;
245 DWORD dwMsTimeout;
246 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
247 {
248 dwMsTimeout = INFINITE;
249 uAbsDeadline = UINT64_MAX;
250 }
251 else
252 {
253 if (fFlags & RTSEMWAIT_FLAGS_NANOSECS)
254 uTimeout = uTimeout < UINT64_MAX - UINT32_C(1000000) / 2
255 ? (uTimeout + UINT32_C(1000000) / 2) / UINT32_C(1000000)
256 : UINT64_MAX / UINT32_C(1000000);
257 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
258 {
259 uAbsDeadline = uTimeout;
260 uint64_t u64Now = RTTimeSystemMilliTS();
261 if (u64Now < uTimeout)
262 uTimeout -= u64Now;
263 else
264 uTimeout = 0;
265 }
266 else if (fFlags & RTSEMWAIT_FLAGS_RESUME)
267 uAbsDeadline = RTTimeSystemMilliTS() + uTimeout;
268 else
269 uAbsDeadline = UINT64_MAX;
270
271 dwMsTimeout = uTimeout < UINT32_MAX
272 ? (DWORD)uTimeout
273 : INFINITE;
274 }
275
276 /*
277 * Do the wait.
278 */
279 DWORD rc;
280#ifdef RTSEMEVENT_STRICT
281 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
282 if (pThis->fEverHadSignallers)
283 {
284 do
285 rc = WaitForSingleObjectEx(pThis->hev, 0 /*Timeout*/, TRUE /*fAlertable*/);
286 while (rc == WAIT_IO_COMPLETION && (fFlags & RTSEMWAIT_FLAGS_RESUME));
287 if (rc != WAIT_TIMEOUT || dwMsTimeout == 0)
288 return rtSemEventWaitHandleStatus(pThis, fFlags, rc);
289 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
290 dwMsTimeout, RTTHREADSTATE_EVENT_MULTI, true);
291 if (RT_FAILURE(rc9))
292 return rc9;
293 }
294#else
295 RTTHREAD hThreadSelf = RTThreadSelf();
296#endif
297 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
298 rc = WaitForSingleObjectEx(pThis->hev, dwMsTimeout, TRUE /*fAlertable*/);
299 if (rc == WAIT_IO_COMPLETION && (fFlags & RTSEMWAIT_FLAGS_RESUME))
300 {
301 while ( rc == WAIT_IO_COMPLETION
302 && RTTimeSystemMilliTS() < uAbsDeadline)
303 rc = WaitForSingleObjectEx(pThis->hev, dwMsTimeout, TRUE /*fAlertable*/);
304
305 }
306 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
307 return rtSemEventWaitHandleStatus(pThis, fFlags, rc);
308}
309
310
311
312#undef RTSemEventMultiWaitEx
313RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
314{
315#ifndef RTSEMEVENT_STRICT
316 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, NULL);
317#else
318 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
319 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
320#endif
321}
322
323
324RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
325 RTHCUINTPTR uId, RT_SRC_POS_DECL)
326{
327 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
328 return rtSemEventMultiWinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
329}
330
331
332
333RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
334{
335#ifdef RTSEMEVENT_STRICT
336 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
337 AssertPtrReturnVoid(pThis);
338 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
339
340 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
341 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
342#endif
343}
344
345
346RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
347{
348#ifdef RTSEMEVENT_STRICT
349 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
350 AssertPtrReturnVoid(pThis);
351 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
352
353 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
354 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
355#endif
356}
357
358
359RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
360{
361#ifdef RTSEMEVENT_STRICT
362 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
363 AssertPtrReturnVoid(pThis);
364 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
365
366 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
367#endif
368}
369
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