VirtualBox

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

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

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use