VirtualBox

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

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

Runtime/poll: Add a method to change the events to poll for without removing and adding the source again

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: poll-win.cpp 31453 2010-08-08 13:30:35Z 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);
170 break;
171
172 case RTHANDLETYPE_SOCKET:
173 rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
174 pThis->aHandles[i].fFinalEntry);
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 i = cHandles;
212 while (i-- > 0)
213 {
214 fEvents = 0;
215 switch (pThis->aHandles[i].enmType)
216 {
217 case RTHANDLETYPE_PIPE:
218 rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents,
219 pThis->aHandles[i].fFinalEntry);
220 break;
221
222 case RTHANDLETYPE_SOCKET:
223 rtSocketPollDone(pThis->aHandles[i].u.hSocket, pThis->aHandles[i].fEvents,
224 pThis->aHandles[i].fFinalEntry);
225 break;
226
227 default:
228 AssertFailed();
229 break;
230 }
231 if (fEvents)
232 {
233 Assert(fEvents != UINT32_MAX);
234 if (pfEvents)
235 *pfEvents = fEvents;
236 if (pid)
237 *pid = pThis->aHandles[i].id;
238 rc = VINF_SUCCESS;
239 }
240 }
241
242 return rc;
243}
244
245
246RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
247{
248 RTPOLLSETINTERNAL *pThis = hPollSet;
249 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
250 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
251 AssertPtrNull(pfEvents);
252 AssertPtrNull(pid);
253
254 /*
255 * Set the busy flag and do the job.
256 */
257 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
258
259 int rc;
260 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
261 {
262 do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
263 while (rc == VERR_INTERRUPTED);
264 }
265 else
266 {
267 uint64_t MsStart = RTTimeMilliTS();
268 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
269 while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
270 {
271 if (RTTimeMilliTS() - MsStart >= cMillies)
272 {
273 rc = VERR_TIMEOUT;
274 break;
275 }
276 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
277 }
278 }
279
280 ASMAtomicWriteBool(&pThis->fBusy, false);
281
282 return rc;
283}
284
285
286RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
287{
288 RTPOLLSETINTERNAL *pThis = hPollSet;
289 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
290 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
291 AssertPtrNull(pfEvents);
292 AssertPtrNull(pid);
293
294 /*
295 * Set the busy flag and do the job.
296 */
297 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
298
299 int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
300
301 ASMAtomicWriteBool(&pThis->fBusy, false);
302
303 return rc;
304}
305
306
307RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
308{
309 AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
310 RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAllocZ(sizeof(RTPOLLSETINTERNAL));
311 if (!pThis)
312 return VERR_NO_MEMORY;
313
314 pThis->u32Magic = RTPOLLSET_MAGIC;
315 pThis->fBusy = false;
316 pThis->cHandles = 0;
317 for (size_t i = 0; i < RT_ELEMENTS(pThis->ahNative); i++)
318 pThis->ahNative[i] = INVALID_HANDLE_VALUE;
319
320 *phPollSet = pThis;
321 return VINF_SUCCESS;
322}
323
324
325RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
326{
327 RTPOLLSETINTERNAL *pThis = hPollSet;
328 if (pThis == NIL_RTPOLLSET)
329 return VINF_SUCCESS;
330 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
331 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
332 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
333
334 ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
335 RTMemFree(pThis);
336
337 return VINF_SUCCESS;
338}
339
340
341RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
342{
343 /*
344 * Validate the input (tedious).
345 */
346 RTPOLLSETINTERNAL *pThis = hPollSet;
347 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
348 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
349 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
350 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
351 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
352
353 if (!pHandle)
354 return VINF_SUCCESS;
355 AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
356 AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
357
358 /*
359 * Set the busy flag and do the job.
360 */
361 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
362
363 int rc = VINF_SUCCESS;
364 HANDLE hNative = INVALID_HANDLE_VALUE;
365 RTHANDLEUNION uh;
366 uh.uInt = 0;
367 switch (pHandle->enmType)
368 {
369 case RTHANDLETYPE_PIPE:
370 uh.hPipe = pHandle->u.hPipe;
371 if (uh.hPipe != NIL_RTPIPE)
372 rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative);
373 break;
374
375 case RTHANDLETYPE_SOCKET:
376 uh.hSocket = pHandle->u.hSocket;
377 if (uh.hSocket != NIL_RTSOCKET)
378 rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative);
379 break;
380
381 case RTHANDLETYPE_FILE:
382 AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
383 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
384 break;
385
386 case RTHANDLETYPE_THREAD:
387 AssertMsgFailed(("Thread handles are currently not pollable\n"));
388 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
389 break;
390
391 default:
392 AssertMsgFailed(("\n"));
393 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
394 break;
395 }
396 if ( RT_SUCCESS(rc)
397 && hNative != INVALID_HANDLE_VALUE)
398 {
399 uint32_t const i = pThis->cHandles;
400
401 /* Check that the handle ID doesn't exist already. */
402 uint32_t iPrev = UINT32_MAX;
403 uint32_t j = i;
404 while (j-- > 0)
405 {
406 if (pThis->aHandles[j].id == id)
407 {
408 rc = VERR_POLL_HANDLE_ID_EXISTS;
409 break;
410 }
411 if ( pThis->aHandles[j].enmType == pHandle->enmType
412 && pThis->aHandles[j].u.uInt == uh.uInt)
413 iPrev = j;
414 }
415
416 /* Check that we won't overflow the poll set now. */
417 if ( RT_SUCCESS(rc)
418 && i + 1 > RT_ELEMENTS(pThis->ahNative))
419 rc = VERR_POLL_SET_IS_FULL;
420 if (RT_SUCCESS(rc))
421 {
422 /* Add the handles to the two parallel arrays. */
423 pThis->ahNative[i] = hNative;
424 pThis->aHandles[i].enmType = pHandle->enmType;
425 pThis->aHandles[i].u = uh;
426 pThis->aHandles[i].id = id;
427 pThis->aHandles[i].fEvents = fEvents;
428 pThis->aHandles[i].fFinalEntry = true;
429 pThis->cHandles = i + 1;
430
431 if (iPrev != UINT32_MAX)
432 {
433 Assert(pThis->aHandles[i].fFinalEntry);
434 pThis->aHandles[i].fFinalEntry = false;
435 }
436
437 rc = VINF_SUCCESS;
438 }
439 }
440
441 ASMAtomicWriteBool(&pThis->fBusy, false);
442 return rc;
443}
444
445
446RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
447{
448 /*
449 * Validate the input.
450 */
451 RTPOLLSETINTERNAL *pThis = hPollSet;
452 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
453 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
454 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
455
456 /*
457 * Set the busy flag and do the job.
458 */
459 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
460
461 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
462 uint32_t i = pThis->cHandles;
463 while (i-- > 0)
464 if (pThis->aHandles[i].id == id)
465 {
466 /* Save some details for the duplicate searching. */
467 bool fFinalEntry = pThis->aHandles[i].fFinalEntry;
468 RTHANDLETYPE enmType = pThis->aHandles[i].enmType;
469 RTHANDLEUNION uh = pThis->aHandles[i].u;
470
471 /* Remove the entry. */
472 pThis->cHandles--;
473 size_t const cToMove = pThis->cHandles - i;
474 if (cToMove)
475 {
476 memmove(&pThis->aHandles[i], &pThis->aHandles[i + 1], cToMove * sizeof(pThis->aHandles[i]));
477 memmove(&pThis->ahNative[i], &pThis->ahNative[i + 1], cToMove * sizeof(pThis->ahNative[i]));
478 }
479
480 /* Check for duplicate and set the fFinalEntry flag. */
481 if (fFinalEntry)
482 while (i-- > 0)
483 if ( pThis->aHandles[i].u.uInt == uh.uInt
484 && pThis->aHandles[i].enmType == enmType)
485 {
486 Assert(!pThis->aHandles[i].fFinalEntry);
487 pThis->aHandles[i].fFinalEntry = true;
488 break;
489 }
490
491 rc = VINF_SUCCESS;
492 break;
493 }
494
495 ASMAtomicWriteBool(&pThis->fBusy, false);
496 return rc;
497}
498
499
500RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
501{
502 /*
503 * Validate the input.
504 */
505 RTPOLLSETINTERNAL *pThis = hPollSet;
506 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
507 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
508 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
509 AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
510
511 /*
512 * Set the busy flag and do the job.
513 */
514 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
515
516 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
517 uint32_t i = pThis->cHandles;
518 while (i-- > 0)
519 if (pThis->aHandles[i].id == id)
520 {
521 if (pHandle)
522 {
523 pHandle->enmType = pThis->aHandles[i].enmType;
524 pHandle->u = pThis->aHandles[i].u;
525 }
526 rc = VINF_SUCCESS;
527 break;
528 }
529
530 ASMAtomicWriteBool(&pThis->fBusy, false);
531 return rc;
532}
533
534
535RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
536{
537 /*
538 * Validate the input.
539 */
540 RTPOLLSETINTERNAL *pThis = hPollSet;
541 AssertPtrReturn(pThis, UINT32_MAX);
542 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
543
544 /*
545 * Set the busy flag and do the job.
546 */
547 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
548 uint32_t cHandles = pThis->cHandles;
549 ASMAtomicWriteBool(&pThis->fBusy, false);
550
551 return cHandles;
552}
553
554RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
555{
556 /*
557 * Validate the input.
558 */
559 RTPOLLSETINTERNAL *pThis = hPollSet;
560 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
561 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
562 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
563 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
564 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
565
566 /*
567 * Set the busy flag and do the job.
568 */
569 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
570
571 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
572 uint32_t i = pThis->cHandles;
573 while (i-- > 0)
574 if (pThis->paHandles[i].id == id)
575 {
576 pThis->aHandles[i].fEvents = fEvents;
577 rc = VINF_SUCCESS;
578 break;
579 }
580
581 ASMAtomicWriteBool(&pThis->fBusy, false);
582 return rc;
583}
584
585
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