VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/poll-win.cpp@ 37043

Last change on this file since 37043 was 32431, checked in by vboxsync, 14 years ago

scm cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1/* $Id: poll-win.cpp 32431 2010-09-11 18:02:17Z vboxsync $ */
2/** @file
3 * IPRT - Polling I/O Handles, Windows Implementation.
4 *
5 * @todo merge poll-win.cpp and poll-posix.cpp, there is lots of common code.
6 */
7
8/*
9 * Copyright (C) 2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 */
28
29
30/*******************************************************************************
31* Header Files *
32*******************************************************************************/
33#include <Windows.h>
34
35#include <iprt/poll.h>
36#include "internal/iprt.h"
37
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/err.h>
41#include <iprt/mem.h>
42#include <iprt/pipe.h>
43#include <iprt/string.h>
44#include <iprt/thread.h>
45#include <iprt/time.h>
46
47#include "internal/pipe.h"
48#define IPRT_INTERNAL_SOCKET_POLLING_ONLY
49#include "internal/socket.h"
50#include "internal/magics.h"
51
52
53/*******************************************************************************
54* Structures and Typedefs *
55*******************************************************************************/
56/**
57 * Handle entry in a poll set.
58 */
59typedef struct RTPOLLSETHNDENT
60{
61 /** The handle type. */
62 RTHANDLETYPE enmType;
63 /** The handle ID. */
64 uint32_t id;
65 /** The events we're waiting for here. */
66 uint32_t fEvents;
67 /** Set if this is the final entry for this handle.
68 * If the handle is entered more than once, this will be clear for all but
69 * the last entry. */
70 bool fFinalEntry;
71 /** The handle union. */
72 RTHANDLEUNION u;
73} RTPOLLSETHNDENT;
74/** Pointer to a handle entry. */
75typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
76
77
78/**
79 * Poll set data, Windows.
80 */
81typedef struct RTPOLLSETINTERNAL
82{
83 /** The magic value (RTPOLLSET_MAGIC). */
84 uint32_t u32Magic;
85 /** Set when someone is polling or making changes. */
86 bool volatile fBusy;
87
88 /** The number of valid handles in the set. */
89 uint32_t cHandles;
90 /** The native handles. */
91 HANDLE ahNative[MAXIMUM_WAIT_OBJECTS];
92 /** Array of handles and IDs. */
93 RTPOLLSETHNDENT aHandles[MAXIMUM_WAIT_OBJECTS];
94} RTPOLLSETINTERNAL;
95
96
97/**
98 * Common worker for RTPoll and RTPollNoResume
99 */
100static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
101{
102 int rc;
103
104 if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
105 return VERR_DEADLOCK;
106
107 /*
108 * Check for special case, RTThreadSleep...
109 */
110 uint32_t const cHandles = pThis->cHandles;
111 if (cHandles == 0)
112 {
113 rc = RTThreadSleep(cMillies);
114 if (RT_SUCCESS(rc))
115 rc = VERR_TIMEOUT;
116 return rc;
117 }
118
119 /*
120 * Check + prepare the handles before waiting.
121 */
122 uint32_t fEvents = 0;
123 bool const fNoWait = cMillies == 0;
124 uint32_t i;
125 for (i = 0; i < cHandles; i++)
126 {
127 switch (pThis->aHandles[i].enmType)
128 {
129 case RTHANDLETYPE_PIPE:
130 fEvents = rtPipePollStart(pThis->aHandles[i].u.hPipe, pThis, pThis->aHandles[i].fEvents,
131 pThis->aHandles[i].fFinalEntry, fNoWait);
132 break;
133
134 case RTHANDLETYPE_SOCKET:
135 fEvents = rtSocketPollStart(pThis->aHandles[i].u.hSocket, pThis, pThis->aHandles[i].fEvents,
136 pThis->aHandles[i].fFinalEntry, fNoWait);
137 break;
138
139 default:
140 AssertFailed();
141 fEvents = UINT32_MAX;
142 break;
143 }
144 if (fEvents)
145 break;
146 }
147 if ( fEvents
148 || fNoWait)
149 {
150
151 if (pid)
152 *pid = pThis->aHandles[i].id;
153 if (pfEvents)
154 *pfEvents = fEvents;
155 rc = !fEvents
156 ? VERR_TIMEOUT
157 : fEvents != UINT32_MAX
158 ? VINF_SUCCESS
159 : VERR_INTERNAL_ERROR_4;
160
161 /* clean up */
162 if (!fNoWait)
163 while (i-- > 0)
164 {
165 switch (pThis->aHandles[i].enmType)
166 {
167 case RTHANDLETYPE_PIPE:
168 rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents,
169 pThis->aHandles[i].fFinalEntry, false);
170 break;
171
172 case RTHANDLETYPE_SOCKET:
173 rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
174 pThis->aHandles[i].fFinalEntry, false);
175 break;
176
177 default:
178 AssertFailed();
179 break;
180 }
181 }
182
183 return rc;
184 }
185
186 /*
187 * Wait.
188 */
189 DWORD dwRc = WaitForMultipleObjectsEx(cHandles, &pThis->ahNative[0],
190 FALSE /*fWaitAll */,
191 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
192 TRUE /*fAlertable*/);
193 if ( dwRc >= WAIT_OBJECT_0
194 && dwRc < WAIT_OBJECT_0 + cHandles)
195 rc = VERR_INTERRUPTED;
196 else if (dwRc == WAIT_TIMEOUT)
197 rc = VERR_TIMEOUT;
198 else if (dwRc == WAIT_IO_COMPLETION)
199 rc = VERR_INTERRUPTED;
200 else if (dwRc == WAIT_FAILED)
201 rc = RTErrConvertFromWin32(GetLastError());
202 else
203 {
204 AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc));
205 rc = VERR_INTERNAL_ERROR_5;
206 }
207
208 /*
209 * Get event (if pending) and do wait cleanup.
210 */
211 bool fHarvestEvents = true;
212 for (i = 0; i < cHandles; i++)
213 {
214 fEvents = 0;
215 switch (pThis->aHandles[i].enmType)
216 {
217 case RTHANDLETYPE_PIPE:
218 fEvents = rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents,
219 pThis->aHandles[i].fFinalEntry, fHarvestEvents);
220 break;
221
222 case RTHANDLETYPE_SOCKET:
223 fEvents = rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
224 pThis->aHandles[i].fFinalEntry, fHarvestEvents);
225 break;
226
227 default:
228 AssertFailed();
229 break;
230 }
231 if ( fEvents
232 && fHarvestEvents)
233 {
234 Assert(fEvents != UINT32_MAX);
235 fHarvestEvents = false;
236 if (pfEvents)
237 *pfEvents = fEvents;
238 if (pid)
239 *pid = pThis->aHandles[i].id;
240 rc = VINF_SUCCESS;
241 }
242 }
243
244 return rc;
245}
246
247
248RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
249{
250 RTPOLLSETINTERNAL *pThis = hPollSet;
251 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
252 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
253 AssertPtrNull(pfEvents);
254 AssertPtrNull(pid);
255
256 /*
257 * Set the busy flag and do the job.
258 */
259 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
260
261 int rc;
262 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
263 {
264 do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
265 while (rc == VERR_INTERRUPTED);
266 }
267 else
268 {
269 uint64_t MsStart = RTTimeMilliTS();
270 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
271 while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
272 {
273 if (RTTimeMilliTS() - MsStart >= cMillies)
274 {
275 rc = VERR_TIMEOUT;
276 break;
277 }
278 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
279 }
280 }
281
282 ASMAtomicWriteBool(&pThis->fBusy, false);
283
284 return rc;
285}
286
287
288RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
289{
290 RTPOLLSETINTERNAL *pThis = hPollSet;
291 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
292 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
293 AssertPtrNull(pfEvents);
294 AssertPtrNull(pid);
295
296 /*
297 * Set the busy flag and do the job.
298 */
299 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
300
301 int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
302
303 ASMAtomicWriteBool(&pThis->fBusy, false);
304
305 return rc;
306}
307
308
309RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
310{
311 AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
312 RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAllocZ(sizeof(RTPOLLSETINTERNAL));
313 if (!pThis)
314 return VERR_NO_MEMORY;
315
316 pThis->u32Magic = RTPOLLSET_MAGIC;
317 pThis->fBusy = false;
318 pThis->cHandles = 0;
319 for (size_t i = 0; i < RT_ELEMENTS(pThis->ahNative); i++)
320 pThis->ahNative[i] = INVALID_HANDLE_VALUE;
321
322 *phPollSet = pThis;
323 return VINF_SUCCESS;
324}
325
326
327RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
328{
329 RTPOLLSETINTERNAL *pThis = hPollSet;
330 if (pThis == NIL_RTPOLLSET)
331 return VINF_SUCCESS;
332 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
333 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
334 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
335
336 ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
337 RTMemFree(pThis);
338
339 return VINF_SUCCESS;
340}
341
342
343RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
344{
345 /*
346 * Validate the input (tedious).
347 */
348 RTPOLLSETINTERNAL *pThis = hPollSet;
349 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
350 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
351 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
352 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
353 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
354
355 if (!pHandle)
356 return VINF_SUCCESS;
357 AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
358 AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
359
360 /*
361 * Set the busy flag and do the job.
362 */
363 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
364
365 int rc = VINF_SUCCESS;
366 HANDLE hNative = INVALID_HANDLE_VALUE;
367 RTHANDLEUNION uh;
368 uh.uInt = 0;
369 switch (pHandle->enmType)
370 {
371 case RTHANDLETYPE_PIPE:
372 uh.hPipe = pHandle->u.hPipe;
373 if (uh.hPipe != NIL_RTPIPE)
374 rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative);
375 break;
376
377 case RTHANDLETYPE_SOCKET:
378 uh.hSocket = pHandle->u.hSocket;
379 if (uh.hSocket != NIL_RTSOCKET)
380 rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative);
381 break;
382
383 case RTHANDLETYPE_FILE:
384 AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
385 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
386 break;
387
388 case RTHANDLETYPE_THREAD:
389 AssertMsgFailed(("Thread handles are currently not pollable\n"));
390 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
391 break;
392
393 default:
394 AssertMsgFailed(("\n"));
395 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
396 break;
397 }
398 if ( RT_SUCCESS(rc)
399 && hNative != INVALID_HANDLE_VALUE)
400 {
401 uint32_t const i = pThis->cHandles;
402
403 /* Check that the handle ID doesn't exist already. */
404 uint32_t iPrev = UINT32_MAX;
405 uint32_t j = i;
406 while (j-- > 0)
407 {
408 if (pThis->aHandles[j].id == id)
409 {
410 rc = VERR_POLL_HANDLE_ID_EXISTS;
411 break;
412 }
413 if ( pThis->aHandles[j].enmType == pHandle->enmType
414 && pThis->aHandles[j].u.uInt == uh.uInt)
415 iPrev = j;
416 }
417
418 /* Check that we won't overflow the poll set now. */
419 if ( RT_SUCCESS(rc)
420 && i + 1 > RT_ELEMENTS(pThis->ahNative))
421 rc = VERR_POLL_SET_IS_FULL;
422 if (RT_SUCCESS(rc))
423 {
424 /* Add the handles to the two parallel arrays. */
425 pThis->ahNative[i] = hNative;
426 pThis->aHandles[i].enmType = pHandle->enmType;
427 pThis->aHandles[i].u = uh;
428 pThis->aHandles[i].id = id;
429 pThis->aHandles[i].fEvents = fEvents;
430 pThis->aHandles[i].fFinalEntry = true;
431 pThis->cHandles = i + 1;
432
433 if (iPrev != UINT32_MAX)
434 {
435 Assert(pThis->aHandles[i].fFinalEntry);
436 pThis->aHandles[i].fFinalEntry = false;
437 }
438
439 rc = VINF_SUCCESS;
440 }
441 }
442
443 ASMAtomicWriteBool(&pThis->fBusy, false);
444 return rc;
445}
446
447
448RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
449{
450 /*
451 * Validate the input.
452 */
453 RTPOLLSETINTERNAL *pThis = hPollSet;
454 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
455 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
456 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
457
458 /*
459 * Set the busy flag and do the job.
460 */
461 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
462
463 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
464 uint32_t i = pThis->cHandles;
465 while (i-- > 0)
466 if (pThis->aHandles[i].id == id)
467 {
468 /* Save some details for the duplicate searching. */
469 bool fFinalEntry = pThis->aHandles[i].fFinalEntry;
470 RTHANDLETYPE enmType = pThis->aHandles[i].enmType;
471 RTHANDLEUNION uh = pThis->aHandles[i].u;
472
473 /* Remove the entry. */
474 pThis->cHandles--;
475 size_t const cToMove = pThis->cHandles - i;
476 if (cToMove)
477 {
478 memmove(&pThis->aHandles[i], &pThis->aHandles[i + 1], cToMove * sizeof(pThis->aHandles[i]));
479 memmove(&pThis->ahNative[i], &pThis->ahNative[i + 1], cToMove * sizeof(pThis->ahNative[i]));
480 }
481
482 /* Check for duplicate and set the fFinalEntry flag. */
483 if (fFinalEntry)
484 while (i-- > 0)
485 if ( pThis->aHandles[i].u.uInt == uh.uInt
486 && pThis->aHandles[i].enmType == enmType)
487 {
488 Assert(!pThis->aHandles[i].fFinalEntry);
489 pThis->aHandles[i].fFinalEntry = true;
490 break;
491 }
492
493 rc = VINF_SUCCESS;
494 break;
495 }
496
497 ASMAtomicWriteBool(&pThis->fBusy, false);
498 return rc;
499}
500
501
502RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
503{
504 /*
505 * Validate the input.
506 */
507 RTPOLLSETINTERNAL *pThis = hPollSet;
508 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
509 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
510 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
511 AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
512
513 /*
514 * Set the busy flag and do the job.
515 */
516 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
517
518 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
519 uint32_t i = pThis->cHandles;
520 while (i-- > 0)
521 if (pThis->aHandles[i].id == id)
522 {
523 if (pHandle)
524 {
525 pHandle->enmType = pThis->aHandles[i].enmType;
526 pHandle->u = pThis->aHandles[i].u;
527 }
528 rc = VINF_SUCCESS;
529 break;
530 }
531
532 ASMAtomicWriteBool(&pThis->fBusy, false);
533 return rc;
534}
535
536
537RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
538{
539 /*
540 * Validate the input.
541 */
542 RTPOLLSETINTERNAL *pThis = hPollSet;
543 AssertPtrReturn(pThis, UINT32_MAX);
544 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
545
546 /*
547 * Set the busy flag and do the job.
548 */
549 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
550 uint32_t cHandles = pThis->cHandles;
551 ASMAtomicWriteBool(&pThis->fBusy, false);
552
553 return cHandles;
554}
555
556RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
557{
558 /*
559 * Validate the input.
560 */
561 RTPOLLSETINTERNAL *pThis = hPollSet;
562 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
563 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
564 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
565 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
566 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
567
568 /*
569 * Set the busy flag and do the job.
570 */
571 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
572
573 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
574 uint32_t i = pThis->cHandles;
575 while (i-- > 0)
576 if (pThis->aHandles[i].id == id)
577 {
578 pThis->aHandles[i].fEvents = fEvents;
579 rc = VINF_SUCCESS;
580 break;
581 }
582
583 ASMAtomicWriteBool(&pThis->fBusy, false);
584 return rc;
585}
586
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