VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/poll-posix.cpp@ 27509

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

iprt: Poll on sockets on windows (untested). RTPollSetCount -> RTPollSetGetCount.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/* $Id: poll-posix.cpp 27509 2010-03-18 23:47:16Z vboxsync $ */
2/** @file
3 * IPRT - Polling I/O Handles, POSIX Implementation.
4 */
5
6/*
7 * Copyright (C) 2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
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/socket.h>
44#include <iprt/string.h>
45#include <iprt/thread.h>
46#include <iprt/time.h>
47#include "internal/magics.h"
48
49#include <limits.h>
50#include <errno.h>
51#include <sys/poll.h>
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Handle entry in a poll set.
59 */
60typedef struct RTPOLLSETHNDENT
61{
62 /** The handle type. */
63 RTHANDLETYPE enmType;
64 /** The handle ID. */
65 uint32_t id;
66 /** The handle union. */
67 RTHANDLEUNION u;
68} RTPOLLSETHNDENT;
69/** Pointer to a handle entry. */
70typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
71
72/**
73 * Poll set data, POSIX.
74 */
75typedef struct RTPOLLSETINTERNAL
76{
77 /** The magic value (RTPOLLSET_MAGIC). */
78 uint32_t u32Magic;
79 /** Set when someone is polling or making changes. */
80 bool volatile fBusy;
81
82 /** The number of valid handles in the set. */
83 uint32_t cHandles;
84 /** The number of allocated handles. */
85 uint32_t cHandlesAllocated;
86
87 /** Pointer to an array of pollfd structures. */
88 struct pollfd *paPollFds;
89 /** Pointer to an array of handles and IDs. */
90 PRTPOLLSETHNDENT paHandles;
91} RTPOLLSETINTERNAL;
92
93
94/**
95 * Common worker for RTPoll and RTPollNoResume
96 */
97static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
98{
99 if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
100 return VERR_DEADLOCK;
101
102 /* clear the revents. */
103 uint32_t i = pThis->cHandles;
104 while (i-- > 0)
105 pThis->paPollFds[i].revents = 0;
106
107 int rc = poll(&pThis->paPollFds[0], pThis->cHandles,
108 cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX
109 ? -1
110 : (int)cMillies);
111 if (rc == 0)
112 return VERR_TIMEOUT;
113 if (rc < 0)
114 return RTErrConvertFromErrno(errno);
115
116 for (i = 0; i < pThis->cHandles; i++)
117 if (pThis->paPollFds[i].revents)
118 {
119 if (pfEvents)
120 {
121 *pfEvents = 0;
122 if (pThis->paPollFds[i].revents & (POLLIN
123#ifdef POLLRDNORM
124 | POLLRDNORM /* just in case */
125#endif
126#ifdef POLLRDBAND
127 | POLLRDBAND /* ditto */
128#endif
129#ifdef POLLPRI
130 | POLLPRI /* ditto */
131#endif
132#ifdef POLLMSG
133 | POLLMSG /* ditto */
134#endif
135#ifdef POLLWRITE
136 | POLLWRITE /* ditto */
137#endif
138#ifdef POLLEXTEND
139 | POLLEXTEND /* ditto */
140#endif
141 )
142 )
143 *pfEvents |= RTPOLL_EVT_READ;
144
145 if (pThis->paPollFds[i].revents & (POLLOUT
146#ifdef POLLWRNORM
147 | POLLWRNORM /* just in case */
148#endif
149#ifdef POLLWRBAND
150 | POLLWRBAND /* ditto */
151#endif
152 )
153 )
154 *pfEvents |= RTPOLL_EVT_WRITE;
155
156 if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL
157#ifdef POLLRDHUP
158 | POLLRDHUP
159#endif
160 )
161 )
162 *pfEvents |= RTPOLL_EVT_ERROR;
163 }
164 if (pid)
165 *pid = pThis->paHandles[i].id;
166 return VINF_SUCCESS;
167 }
168
169 AssertFailed();
170 RTThreadYield();
171 return VERR_INTERRUPTED;
172}
173
174
175RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
176{
177 RTPOLLSETINTERNAL *pThis = hPollSet;
178 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
179 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
180 AssertPtrNull(pfEvents);
181 AssertPtrNull(pid);
182
183 /*
184 * Set the busy flag and do the job.
185 */
186 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
187
188 int rc;
189 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
190 {
191 do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
192 while (rc == VERR_INTERRUPTED);
193 }
194 else
195 {
196 uint64_t MsStart = RTTimeMilliTS();
197 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
198 while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
199 {
200 if (RTTimeMilliTS() - MsStart >= cMillies)
201 {
202 rc = VERR_TIMEOUT;
203 break;
204 }
205 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
206 }
207 }
208
209 ASMAtomicWriteBool(&pThis->fBusy, false);
210
211 return rc;
212}
213
214
215RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
216{
217 RTPOLLSETINTERNAL *pThis = hPollSet;
218 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
219 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
220 AssertPtrNull(pfEvents);
221 AssertPtrNull(pid);
222
223 /*
224 * Set the busy flag and do the job.
225 */
226 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
227
228 int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid);
229
230 ASMAtomicWriteBool(&pThis->fBusy, false);
231
232 return rc;
233}
234
235
236RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
237{
238 AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
239 RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL));
240 if (!pThis)
241 return VERR_NO_MEMORY;
242
243 pThis->u32Magic = RTPOLLSET_MAGIC;
244 pThis->fBusy = false;
245 pThis->cHandles = 0;
246 pThis->cHandlesAllocated = 0;
247 pThis->paPollFds = NULL;
248 pThis->paHandles = NULL;
249
250 *phPollSet = pThis;
251 return VINF_SUCCESS;
252}
253
254
255RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
256{
257 RTPOLLSETINTERNAL *pThis = hPollSet;
258 if (pThis == NIL_RTPOLLSET)
259 return VINF_SUCCESS;
260 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
261 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
262 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
263
264 ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
265 RTMemFree(pThis->paPollFds);
266 pThis->paPollFds = NULL;
267 RTMemFree(pThis->paHandles);
268 pThis->paHandles = NULL;
269 RTMemFree(pThis);
270
271 return VINF_SUCCESS;
272}
273
274
275RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
276{
277 /*
278 * Validate the input (tedious).
279 */
280 RTPOLLSETINTERNAL *pThis = hPollSet;
281 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
282 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
283 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
284 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
285 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
286
287 if (!pHandle)
288 return VINF_SUCCESS;
289 AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
290 AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
291
292 /*
293 * Set the busy flag and do the job.
294 */
295 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
296
297 int rc = VINF_SUCCESS;
298 int fd = -1;
299 switch (pHandle->enmType)
300 {
301 case RTHANDLETYPE_PIPE:
302 if (pHandle->u.hPipe != NIL_RTPIPE)
303 fd = (int)RTPipeToNative(pHandle->u.hPipe);
304 break;
305
306 case RTHANDLETYPE_SOCKET:
307 if (pHandle->u.hSocket != NIL_RTSOCKET)
308 fd = (int)RTSocketToNative(pHandle->u.hSocket);
309 break;
310
311 case RTHANDLETYPE_FILE:
312 AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
313 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
314 break;
315
316 case RTHANDLETYPE_THREAD:
317 AssertMsgFailed(("Thread handles are currently not pollable\n"));
318 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
319 break;
320
321 default:
322 AssertMsgFailed(("\n"));
323 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
324 break;
325 }
326 if (fd != -1)
327 {
328 uint32_t const i = pThis->cHandles;
329
330 /* Check that the handle ID doesn't exist already. */
331 uint32_t j = i;
332 while (j-- > 0)
333 if (pThis->paHandles[j].id == id)
334 {
335 rc = VERR_POLL_HANDLE_ID_EXISTS;
336 break;
337 }
338 if (RT_SUCCESS(rc))
339 {
340 /* Grow the tables if necessary. */
341 if (i + 1 > pThis->cHandlesAllocated)
342 {
343 uint32_t const c = pThis->cHandlesAllocated + 32;
344 void *pvNew;
345 pvNew = RTMemRealloc(pThis->paHandles, c * sizeof(pThis->paHandles[0]));
346 if (pvNew)
347 {
348 pThis->paHandles = (PRTPOLLSETHNDENT)pvNew;
349 pvNew = RTMemRealloc(pThis->paPollFds, c * sizeof(pThis->paPollFds[0]));
350 if (pvNew)
351 pThis->paPollFds = (struct pollfd *)pvNew;
352 else
353 rc = VERR_NO_MEMORY;
354 }
355 else
356 rc = VERR_NO_MEMORY;
357 }
358 if (RT_SUCCESS(rc))
359 {
360 /* Add it to the poll file descriptor array and call poll to
361 validate the event flags. */
362 pThis->paPollFds[i].fd = fd;
363 pThis->paPollFds[i].revents = 0;
364 pThis->paPollFds[i].events = 0;
365 if (fEvents & RTPOLL_EVT_READ)
366 pThis->paPollFds[i].events |= POLLIN;
367 if (fEvents & RTPOLL_EVT_WRITE)
368 pThis->paPollFds[i].events |= POLLOUT;
369 if (fEvents & RTPOLL_EVT_ERROR)
370 pThis->paPollFds[i].events |= POLLERR;
371
372 if (poll(&pThis->paPollFds[i], 1, 0) >= 0)
373 {
374 /* Add the handle info and close the transaction. */
375 pThis->paHandles[i].enmType = pHandle->enmType;
376 pThis->paHandles[i].u = pHandle->u;
377 pThis->paHandles[i].id = id;
378
379 pThis->cHandles = i + 1;
380 rc = VINF_SUCCESS;
381 }
382 else
383 {
384 rc = RTErrConvertFromErrno(errno);
385 pThis->paPollFds[i].fd = -1;
386 }
387 }
388 }
389 }
390
391 ASMAtomicWriteBool(&pThis->fBusy, false);
392 return rc;
393}
394
395
396RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
397{
398 /*
399 * Validate the input.
400 */
401 RTPOLLSETINTERNAL *pThis = hPollSet;
402 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
403 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
404 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
405
406 /*
407 * Set the busy flag and do the job.
408 */
409 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
410
411 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
412 uint32_t i = pThis->cHandles;
413 while (i-- > 0)
414 if (pThis->paHandles[i].id == id)
415 {
416 pThis->cHandles--;
417 size_t const cToMove = pThis->cHandles - i;
418 if (cToMove)
419 {
420 memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i]));
421 memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i]));
422 }
423 rc = VINF_SUCCESS;
424 break;
425 }
426
427 ASMAtomicWriteBool(&pThis->fBusy, false);
428 return rc;
429}
430
431
432RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
433{
434 /*
435 * Validate the input.
436 */
437 RTPOLLSETINTERNAL *pThis = hPollSet;
438 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
439 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
440 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
441 AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
442
443 /*
444 * Set the busy flag and do the job.
445 */
446 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
447
448 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
449 uint32_t i = pThis->cHandles;
450 while (i-- > 0)
451 if (pThis->paHandles[i].id == id)
452 {
453 if (pHandle)
454 {
455 pHandle->enmType = pThis->paHandles[i].enmType;
456 pHandle->u = pThis->paHandles[i].u;
457 }
458 rc = VINF_SUCCESS;
459 break;
460 }
461
462 ASMAtomicWriteBool(&pThis->fBusy, false);
463 return rc;
464}
465
466
467RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
468{
469 /*
470 * Validate the input.
471 */
472 RTPOLLSETINTERNAL *pThis = hPollSet;
473 AssertPtrReturn(pThis, UINT32_MAX);
474 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
475
476 /*
477 * Set the busy flag and do the job.
478 */
479 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
480 uint32_t cHandles = pThis->cHandles;
481 ASMAtomicWriteBool(&pThis->fBusy, false);
482
483 return cHandles;
484}
485
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