VirtualBox

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

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

poll-posix.cpp: initial untested code.

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