VirtualBox

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

Last change on this file since 92258 was 83544, checked in by vboxsync, 5 years ago

IPRT/poll.cpp: Rearranged code for better mojo when there are no handles in the set.

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