VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use