proxy_pollmgr.c revision 5e1b2462d27a7b23080cfdbfc9756ce8aca2a12e
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync/* -*- indent-tabs-mode: nil; -*- */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync nfds_t capacity; /* allocated size of the arrays */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync /* channels (socketpair) for static slots */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsyncstatic void pollmgr_loop(void);
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsyncstatic void pollmgr_add_at(int, struct pollmgr_handler *, SOCKET, int);
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsyncstatic void pollmgr_refptr_delete(struct pollmgr_refptr *);
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync * We cannot portably peek at the length of the incoming datagram and
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync * pre-allocate pbuf chain to recvmsg() directly to it. On Linux it's
81587231c9c584851518872e197f6f02dffe68cavboxsync * possible to recv with MSG_PEEK|MSG_TRUC, but extra syscall is
81587231c9c584851518872e197f6f02dffe68cavboxsync * probably more expensive (haven't measured) than doing an extra copy
81587231c9c584851518872e197f6f02dffe68cavboxsync * of data, since typical UDP datagrams are small enough to avoid
81587231c9c584851518872e197f6f02dffe68cavboxsync * fragmentation.
81587231c9c584851518872e197f6f02dffe68cavboxsync * We can use shared buffer here since we read from sockets
7be2140da7230ed5736528554a4dc34b2ac482acvboxsync * sequentially in a loop over pollfd.
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync status = socketpair(PF_LOCAL, SOCK_DGRAM, 0, pollmgr.chan[i]);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync status = RTWinSocketPair(PF_INET, SOCK_DGRAM, 0, pollmgr.chan[i]);
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync * Must be called before pollmgr loop is started, so no locking.
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncpollmgr_add_chan(int slot, struct pollmgr_handler *handler)
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr_add_at(slot, handler, pollmgr.chan[slot][POLLMGR_CHFD_RD], POLLIN);
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync * Must be called from pollmgr loop (via callbacks), so no locking.
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncpollmgr_add(struct pollmgr_handler *handler, SOCKET fd, int events)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync realloc(pollmgr.fds, newcap * sizeof(*pollmgr.fds));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds = newfds; /* don't crash/leak if realloc(handlers) fails */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* but don't update capacity yet! */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync realloc(pollmgr.handlers, newcap * sizeof(*pollmgr.handlers));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* if we failed to realloc here, then fds points to the
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * new array, but we pretend we still has old capacity */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncpollmgr_add_at(int slot, struct pollmgr_handler *handler, SOCKET fd, int events)
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsyncpollmgr_chan_send(int slot, void *buf, size_t nbytes)
81587231c9c584851518872e197f6f02dffe68cavboxsync warnx("send on chan %d: datagram truncated to %u bytes",
81587231c9c584851518872e197f6f02dffe68cavboxsync * Receive a pointer sent over poll manager channel.
81587231c9c584851518872e197f6f02dffe68cavboxsyncpollmgr_chan_recv_ptr(struct pollmgr_handler *handler, SOCKET fd, int revents)
81587231c9c584851518872e197f6f02dffe68cavboxsync errx(EXIT_FAILURE, "chan %d: fd invalid", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync errx(EXIT_FAILURE, "chan %d: fd error", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync err(EXIT_FAILURE, "chan %d: recv", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync pollmgr.fds[slot].fd = INVALID_SOCKET; /* see poll loop */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync int rc = RTWinPoll(pollmgr.fds, pollmgr.nfds,RT_INDEFINITE_WAIT, &nready);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* NOTREACHED*/
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* NOTREACHED*/
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else if (nready == 0) { /* cannot happen, we wait forever (-1) */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync continue; /* - but be defensive */
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync for (i = 0; (nfds_t)i < pollmgr.nfds && nready > 0; ++i) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * Channel handlers can request deletion of dynamic slots
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * by calling pollmgr_del_slot() that clobbers slot's fd.
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (fd == INVALID_SOCKET && i >= POLLMGR_SLOT_FIRST_DYNAMIC) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* adjust count if events were pending for that slot */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* pretend that slot handler requested deletion */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync continue; /* next fd */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (handler != NULL && handler->callback != NULL) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync#endif /* DEBUG */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nevents = (*handler->callback)(handler, fd, revents);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF0(("%s: invalid handler for fd %d: ", __func__, fd));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF0(("%p (callback = NULL)\n", (void *)handler));
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync /* Don't garbage-collect channels. */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync /* schedule for deletion (see g/c loop for details) */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync *pdelprev = i; /* make previous entry point to us */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[i].fd = INVALID_SOCKET; /* end of list (for now) */
81587231c9c584851518872e197f6f02dffe68cavboxsync } /* processing loop */
81587231c9c584851518872e197f6f02dffe68cavboxsync * Garbage collect and compact the array.
81587231c9c584851518872e197f6f02dffe68cavboxsync * We overload pollfd::fd of garbage entries to store the
81587231c9c584851518872e197f6f02dffe68cavboxsync * index of the next garbage entry. The garbage list is
81587231c9c584851518872e197f6f02dffe68cavboxsync * co-directional with the fds array. The index of the first
81587231c9c584851518872e197f6f02dffe68cavboxsync * entry is in "delfirst", the last entry "points to"
81587231c9c584851518872e197f6f02dffe68cavboxsync * INVALID_SOCKET.
81587231c9c584851518872e197f6f02dffe68cavboxsync * See update_events code for nevents < 0 at the end of the
81587231c9c584851518872e197f6f02dffe68cavboxsync * processing loop above.
81587231c9c584851518872e197f6f02dffe68cavboxsync * We want a live entry in the last slot to swap into the
81587231c9c584851518872e197f6f02dffe68cavboxsync * freed slot, so make sure we have one.
81587231c9c584851518872e197f6f02dffe68cavboxsync if (pollmgr.fds[last].events == POLLMGR_GARBAGE /* garbage */
7be2140da7230ed5736528554a4dc34b2ac482acvboxsync || pollmgr.fds[last].fd == INVALID_SOCKET) /* or killed */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync /* drop garbage entry at the end of the array */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* congruent to delnext >= pollmgr.nfds test below */
81587231c9c584851518872e197f6f02dffe68cavboxsync /* copy live entry at the end to the first slot being freed */
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync pollmgr.fds[delfirst] = pollmgr.fds[last]; /* struct copy */
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync pollmgr.handlers[delfirst] = pollmgr.handlers[last];
struct pollmgr_refptr *
return NULL;
return rp;
struct pollmgr_handler *
if (weak == 0) {
return NULL;
return NULL;
return handler;
if (weak == 0) {