VirtualBox

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

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

RTPollSetCount.

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