VirtualBox

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

Last change on this file since 27653 was 27510, checked in by vboxsync, 15 years ago

poll-win.cpp,socket.cpp: Tested socket polling for windows.

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