proxy_pollmgr.c revision 5e1b2462d27a7b23080cfdbfc9756ce8aca2a12e
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync/* -*- indent-tabs-mode: nil; -*- */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#include "winutils.h"
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#include "proxy_pollmgr.h"
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#include "proxy.h"
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#ifndef RT_OS_WINDOWS
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#include <sys/socket.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <netinet/in.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <err.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <errno.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <poll.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <stdio.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <stdlib.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <string.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <time.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <unistd.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#else
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <iprt/err.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <stdlib.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include <string.h>
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#include "winpoll.h"
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync#endif
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#define POLLMGR_GARBAGE (-1)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsyncstruct pollmgr {
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync struct pollfd *fds;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync struct pollmgr_handler **handlers;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync nfds_t capacity; /* allocated size of the arrays */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync nfds_t nfds; /* part of the arrays in use */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync /* channels (socketpair) for static slots */
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync SOCKET chan[POLLMGR_SLOT_STATIC_COUNT][2];
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#define POLLMGR_CHFD_RD 0 /* - pollmgr side */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#define POLLMGR_CHFD_WR 1 /* - client side */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync} pollmgr;
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsyncstatic void pollmgr_loop(void);
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsyncstatic void pollmgr_add_at(int, struct pollmgr_handler *, SOCKET, int);
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsyncstatic void pollmgr_refptr_delete(struct pollmgr_refptr *);
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync/*
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 *
81587231c9c584851518872e197f6f02dffe68cavboxsync * We can use shared buffer here since we read from sockets
7be2140da7230ed5736528554a4dc34b2ac482acvboxsync * sequentially in a loop over pollfd.
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncu8_t pollmgr_udpbuf[64 * 1024];
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncint
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncpollmgr_init(void)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync{
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync struct pollfd *newfds;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync struct pollmgr_handler **newhdls;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nfds_t newcap;
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync int status;
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync nfds_t i;
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync pollmgr.fds = NULL;
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync pollmgr.handlers = NULL;
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync pollmgr.capacity = 0;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync pollmgr.nfds = 0;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.chan[i][POLLMGR_CHFD_RD] = -1;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync pollmgr.chan[i][POLLMGR_CHFD_WR] = -1;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync#ifndef RT_OS_WINDOWS
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync status = socketpair(PF_LOCAL, SOCK_DGRAM, 0, pollmgr.chan[i]);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync if (status < 0) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync perror("socketpair");
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync goto cleanup_close;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync#else
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync status = RTWinSocketPair(PF_INET, SOCK_DGRAM, 0, pollmgr.chan[i]);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync AssertRCReturn(status, -1);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync if (RT_FAILURE(status)) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync perror("socketpair");
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync goto cleanup_close;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync#endif
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync newcap = 16; /* XXX: magic */
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync LWIP_ASSERT1(newcap >= POLLMGR_SLOT_STATIC_COUNT);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync newfds = (struct pollfd *)
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync malloc(newcap * sizeof(*pollmgr.fds));
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync if (newfds == NULL) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync perror("calloc");
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync goto cleanup_close;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync newhdls = (struct pollmgr_handler **)
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync malloc(newcap * sizeof(*pollmgr.handlers));
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync if (newhdls == NULL) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync perror("malloc");
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync free(newfds);
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync goto cleanup_close;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.capacity = newcap;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds = newfds;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.handlers = newhdls;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.nfds = POLLMGR_SLOT_STATIC_COUNT;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync for (i = 0; i < pollmgr.capacity; ++i) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].fd = INVALID_SOCKET;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].events = 0;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].revents = 0;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync return 0;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync cleanup_close:
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync SOCKET *chan = pollmgr.chan[i];
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync if (chan[POLLMGR_CHFD_RD] >= 0) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync closesocket(chan[POLLMGR_CHFD_RD]);
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync closesocket(chan[POLLMGR_CHFD_WR]);
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync return -1;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync}
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync/*
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync * Must be called before pollmgr loop is started, so no locking.
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncSOCKET
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncpollmgr_add_chan(int slot, struct pollmgr_handler *handler)
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync{
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync if (slot >= POLLMGR_SLOT_FIRST_DYNAMIC) {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync handler->slot = -1;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync return -1;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr_add_at(slot, handler, pollmgr.chan[slot][POLLMGR_CHFD_RD], POLLIN);
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync return pollmgr.chan[slot][POLLMGR_CHFD_WR];
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync}
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync/*
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync * Must be called from pollmgr loop (via callbacks), so no locking.
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncint
b6097213cd07c5383c49168bfb61f915dbd4587avboxsyncpollmgr_add(struct pollmgr_handler *handler, SOCKET fd, int events)
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync{
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync int slot;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync DPRINTF2(("%s: new fd %d\n", __func__, fd));
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync if (pollmgr.nfds == pollmgr.capacity) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync struct pollfd *newfds;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync struct pollmgr_handler **newhdls;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nfds_t newcap;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nfds_t i;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newcap = pollmgr.capacity * 2;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newfds = (struct pollfd *)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync realloc(pollmgr.fds, newcap * sizeof(*pollmgr.fds));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (newfds == NULL) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync perror("realloc");
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync handler->slot = -1;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync return -1;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds = newfds; /* don't crash/leak if realloc(handlers) fails */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* but don't update capacity yet! */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newhdls = (struct pollmgr_handler **)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync realloc(pollmgr.handlers, newcap * sizeof(*pollmgr.handlers));
e0b01f0907f9ade6df65e65e86196fa09a11a245vboxsync if (newhdls == NULL) {
e0b01f0907f9ade6df65e65e86196fa09a11a245vboxsync perror("realloc");
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* if we failed to realloc here, then fds points to the
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * new array, but we pretend we still has old capacity */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync handler->slot = -1;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync return -1;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.handlers = newhdls;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.capacity = newcap;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync for (i = pollmgr.nfds; i < newcap; ++i) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newfds[i].fd = INVALID_SOCKET;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newfds[i].events = 0;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newfds[i].revents = 0;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync newhdls[i] = NULL;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync slot = pollmgr.nfds;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync ++pollmgr.nfds;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr_add_at(slot, handler, fd, events);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync return slot;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync}
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncstatic void
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncpollmgr_add_at(int slot, struct pollmgr_handler *handler, SOCKET fd, int events)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync{
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[slot].fd = fd;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[slot].events = events;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[slot].revents = 0;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.handlers[slot] = handler;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync handler->slot = slot;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync}
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncssize_t
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsyncpollmgr_chan_send(int slot, void *buf, size_t nbytes)
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync{
7be2140da7230ed5736528554a4dc34b2ac482acvboxsync SOCKET fd;
81587231c9c584851518872e197f6f02dffe68cavboxsync ssize_t nsent;
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync if (slot >= POLLMGR_SLOT_FIRST_DYNAMIC) {
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync return -1;
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync }
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync fd = pollmgr.chan[slot][POLLMGR_CHFD_WR];
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync nsent = send(fd, buf, (int)nbytes, 0);
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync if (nsent == SOCKET_ERROR) {
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync warn("send on chan %d", slot);
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync return -1;
9735c8af814f4e79e0c2e4b63b2a61a30faa67bfvboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync else if ((size_t)nsent != nbytes) {
81587231c9c584851518872e197f6f02dffe68cavboxsync warnx("send on chan %d: datagram truncated to %u bytes",
81587231c9c584851518872e197f6f02dffe68cavboxsync slot, (unsigned int)nsent);
81587231c9c584851518872e197f6f02dffe68cavboxsync return -1;
81587231c9c584851518872e197f6f02dffe68cavboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync return nsent;
81587231c9c584851518872e197f6f02dffe68cavboxsync}
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync/**
81587231c9c584851518872e197f6f02dffe68cavboxsync * Receive a pointer sent over poll manager channel.
81587231c9c584851518872e197f6f02dffe68cavboxsync */
81587231c9c584851518872e197f6f02dffe68cavboxsyncvoid *
81587231c9c584851518872e197f6f02dffe68cavboxsyncpollmgr_chan_recv_ptr(struct pollmgr_handler *handler, SOCKET fd, int revents)
81587231c9c584851518872e197f6f02dffe68cavboxsync{
81587231c9c584851518872e197f6f02dffe68cavboxsync void *ptr;
81587231c9c584851518872e197f6f02dffe68cavboxsync ssize_t nread;
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync if (revents & POLLNVAL) {
81587231c9c584851518872e197f6f02dffe68cavboxsync errx(EXIT_FAILURE, "chan %d: fd invalid", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync if (revents & (POLLERR | POLLHUP)) {
81587231c9c584851518872e197f6f02dffe68cavboxsync errx(EXIT_FAILURE, "chan %d: fd error", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync LWIP_ASSERT1(revents & POLLIN);
81587231c9c584851518872e197f6f02dffe68cavboxsync nread = recv(fd, (char *)&ptr, sizeof(ptr), 0);
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync if (nread == SOCKET_ERROR) {
81587231c9c584851518872e197f6f02dffe68cavboxsync err(EXIT_FAILURE, "chan %d: recv", (int)handler->slot);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
43c126a098acd369888f9302a322366ccb2bd4d7vboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync if (nread != sizeof(ptr)) {
81587231c9c584851518872e197f6f02dffe68cavboxsync errx(EXIT_FAILURE, "chan %d: recv: read %d bytes",
81587231c9c584851518872e197f6f02dffe68cavboxsync (int)handler->slot, (int)nread);
81587231c9c584851518872e197f6f02dffe68cavboxsync /* NOTREACHED */
81587231c9c584851518872e197f6f02dffe68cavboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync return ptr;
81587231c9c584851518872e197f6f02dffe68cavboxsync}
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsyncvoid
81587231c9c584851518872e197f6f02dffe68cavboxsyncpollmgr_update_events(int slot, int events)
81587231c9c584851518872e197f6f02dffe68cavboxsync{
81587231c9c584851518872e197f6f02dffe68cavboxsync LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
81587231c9c584851518872e197f6f02dffe68cavboxsync LWIP_ASSERT1((nfds_t)slot < pollmgr.nfds);
81587231c9c584851518872e197f6f02dffe68cavboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[slot].events = events;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync}
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncvoid
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsyncpollmgr_del_slot(int slot)
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsync{
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync DPRINTF2(("%s(%d): fd %d ! DELETED\n",
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync __func__, slot, pollmgr.fds[slot].fd));
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync pollmgr.fds[slot].fd = INVALID_SOCKET; /* see poll loop */
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync}
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsyncvoid
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsyncpollmgr_thread(void *ignored)
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync{
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync LWIP_UNUSED_ARG(ignored);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr_loop();
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync}
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsync
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsyncstatic void
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsyncpollmgr_loop(void)
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync{
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsync int nready;
da97b7ac000d0f02e86c31a4f2767a00d83c6167vboxsync SOCKET delfirst;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync SOCKET *pdelprev;
81587231c9c584851518872e197f6f02dffe68cavboxsync int i;
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync for (;;) {
81587231c9c584851518872e197f6f02dffe68cavboxsync#ifndef RT_OS_WINDOWS
81587231c9c584851518872e197f6f02dffe68cavboxsync nready = poll(pollmgr.fds, pollmgr.nfds, -1);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync#else
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync int rc = RTWinPoll(pollmgr.fds, pollmgr.nfds,RT_INDEFINITE_WAIT, &nready);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (RT_FAILURE(rc)) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* NOTREACHED*/
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync#endif
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF2(("%s: ready %d fd%s\n",
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync __func__, nready, (nready == 1 ? "" : "s")));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (nready < 0) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (errno == EINTR) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync continue;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* NOTREACHED*/
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else if (nready == 0) { /* cannot happen, we wait forever (-1) */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync continue; /* - but be defensive */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync delfirst = INVALID_SOCKET;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pdelprev = &delfirst;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
dccbafa70b5a9a6f933c5566e4542caf9f379b97vboxsync for (i = 0; (nfds_t)i < pollmgr.nfds && nready > 0; ++i) {
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync struct pollmgr_handler *handler;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync SOCKET fd;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync int revents, nevents;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync fd = pollmgr.fds[i].fd;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync revents = pollmgr.fds[i].revents;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /*
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * Channel handlers can request deletion of dynamic slots
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync * by calling pollmgr_del_slot() that clobbers slot's fd.
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (fd == INVALID_SOCKET && i >= POLLMGR_SLOT_FIRST_DYNAMIC) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* adjust count if events were pending for that slot */
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync if (revents != 0) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync --nready;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* pretend that slot handler requested deletion */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nevents = -1;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync goto update_events;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (revents == 0) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync continue; /* next fd */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync --nready;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync handler = pollmgr.handlers[i];
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (handler != NULL && handler->callback != NULL) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync#if LWIP_PROXY_DEBUG /* DEBUG */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (revents == POLLIN) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF2(("%s: ch %d\n", __func__, i));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF2(("%s: ch %d @ revents 0x%x!\n",
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync __func__, i, revents));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF2(("%s: fd %d @ revents 0x%x\n",
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync __func__, fd, revents));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync#endif /* DEBUG */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nevents = (*handler->callback)(handler, fd, revents);
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF0(("%s: invalid handler for fd %d: ", __func__, fd));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (handler == NULL) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF0(("NULL\n"));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync else {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync DPRINTF0(("%p (callback = NULL)\n", (void *)handler));
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync nevents = -1; /* delete it */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync update_events:
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync if (nevents >= 0) {
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync if (nevents != pollmgr.fds[i].events) {
d618bed3882cd227cf8f5d0d2824f8db42fad415vboxsync DPRINTF2(("%s: fd %d ! nevents 0x%x\n",
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync __func__, fd, nevents));
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync pollmgr.fds[i].events = nevents;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync }
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync else if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync /* Don't garbage-collect channels. */
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync DPRINTF2(("%s: fd %d ! DELETED (channel %d)\n",
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync __func__, fd, i));
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].fd = INVALID_SOCKET;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].events = 0;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.fds[i].revents = 0;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pollmgr.handlers[i] = NULL;
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync }
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync else {
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync DPRINTF2(("%s: fd %d ! DELETED\n", __func__, fd));
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync /* schedule for deletion (see g/c loop for details) */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync *pdelprev = i; /* make previous entry point to us */
b6097213cd07c5383c49168bfb61f915dbd4587avboxsync pdelprev = &pollmgr.fds[i].fd;
c882ddf98a60a4aab1218108b334083f98b7d66avboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[i].fd = INVALID_SOCKET; /* end of list (for now) */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[i].events = POLLMGR_GARBAGE;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync pollmgr.fds[i].revents = 0;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync pollmgr.handlers[i] = NULL;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync } /* processing loop */
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync /*
81587231c9c584851518872e197f6f02dffe68cavboxsync * Garbage collect and compact the array.
81587231c9c584851518872e197f6f02dffe68cavboxsync *
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 *
81587231c9c584851518872e197f6f02dffe68cavboxsync * See update_events code for nevents < 0 at the end of the
81587231c9c584851518872e197f6f02dffe68cavboxsync * processing loop above.
81587231c9c584851518872e197f6f02dffe68cavboxsync */
81587231c9c584851518872e197f6f02dffe68cavboxsync while (delfirst != INVALID_SOCKET) {
81587231c9c584851518872e197f6f02dffe68cavboxsync const int last = pollmgr.nfds - 1;
81587231c9c584851518872e197f6f02dffe68cavboxsync
81587231c9c584851518872e197f6f02dffe68cavboxsync /*
81587231c9c584851518872e197f6f02dffe68cavboxsync * We want a live entry in the last slot to swap into the
81587231c9c584851518872e197f6f02dffe68cavboxsync * freed slot, so make sure we have one.
81587231c9c584851518872e197f6f02dffe68cavboxsync */
81587231c9c584851518872e197f6f02dffe68cavboxsync if (pollmgr.fds[last].events == POLLMGR_GARBAGE /* garbage */
7be2140da7230ed5736528554a4dc34b2ac482acvboxsync || pollmgr.fds[last].fd == INVALID_SOCKET) /* or killed */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync {
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync /* drop garbage entry at the end of the array */
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync --pollmgr.nfds;
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync if (delfirst == last) {
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync /* congruent to delnext >= pollmgr.nfds test below */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync delfirst = INVALID_SOCKET; /* done */
45e9c1c72518aeba6673332bdd4d70b59e1c11a4vboxsync }
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync }
81587231c9c584851518872e197f6f02dffe68cavboxsync else {
81587231c9c584851518872e197f6f02dffe68cavboxsync const SOCKET delnext = pollmgr.fds[delfirst].fd;
14e0667f834cd0e2a8c365084cd2ad0a893109e8vboxsync
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];
ea6c70405e39fa563a55780ef25e0933d8c73a1avboxsync pollmgr.handlers[delfirst]->slot = (int)delfirst;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync --pollmgr.nfds;
4d6dcfe00aab559241d9ed05b89f803ab5ddf611vboxsync
if ((nfds_t)delnext >= pollmgr.nfds) {
delfirst = INVALID_SOCKET; /* done */
}
else {
delfirst = delnext;
}
}
pollmgr.fds[last].fd = INVALID_SOCKET;
pollmgr.fds[last].events = 0;
pollmgr.fds[last].revents = 0;
pollmgr.handlers[last] = NULL;
}
} /* poll loop */
}
/**
* Create strongly held refptr.
*/
struct pollmgr_refptr *
pollmgr_refptr_create(struct pollmgr_handler *ptr)
{
struct pollmgr_refptr *rp;
LWIP_ASSERT1(ptr != NULL);
rp = (struct pollmgr_refptr *)malloc(sizeof (*rp));
if (rp == NULL) {
return NULL;
}
sys_mutex_new(&rp->lock);
rp->ptr = ptr;
rp->strong = 1;
rp->weak = 0;
return rp;
}
static void
pollmgr_refptr_delete(struct pollmgr_refptr *rp)
{
if (rp == NULL) {
return;
}
LWIP_ASSERT1(rp->strong == 0);
LWIP_ASSERT1(rp->weak == 0);
sys_mutex_free(&rp->lock);
free(rp);
}
/**
* Add weak reference before "rp" is sent over a poll manager channel.
*/
void
pollmgr_refptr_weak_ref(struct pollmgr_refptr *rp)
{
sys_mutex_lock(&rp->lock);
LWIP_ASSERT1(rp->ptr != NULL);
LWIP_ASSERT1(rp->strong > 0);
++rp->weak;
sys_mutex_unlock(&rp->lock);
}
/**
* Try to get the pointer from implicitely weak reference we've got
* from a channel.
*
* If we detect that the object is still strongly referenced, but no
* longer registered with the poll manager we abort strengthening
* conversion here b/c lwip thread callback is already scheduled to
* destruct the object.
*/
struct pollmgr_handler *
pollmgr_refptr_get(struct pollmgr_refptr *rp)
{
struct pollmgr_handler *handler;
size_t weak;
sys_mutex_lock(&rp->lock);
LWIP_ASSERT1(rp->weak > 0);
weak = --rp->weak;
handler = rp->ptr;
if (handler == NULL) {
LWIP_ASSERT1(rp->strong == 0);
sys_mutex_unlock(&rp->lock);
if (weak == 0) {
pollmgr_refptr_delete(rp);
}
return NULL;
}
LWIP_ASSERT1(rp->strong == 1);
/*
* Here we woild do:
*
* ++rp->strong;
*
* and then, after channel handler is done, we would decrement it
* back.
*
* Instead we check that the object is still registered with poll
* manager. If it is, there's no race with lwip thread trying to
* drop its strong reference, as lwip thread callback to destruct
* the object is always scheduled by its poll manager callback.
*
* Conversly, if we detect that the object is no longer registered
* with poll manager, we immediately abort. Since channel handler
* can't do anything useful anyway and would have to return
* immediately.
*
* Since channel handler would always find rp->strong as it had
* left it, just elide extra strong reference creation to avoid
* the whole back-and-forth.
*/
if (handler->slot < 0) { /* no longer polling */
sys_mutex_unlock(&rp->lock);
return NULL;
}
sys_mutex_unlock(&rp->lock);
return handler;
}
/**
* Remove (the only) strong reference.
*
* If it were real strong/weak pointers, we should also call
* destructor for the referenced object, but
*/
void
pollmgr_refptr_unref(struct pollmgr_refptr *rp)
{
sys_mutex_lock(&rp->lock);
LWIP_ASSERT1(rp->strong == 1);
--rp->strong;
if (rp->strong > 0) {
sys_mutex_unlock(&rp->lock);
}
else {
size_t weak;
/* void *ptr = rp->ptr; */
rp->ptr = NULL;
/* delete ptr; // see doc comment */
weak = rp->weak;
sys_mutex_unlock(&rp->lock);
if (weak == 0) {
pollmgr_refptr_delete(rp);
}
}
}