VirtualBox

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

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