VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/poll.cpp@ 55998

Last change on this file since 55998 was 44487, checked in by vboxsync, 12 years ago

IPRT: Poll on OS/2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.7 KB
Line 
1/* $Id: poll.cpp 44487 2013-01-31 12:37:42Z vboxsync $ */
2/** @file
3 * IPRT - Polling I/O Handles, Windows+Posix Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2013 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/cdefs.h>
32#ifdef RT_OS_WINDOWS
33# include <Windows.h>
34
35#elif defined(RT_OS_OS2)
36# define INCL_BASE
37# include <os2.h>
38# include <limits.h>
39# include <sys/socket.h>
40
41#else
42# include <limits.h>
43# include <errno.h>
44# include <sys/poll.h>
45#endif
46
47#include <iprt/poll.h>
48#include "internal/iprt.h"
49
50#include <iprt/alloca.h>
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53#include <iprt/err.h>
54#include <iprt/mem.h>
55#include <iprt/pipe.h>
56#include <iprt/socket.h>
57#include <iprt/string.h>
58#include <iprt/thread.h>
59#include <iprt/time.h>
60
61#include "internal/pipe.h"
62#define IPRT_INTERNAL_SOCKET_POLLING_ONLY
63#include "internal/socket.h"
64#include "internal/magics.h"
65
66
67/*******************************************************************************
68* Defined Constants And Macros *
69*******************************************************************************/
70/** The maximum poll set size.
71 * @remarks To help portability, we set this to the Windows limit. We can lift
72 * this restriction later if it becomes necessary. */
73#define RTPOLL_SET_MAX 64
74
75
76
77/*******************************************************************************
78* Structures and Typedefs *
79*******************************************************************************/
80/**
81 * Handle entry in a poll set.
82 */
83typedef struct RTPOLLSETHNDENT
84{
85 /** The handle type. */
86 RTHANDLETYPE enmType;
87 /** The handle ID. */
88 uint32_t id;
89 /** The events we're waiting for here. */
90 uint32_t fEvents;
91 /** Set if this is the final entry for this handle.
92 * If the handle is entered more than once, this will be clear for all but
93 * the last entry. */
94 bool fFinalEntry;
95 /** The handle union. */
96 RTHANDLEUNION u;
97} RTPOLLSETHNDENT;
98/** Pointer to a handle entry. */
99typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT;
100
101
102/**
103 * Poll set data.
104 */
105typedef struct RTPOLLSETINTERNAL
106{
107 /** The magic value (RTPOLLSET_MAGIC). */
108 uint32_t u32Magic;
109 /** Set when someone is polling or making changes. */
110 bool volatile fBusy;
111
112 /** The number of allocated handles. */
113 uint16_t cHandlesAllocated;
114 /** The number of valid handles in the set. */
115 uint16_t cHandles;
116
117#ifdef RT_OS_WINDOWS
118 /** Pointer to an array of native handles. */
119 HANDLE *pahNative;
120#elif defined(RT_OS_OS2)
121 /** The semaphore records. */
122 PSEMRECORD paSemRecs;
123 /** The multiple wait semaphore used for non-socket waits. */
124 HMUX hmux;
125 /** os2_select template. */
126 int *pafdSelect;
127 /** The number of sockets to monitor for read. */
128 uint16_t cReadSockets;
129 /** The number of sockets to monitor for write. */
130 uint16_t cWriteSockets;
131 /** The number of sockets to monitor for exceptions. */
132 uint16_t cXcptSockets;
133 /** The number of pipes. */
134 uint16_t cPipes;
135 /** Pointer to an array of native handles. */
136 PRTHCINTPTR pahNative;
137#else
138 /** Pointer to an array of pollfd structures. */
139 struct pollfd *paPollFds;
140#endif
141 /** Pointer to an array of handles and IDs. */
142 PRTPOLLSETHNDENT paHandles;
143} RTPOLLSETINTERNAL;
144
145
146
147/**
148 * Common worker for RTPoll and RTPollNoResume
149 */
150static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, uint64_t MsStart, RTMSINTERVAL cMillies,
151 uint32_t *pfEvents, uint32_t *pid)
152{
153 int rc;
154
155 if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT))
156 return VERR_DEADLOCK;
157
158 /*
159 * Check for special case, RTThreadSleep...
160 */
161 uint32_t const cHandles = pThis->cHandles;
162 if (cHandles == 0)
163 {
164 rc = RTThreadSleep(cMillies);
165 if (RT_SUCCESS(rc))
166 rc = VERR_TIMEOUT;
167 return rc;
168 }
169
170#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
171 /*
172 * Check + prepare the handles before waiting.
173 */
174 uint32_t fEvents = 0;
175 bool const fNoWait = cMillies == 0;
176 uint32_t i;
177 for (i = 0; i < cHandles; i++)
178 {
179 switch (pThis->paHandles[i].enmType)
180 {
181 case RTHANDLETYPE_PIPE:
182 fEvents = rtPipePollStart(pThis->paHandles[i].u.hPipe, pThis, pThis->paHandles[i].fEvents,
183 pThis->paHandles[i].fFinalEntry, fNoWait);
184 break;
185
186 case RTHANDLETYPE_SOCKET:
187 fEvents = rtSocketPollStart(pThis->paHandles[i].u.hSocket, pThis, pThis->paHandles[i].fEvents,
188 pThis->paHandles[i].fFinalEntry, fNoWait);
189 break;
190
191 default:
192 AssertFailed();
193 fEvents = UINT32_MAX;
194 break;
195 }
196 if (fEvents)
197 break;
198 }
199 if ( fEvents
200 || fNoWait)
201 {
202
203 if (pid)
204 *pid = pThis->paHandles[i].id;
205 if (pfEvents)
206 *pfEvents = fEvents;
207 rc = !fEvents
208 ? VERR_TIMEOUT
209 : fEvents != UINT32_MAX
210 ? VINF_SUCCESS
211 : VERR_INTERNAL_ERROR_4;
212
213 /* clean up */
214 if (!fNoWait)
215 while (i-- > 0)
216 {
217 switch (pThis->paHandles[i].enmType)
218 {
219 case RTHANDLETYPE_PIPE:
220 rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents,
221 pThis->paHandles[i].fFinalEntry, false);
222 break;
223
224 case RTHANDLETYPE_SOCKET:
225 rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents,
226 pThis->paHandles[i].fFinalEntry, false);
227 break;
228
229 default:
230 AssertFailed();
231 break;
232 }
233 }
234
235 return rc;
236 }
237
238
239 /*
240 * Wait.
241 */
242# ifdef RT_OS_WINDOWS
243 DWORD dwRc = WaitForMultipleObjectsEx(cHandles, pThis->pahNative,
244 FALSE /*fWaitAll */,
245 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies,
246 TRUE /*fAlertable*/);
247 if ( dwRc >= WAIT_OBJECT_0
248 && dwRc < WAIT_OBJECT_0 + cHandles)
249 rc = VERR_INTERRUPTED;
250 else if (dwRc == WAIT_TIMEOUT)
251 rc = VERR_TIMEOUT;
252 else if (dwRc == WAIT_IO_COMPLETION)
253 rc = VERR_INTERRUPTED;
254 else if (dwRc == WAIT_FAILED)
255 rc = RTErrConvertFromWin32(GetLastError());
256 else
257 {
258 AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc));
259 rc = VERR_INTERNAL_ERROR_5;
260 }
261
262# else /* RT_OS_OS2 */
263 APIRET orc;
264 ULONG ulUser = 0;
265 uint16_t cSockets = pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets;
266 if (cSockets == 0)
267 {
268 /* Only pipes. */
269 AssertReturn(pThis->cPipes > 0, VERR_INTERNAL_ERROR_2);
270 orc = DosWaitMuxWaitSem(pThis->hmux,
271 cMillies == RT_INDEFINITE_WAIT ? SEM_INDEFINITE_WAIT : RT_MIN(cMillies, SEM_INDEFINITE_WAIT - 1),
272 &ulUser);
273 rc = RTErrConvertFromOS2(orc);
274 }
275 else
276 {
277 int *pafdSelect = (int *)alloca(cSockets + 1);
278 if (pThis->cPipes == 0)
279 {
280 /* Only sockets. */
281 memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1));
282 rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets,
283 cMillies == RT_INDEFINITE_WAIT ? -1 : (long)RT_MIN(cMillies, LONG_MAX));
284 if (rc > 0)
285 rc = VINF_SUCCESS;
286 else if (rc == 0)
287 rc = VERR_TIMEOUT;
288 else
289 rc = RTErrConvertFromErrno(sock_errno());
290 }
291 else
292 {
293 /* Mix of both - taking the easy way out, not optimal, but whatever... */
294 do
295 {
296 orc = DosWaitMuxWaitSem(pThis->hmux, 8, &ulUser);
297 if (orc != ERROR_TIMEOUT && orc != ERROR_SEM_TIMEOUT)
298 {
299 rc = RTErrConvertFromOS2(orc);
300 break;
301 }
302
303 memcpy(pafdSelect, pThis->pafdSelect, sizeof(pThis->pafdSelect[0]) * (cSockets + 1));
304 rc = os2_select(pafdSelect, pThis->cReadSockets, pThis->cWriteSockets, pThis->cXcptSockets, 8);
305 if (rc != 0)
306 {
307 if (rc > 0)
308 rc = VINF_SUCCESS;
309 else
310 rc = RTErrConvertFromErrno(sock_errno());
311 break;
312 }
313 } while (cMillies == RT_INDEFINITE_WAIT || RTTimeMilliTS() - MsStart < cMillies);
314 }
315 }
316# endif /* RT_OS_OS2 */
317
318 /*
319 * Get event (if pending) and do wait cleanup.
320 */
321 bool fHarvestEvents = true;
322 for (i = 0; i < cHandles; i++)
323 {
324 fEvents = 0;
325 switch (pThis->paHandles[i].enmType)
326 {
327 case RTHANDLETYPE_PIPE:
328 fEvents = rtPipePollDone(pThis->paHandles[i].u.hPipe, pThis->paHandles[i].fEvents,
329 pThis->paHandles[i].fFinalEntry, fHarvestEvents);
330 break;
331
332 case RTHANDLETYPE_SOCKET:
333 fEvents = rtSocketPollDone(pThis->paHandles[i].u.hSocket, pThis->paHandles[i].fEvents,
334 pThis->paHandles[i].fFinalEntry, fHarvestEvents);
335 break;
336
337 default:
338 AssertFailed();
339 break;
340 }
341 if ( fEvents
342 && fHarvestEvents)
343 {
344 Assert(fEvents != UINT32_MAX);
345 fHarvestEvents = false;
346 if (pfEvents)
347 *pfEvents = fEvents;
348 if (pid)
349 *pid = pThis->paHandles[i].id;
350 rc = VINF_SUCCESS;
351 }
352 }
353
354#else /* POSIX */
355
356 /* clear the revents. */
357 uint32_t i = pThis->cHandles;
358 while (i-- > 0)
359 pThis->paPollFds[i].revents = 0;
360
361 rc = poll(&pThis->paPollFds[0], pThis->cHandles,
362 cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX
363 ? -1
364 : (int)cMillies);
365 if (rc == 0)
366 return VERR_TIMEOUT;
367 if (rc < 0)
368 return RTErrConvertFromErrno(errno);
369 for (i = 0; i < pThis->cHandles; i++)
370 if (pThis->paPollFds[i].revents)
371 {
372 if (pfEvents)
373 {
374 *pfEvents = 0;
375 if (pThis->paPollFds[i].revents & (POLLIN
376# ifdef POLLRDNORM
377 | POLLRDNORM /* just in case */
378# endif
379# ifdef POLLRDBAND
380 | POLLRDBAND /* ditto */
381# endif
382# ifdef POLLPRI
383 | POLLPRI /* ditto */
384# endif
385# ifdef POLLMSG
386 | POLLMSG /* ditto */
387# endif
388# ifdef POLLWRITE
389 | POLLWRITE /* ditto */
390# endif
391# ifdef POLLEXTEND
392 | POLLEXTEND /* ditto */
393# endif
394 )
395 )
396 *pfEvents |= RTPOLL_EVT_READ;
397
398 if (pThis->paPollFds[i].revents & (POLLOUT
399# ifdef POLLWRNORM
400 | POLLWRNORM /* just in case */
401# endif
402# ifdef POLLWRBAND
403 | POLLWRBAND /* ditto */
404# endif
405 )
406 )
407 *pfEvents |= RTPOLL_EVT_WRITE;
408
409 if (pThis->paPollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL
410# ifdef POLLRDHUP
411 | POLLRDHUP
412# endif
413 )
414 )
415 *pfEvents |= RTPOLL_EVT_ERROR;
416 }
417 if (pid)
418 *pid = pThis->paHandles[i].id;
419 return VINF_SUCCESS;
420 }
421
422 AssertFailed();
423 RTThreadYield();
424 rc = VERR_INTERRUPTED;
425
426#endif /* POSIX */
427
428 return rc;
429}
430
431
432RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
433{
434 RTPOLLSETINTERNAL *pThis = hPollSet;
435 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
436 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
437 AssertPtrNull(pfEvents);
438 AssertPtrNull(pid);
439
440 /*
441 * Set the busy flag and do the job.
442 */
443 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
444
445 int rc;
446 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
447 {
448 do rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid);
449 while (rc == VERR_INTERRUPTED);
450 }
451 else
452 {
453 uint64_t MsStart = RTTimeMilliTS();
454 rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid);
455 while (RT_UNLIKELY(rc == VERR_INTERRUPTED))
456 {
457 if (RTTimeMilliTS() - MsStart >= cMillies)
458 {
459 rc = VERR_TIMEOUT;
460 break;
461 }
462 rc = rtPollNoResumeWorker(pThis, MsStart, cMillies, pfEvents, pid);
463 }
464 }
465
466 ASMAtomicWriteBool(&pThis->fBusy, false);
467
468 return rc;
469}
470
471
472RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid)
473{
474 RTPOLLSETINTERNAL *pThis = hPollSet;
475 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
476 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
477 AssertPtrNull(pfEvents);
478 AssertPtrNull(pid);
479
480 /*
481 * Set the busy flag and do the job.
482 */
483 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
484
485 int rc;
486 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0)
487 rc = rtPollNoResumeWorker(pThis, 0, cMillies, pfEvents, pid);
488 else
489 rc = rtPollNoResumeWorker(pThis, RTTimeMilliTS(), cMillies, pfEvents, pid);
490
491 ASMAtomicWriteBool(&pThis->fBusy, false);
492
493 return rc;
494}
495
496
497RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet)
498{
499 AssertPtrReturn(phPollSet, VERR_INVALID_POINTER);
500 RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAlloc(sizeof(RTPOLLSETINTERNAL));
501 if (!pThis)
502 return VERR_NO_MEMORY;
503
504 pThis->fBusy = false;
505 pThis->cHandles = 0;
506 pThis->cHandlesAllocated = 0;
507#ifdef RT_OS_WINDOWS
508 pThis->pahNative = NULL;
509#elif defined(RT_OS_OS2)
510 pThis->hmux = NULLHANDLE;
511 APIRET orc = DosCreateMuxWaitSem(NULL, &pThis->hmux, 0, NULL, DCMW_WAIT_ANY);
512 if (orc != NO_ERROR)
513 {
514 RTMemFree(pThis);
515 return RTErrConvertFromOS2(orc);
516 }
517 pThis->pafdSelect = NULL;
518 pThis->cReadSockets = 0;
519 pThis->cWriteSockets = 0;
520 pThis->cXcptSockets = 0;
521 pThis->cPipes = 0;
522 pThis->pahNative = NULL;
523#else
524 pThis->paPollFds = NULL;
525#endif
526 pThis->paHandles = NULL;
527 pThis->u32Magic = RTPOLLSET_MAGIC;
528
529 *phPollSet = pThis;
530 return VINF_SUCCESS;
531}
532
533
534RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet)
535{
536 RTPOLLSETINTERNAL *pThis = hPollSet;
537 if (pThis == NIL_RTPOLLSET)
538 return VINF_SUCCESS;
539 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
540 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
541 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
542
543 ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC);
544#ifdef RT_OS_WINDOWS
545 RTMemFree(pThis->pahNative);
546 pThis->pahNative = NULL;
547#elif defined(RT_OS_OS2)
548 DosCloseMuxWaitSem(pThis->hmux);
549 pThis->hmux = NULLHANDLE;
550 RTMemFree(pThis->pafdSelect);
551 pThis->pafdSelect = NULL;
552 RTMemFree(pThis->pahNative);
553 pThis->pahNative = NULL;
554#else
555 RTMemFree(pThis->paPollFds);
556 pThis->paPollFds = NULL;
557#endif
558 RTMemFree(pThis->paHandles);
559 pThis->paHandles = NULL;
560 RTMemFree(pThis);
561
562 return VINF_SUCCESS;
563}
564
565#ifdef RT_OS_OS2
566
567/**
568 * Checks if @a fd is in the specific socket subset.
569 *
570 * @returns true / false.
571 * @param pThis The poll set instance.
572 * @param iStart The index to start at.
573 * @param cFds The number of sockets to check.
574 * @param fd The socket to look for.
575 */
576static bool rtPollSetOs2IsSocketInSet(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t cFds, int fd)
577{
578 int const *pfd = pThis->pafdSelect + iStart;
579 while (cFds-- > 0)
580 {
581 if (*pfd == fd)
582 return true;
583 pfd++;
584 }
585 return false;
586}
587
588
589/**
590 * Removes a socket from a select template subset.
591 *
592 * @param pThis The poll set instance.
593 * @param iStart The index to start at.
594 * @param pcSubSet The subset counter to decrement.
595 * @param fd The socket to remove.
596 */
597static void rtPollSetOs2RemoveSocket(RTPOLLSETINTERNAL *pThis, uint16_t iStart, uint16_t *pcFds, int fd)
598{
599 uint16_t cFds = *pcFds;
600 while (cFds-- > 0)
601 {
602 if (pThis->pafdSelect[iStart] == fd)
603 break;
604 iStart++;
605 }
606 AssertReturnVoid(iStart != UINT16_MAX);
607
608 /* Note! We keep a -1 entry at the end of the set, thus the + 1. */
609 memmove(&pThis->pafdSelect[iStart],
610 &pThis->pafdSelect[iStart + 1],
611 pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - 1 - iStart);
612 *pcFds -= 1;
613
614 Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1);
615}
616
617
618/**
619 * Adds a socket to a select template subset.
620 *
621 * @param pThis The poll set instance.
622 * @param iInsert The insertion point.
623 * ASSUMED to be at the end of the subset.
624 * @param pcSubSet The subset counter to increment.
625 * @param fd The socket to add.
626 */
627static void rtPollSetOs2AddSocket(RTPOLLSETINTERNAL *pThis, uint16_t iInsert, uint16_t *pcFds, int fd)
628{
629 Assert(!rtPollSetOs2IsSocketInSet(pThis, iInsert - *pcFds, *pcFds, fd));
630
631 /* Note! We keep a -1 entry at the end of the set, thus the + 1. */
632 memmove(&pThis->pafdSelect[iInsert + 1],
633 &pThis->pafdSelect[iInsert],
634 pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets + 1 - iInsert);
635 pThis->pafdSelect[iInsert] = fd;
636 *pcFds += 1;
637
638 Assert(pThis->pafdSelect[pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets] == -1);
639}
640
641
642/**
643 * OS/2 specific RTPollSetAdd worker.
644 *
645 * @returns IPRT status code.
646 * @param pThis The poll set instance.
647 * @param i The index of the new handle (not committed).
648 * @param fEvents The events to poll for.
649 */
650static int rtPollSetOs2Add(RTPOLLSETINTERNAL *pThis, unsigned i, uint32_t fEvents)
651{
652 if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET)
653 {
654 int const fdSocket = pThis->pahNative[i];
655 if ( (fEvents & RTPOLL_EVT_READ)
656 && rtPollSetOs2IsSocketInSet(pThis, 0, pThis->cReadSockets, fdSocket))
657 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket);
658
659 if ( (fEvents & RTPOLL_EVT_WRITE)
660 && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets, pThis->cWriteSockets, fdSocket))
661 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cWriteSockets, fdSocket);
662
663 if ( (fEvents & RTPOLL_EVT_ERROR)
664 && rtPollSetOs2IsSocketInSet(pThis, pThis->cReadSockets + pThis->cWriteSockets, pThis->cXcptSockets, fdSocket))
665 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets,
666 &pThis->cXcptSockets, fdSocket);
667 }
668 else if (pThis->paHandles[i].enmType == RTHANDLETYPE_PIPE)
669 {
670 SEMRECORD Rec = { (HSEM)pThis->pahNative[i], pThis->paHandles[i].id };
671 APIRET orc = DosAddMuxWaitSem(pThis->hmux, &Rec);
672 if (orc != NO_ERROR && orc != ERROR_DUPLICATE_HANDLE)
673 return RTErrConvertFromOS2(orc);
674 pThis->cPipes++;
675 }
676 else
677 AssertFailedReturn(VERR_INTERNAL_ERROR_2);
678 return VINF_SUCCESS;
679}
680
681#endif /* RT_OS_OS2 */
682
683/**
684 * Grows the poll set.
685 *
686 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
687 * @param pThis The poll set instance.
688 * @param cHandlesNew The new poll set size.
689 */
690static int rtPollSetGrow(RTPOLLSETINTERNAL *pThis, uint32_t cHandlesNew)
691{
692 Assert(cHandlesNew > pThis->cHandlesAllocated);
693
694 /* The common array. */
695 void *pvNew = RTMemRealloc(pThis->paHandles, cHandlesNew * sizeof(pThis->paHandles[0]));
696 if (!pvNew)
697 return VERR_NO_MEMORY;
698 pThis->paHandles = (PRTPOLLSETHNDENT)pvNew;
699
700
701 /* OS specific handles */
702#if defined(RT_OS_WINDOWS)
703 pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0]));
704 if (!pvNew)
705 return VERR_NO_MEMORY;
706 pThis->pahNative = (HANDLE *)pvNew;
707
708#elif defined(RT_OS_OS2)
709 pvNew = RTMemRealloc(pThis->pahNative, cHandlesNew * sizeof(pThis->pahNative[0]));
710 if (!pvNew)
711 return VERR_NO_MEMORY;
712 pThis->pahNative = (PRTHCINTPTR)pvNew;
713
714 pvNew = RTMemRealloc(pThis->pafdSelect, (cHandlesNew * 3 + 1) * sizeof(pThis->pafdSelect[0]));
715 if (!pvNew)
716 return VERR_NO_MEMORY;
717 pThis->pafdSelect = (int *)pvNew;
718 if (pThis->cHandlesAllocated == 0)
719 pThis->pafdSelect[0] = -1;
720
721#else
722 pvNew = RTMemRealloc(pThis->paPollFds, cHandlesNew * sizeof(pThis->paPollFds[0]));
723 if (!pvNew)
724 return VERR_NO_MEMORY;
725 pThis->paPollFds = (struct pollfd *)pvNew;
726
727#endif
728
729 pThis->cHandlesAllocated = (uint16_t)cHandlesNew;
730 return VINF_SUCCESS;
731}
732
733
734RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id)
735{
736 /*
737 * Validate the input (tedious).
738 */
739 RTPOLLSETINTERNAL *pThis = hPollSet;
740 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
741 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
742 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
743 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
744 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
745
746 if (!pHandle)
747 return VINF_SUCCESS;
748 AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
749 AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER);
750
751 /*
752 * Set the busy flag and do the job.
753 */
754
755 int rc = VINF_SUCCESS;
756 RTHCINTPTR hNative = -1;
757 RTHANDLEUNION uh;
758 uh.uInt = 0;
759 switch (pHandle->enmType)
760 {
761 case RTHANDLETYPE_PIPE:
762 uh.hPipe = pHandle->u.hPipe;
763 if (uh.hPipe == NIL_RTPIPE)
764 return VINF_SUCCESS;
765 rc = rtPipePollGetHandle(uh.hPipe, fEvents, &hNative);
766 break;
767
768 case RTHANDLETYPE_SOCKET:
769 uh.hSocket = pHandle->u.hSocket;
770 if (uh.hSocket == NIL_RTSOCKET)
771 return VINF_SUCCESS;
772 rc = rtSocketPollGetHandle(uh.hSocket, fEvents, &hNative);
773 break;
774
775 case RTHANDLETYPE_FILE:
776 AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n"));
777 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
778 break;
779
780 case RTHANDLETYPE_THREAD:
781 AssertMsgFailed(("Thread handles are currently not pollable\n"));
782 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
783 break;
784
785 default:
786 AssertMsgFailed(("\n"));
787 rc = VERR_POLL_HANDLE_NOT_POLLABLE;
788 break;
789 }
790 if (RT_SUCCESS(rc))
791 {
792 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
793
794 uint32_t const i = pThis->cHandles;
795
796 /* Check that the handle ID doesn't exist already. */
797 uint32_t iPrev = UINT32_MAX;
798 uint32_t j = i;
799 while (j-- > 0)
800 {
801 if (pThis->paHandles[j].id == id)
802 {
803 rc = VERR_POLL_HANDLE_ID_EXISTS;
804 break;
805 }
806 if ( pThis->paHandles[j].enmType == pHandle->enmType
807 && pThis->paHandles[j].u.uInt == uh.uInt)
808 iPrev = j;
809 }
810
811 /* Check that we won't overflow the poll set now. */
812 if ( RT_SUCCESS(rc)
813 && i + 1 > RTPOLL_SET_MAX)
814 rc = VERR_POLL_SET_IS_FULL;
815
816 /* Grow the tables if necessary. */
817 if (RT_SUCCESS(rc) && i + 1 > pThis->cHandlesAllocated)
818 rc = rtPollSetGrow(pThis, pThis->cHandlesAllocated + 32);
819 if (RT_SUCCESS(rc))
820 {
821 /*
822 * Add the handles to the two parallel arrays.
823 */
824#ifdef RT_OS_WINDOWS
825 pThis->pahNative[i] = (HANDLE)hNative;
826#elif defined(RT_OS_OS2)
827 pThis->pahNative[i] = hNative;
828#else
829 pThis->paPollFds[i].fd = (int)hNative;
830 pThis->paPollFds[i].revents = 0;
831 pThis->paPollFds[i].events = 0;
832 if (fEvents & RTPOLL_EVT_READ)
833 pThis->paPollFds[i].events |= POLLIN;
834 if (fEvents & RTPOLL_EVT_WRITE)
835 pThis->paPollFds[i].events |= POLLOUT;
836 if (fEvents & RTPOLL_EVT_ERROR)
837 pThis->paPollFds[i].events |= POLLERR;
838#endif
839 pThis->paHandles[i].enmType = pHandle->enmType;
840 pThis->paHandles[i].u = uh;
841 pThis->paHandles[i].id = id;
842 pThis->paHandles[i].fEvents = fEvents;
843 pThis->paHandles[i].fFinalEntry = true;
844
845 if (iPrev != UINT32_MAX)
846 {
847 Assert(pThis->paHandles[i].fFinalEntry);
848 pThis->paHandles[i].fFinalEntry = false;
849 }
850
851 /*
852 * Validations and OS specific updates.
853 */
854#ifdef RT_OS_WINDOWS
855 /* none */
856#elif defined(RT_OS_OS2)
857 rc = rtPollSetOs2Add(pThis, i, fEvents);
858#else /* POSIX */
859 if (poll(&pThis->paPollFds[i], 1, 0) < 0)
860 {
861 rc = RTErrConvertFromErrno(errno);
862 pThis->paPollFds[i].fd = -1;
863 }
864#endif /* POSIX */
865
866 if (RT_SUCCESS(rc))
867 {
868 /*
869 * Commit it to the set.
870 */
871 pThis->cHandles++; Assert(pThis->cHandles == i + 1);
872 rc = VINF_SUCCESS;
873 }
874 }
875 }
876
877 ASMAtomicWriteBool(&pThis->fBusy, false);
878 return rc;
879}
880
881
882RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id)
883{
884 /*
885 * Validate the input.
886 */
887 RTPOLLSETINTERNAL *pThis = hPollSet;
888 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
889 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
890 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
891
892 /*
893 * Set the busy flag and do the job.
894 */
895 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
896
897 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
898 uint32_t i = pThis->cHandles;
899 while (i-- > 0)
900 if (pThis->paHandles[i].id == id)
901 {
902 /* Save some details for the duplicate searching. */
903 bool const fFinalEntry = pThis->paHandles[i].fFinalEntry;
904 RTHANDLETYPE const enmType = pThis->paHandles[i].enmType;
905 RTHANDLEUNION const uh = pThis->paHandles[i].u;
906#ifdef RT_OS_OS2
907 uint32_t fRemovedEvents = pThis->paHandles[i].fEvents;
908 RTHCINTPTR const hNative = pThis->pahNative[i];
909#endif
910
911 /* Remove the entry. */
912 pThis->cHandles--;
913 size_t const cToMove = pThis->cHandles - i;
914 if (cToMove)
915 {
916 memmove(&pThis->paHandles[i], &pThis->paHandles[i + 1], cToMove * sizeof(pThis->paHandles[i]));
917#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
918 memmove(&pThis->pahNative[i], &pThis->pahNative[i + 1], cToMove * sizeof(pThis->pahNative[i]));
919#else
920 memmove(&pThis->paPollFds[i], &pThis->paPollFds[i + 1], cToMove * sizeof(pThis->paPollFds[i]));
921#endif
922 }
923
924 /* Check for duplicate and set the fFinalEntry flag. */
925 if (fFinalEntry)
926 while (i-- > 0)
927 if ( pThis->paHandles[i].u.uInt == uh.uInt
928 && pThis->paHandles[i].enmType == enmType)
929 {
930 Assert(!pThis->paHandles[i].fFinalEntry);
931 pThis->paHandles[i].fFinalEntry = true;
932 break;
933 }
934
935#ifdef RT_OS_OS2
936 /*
937 * Update OS/2 wait structures.
938 */
939 uint32_t fNewEvents = 0;
940 i = pThis->cHandles;
941 while (i-- > 0)
942 if ( pThis->paHandles[i].u.uInt == uh.uInt
943 && pThis->paHandles[i].enmType == enmType)
944 fNewEvents |= pThis->paHandles[i].fEvents;
945 if (enmType == RTHANDLETYPE_PIPE)
946 {
947 pThis->cPipes--;
948 if (fNewEvents == 0)
949 {
950 APIRET orc = DosDeleteMuxWaitSem(pThis->hmux, (HSEM)hNative);
951 AssertMsg(orc == NO_ERROR, ("%d\n", orc));
952 }
953 }
954 else if ( fNewEvents != (fNewEvents | fRemovedEvents)
955 && enmType == RTHANDLETYPE_SOCKET)
956 {
957 fRemovedEvents = fNewEvents ^ (fNewEvents | fRemovedEvents);
958 if (fRemovedEvents & RTPOLL_EVT_ERROR)
959 rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets, (int)hNative);
960 if (fRemovedEvents & RTPOLL_EVT_WRITE)
961 rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, (int)hNative);
962 if (fRemovedEvents & RTPOLL_EVT_READ)
963 rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, (int)hNative);
964 }
965#endif /* RT_OS_OS2 */
966 rc = VINF_SUCCESS;
967 break;
968 }
969
970 ASMAtomicWriteBool(&pThis->fBusy, false);
971 return rc;
972}
973
974
975RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle)
976{
977 /*
978 * Validate the input.
979 */
980 RTPOLLSETINTERNAL *pThis = hPollSet;
981 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
982 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
983 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
984 AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER);
985
986 /*
987 * Set the busy flag and do the job.
988 */
989 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
990
991 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
992 uint32_t i = pThis->cHandles;
993 while (i-- > 0)
994 if (pThis->paHandles[i].id == id)
995 {
996 if (pHandle)
997 {
998 pHandle->enmType = pThis->paHandles[i].enmType;
999 pHandle->u = pThis->paHandles[i].u;
1000 }
1001 rc = VINF_SUCCESS;
1002 break;
1003 }
1004
1005 ASMAtomicWriteBool(&pThis->fBusy, false);
1006 return rc;
1007}
1008
1009
1010RTDECL(uint32_t) RTPollSetGetCount(RTPOLLSET hPollSet)
1011{
1012 /*
1013 * Validate the input.
1014 */
1015 RTPOLLSETINTERNAL *pThis = hPollSet;
1016 AssertPtrReturn(pThis, UINT32_MAX);
1017 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX);
1018
1019 /*
1020 * Set the busy flag and do the job.
1021 */
1022 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX);
1023 uint32_t cHandles = pThis->cHandles;
1024 ASMAtomicWriteBool(&pThis->fBusy, false);
1025
1026 return cHandles;
1027}
1028
1029RTDECL(int) RTPollSetEventsChange(RTPOLLSET hPollSet, uint32_t id, uint32_t fEvents)
1030{
1031 /*
1032 * Validate the input.
1033 */
1034 RTPOLLSETINTERNAL *pThis = hPollSet;
1035 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1036 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE);
1037 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER);
1038 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
1039 AssertReturn(fEvents, VERR_INVALID_PARAMETER);
1040
1041 /*
1042 * Set the busy flag and do the job.
1043 */
1044 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_CONCURRENT_ACCESS);
1045
1046 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND;
1047 uint32_t i = pThis->cHandles;
1048 while (i-- > 0)
1049 if (pThis->paHandles[i].id == id)
1050 {
1051 if (pThis->paHandles[i].fEvents != fEvents)
1052 {
1053#if defined(RT_OS_WINDOWS)
1054 /*nothing*/
1055#elif defined(RT_OS_OS2)
1056 if (pThis->paHandles[i].enmType == RTHANDLETYPE_SOCKET)
1057 {
1058 uint32_t fOldEvents = 0;
1059 uint32_t j = pThis->cHandles;
1060 while (j-- > 0)
1061 if ( pThis->paHandles[j].enmType == RTHANDLETYPE_SOCKET
1062 && pThis->paHandles[j].u.uInt == pThis->paHandles[i].u.uInt
1063 && j != i)
1064 fOldEvents |= pThis->paHandles[j].fEvents;
1065 uint32_t fNewEvents = fOldEvents | fEvents;
1066 fOldEvents |= pThis->paHandles[i].fEvents;
1067 if (fOldEvents != fEvents)
1068 {
1069 int const fdSocket = pThis->pahNative[i];
1070 uint32_t const fChangedEvents = fOldEvents ^ fNewEvents;
1071
1072 if ((fChangedEvents & RTPOLL_EVT_READ) && (fNewEvents & RTPOLL_EVT_READ))
1073 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets, &pThis->cReadSockets, fdSocket);
1074 else if (fChangedEvents & RTPOLL_EVT_READ)
1075 rtPollSetOs2RemoveSocket(pThis, 0, &pThis->cReadSockets, fdSocket);
1076
1077 if ((fChangedEvents & RTPOLL_EVT_WRITE) && (fNewEvents & RTPOLL_EVT_WRITE))
1078 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets,
1079 &pThis->cWriteSockets, fdSocket);
1080 else if (fChangedEvents & RTPOLL_EVT_WRITE)
1081 rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets, &pThis->cWriteSockets, fdSocket);
1082
1083 if ((fChangedEvents & RTPOLL_EVT_ERROR) && (fNewEvents & RTPOLL_EVT_ERROR))
1084 rtPollSetOs2AddSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets + pThis->cXcptSockets,
1085 &pThis->cXcptSockets, fdSocket);
1086 else if (fChangedEvents & RTPOLL_EVT_ERROR)
1087 rtPollSetOs2RemoveSocket(pThis, pThis->cReadSockets + pThis->cWriteSockets, &pThis->cXcptSockets,
1088 fdSocket);
1089 }
1090 }
1091#else
1092 pThis->paPollFds[i].events = 0;
1093 if (fEvents & RTPOLL_EVT_READ)
1094 pThis->paPollFds[i].events |= POLLIN;
1095 if (fEvents & RTPOLL_EVT_WRITE)
1096 pThis->paPollFds[i].events |= POLLOUT;
1097 if (fEvents & RTPOLL_EVT_ERROR)
1098 pThis->paPollFds[i].events |= POLLERR;
1099#endif
1100 pThis->paHandles[i].fEvents = fEvents;
1101 }
1102 rc = VINF_SUCCESS;
1103 break;
1104 }
1105
1106 ASMAtomicWriteBool(&pThis->fBusy, false);
1107 return rc;
1108}
1109
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