Skip to content

Commit

Permalink
SCP: NAT poll() optimizations
Browse files Browse the repository at this point in the history
- Manage poll() file descriptors more efficiently. Both Linux() poll and
  Windows WSAPoll() ignore file descriptors that are negative in the
  pollfd array. Set the pollfd.fd file descriptor to INVALID_SOCKET when
  no longer needed. Reuse the pollfd array element if have_valid_socket()
  returns false.

- sim_slirp_dispath(): Removed, empty function no longer required.
  • Loading branch information
bscottm committed Dec 11, 2024
1 parent 70120dd commit 8625fb4
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 57 deletions.
9 changes: 7 additions & 2 deletions sim_slirp/sim_slirp.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,9 @@ t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, con
/* Initialize the select/poll file descriptor arrays. */
static int initialize_poll_fds(SimSlirpNetwork *slirp)
{
#if SIM_USE_SELECT
size_t i;

#if SIM_USE_SELECT
FD_ZERO(&slirp->readfds);
FD_ZERO(&slirp->writefds);
FD_ZERO(&slirp->exceptfds);
Expand All @@ -599,9 +599,14 @@ static int initialize_poll_fds(SimSlirpNetwork *slirp)
slirp->lut[i] = INVALID_SOCKET;
#else
/* poll()-based file descriptor polling. */
static const sim_pollfd_t poll_initializer = { INVALID_SOCKET, 0, 0};

slirp->n_fds = FDS_ALLOC_INIT;
slirp->fd_idx = 0;
slirp->fds = (sim_pollfd_t *) calloc(slirp->n_fds, sizeof(sim_pollfd_t));
slirp->fds = (sim_pollfd_t *) malloc(slirp->n_fds * sizeof(sim_pollfd_t));
for (i = 0; i < slirp->n_fds; ++i) {
slirp->fds[i] = poll_initializer;
}
#endif

return 0;
Expand Down
1 change: 0 additions & 1 deletion sim_slirp/sim_slirp.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ SimSlirpNetwork *sim_slirp_open (const char *args, void *pkt_opaque, packet_call
void sim_slirp_close (SimSlirpNetwork *slirp);
int sim_slirp_send (SimSlirpNetwork *slirp, const char *msg, size_t len, int flags);
int sim_slirp_select (SimSlirpNetwork *slirp, int ms_timeout);
void sim_slirp_dispatch (SimSlirpNetwork *slirp);
t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
void sim_slirp_show (SimSlirpNetwork *slirp, FILE *st);

Expand Down
2 changes: 1 addition & 1 deletion sim_slirp/sim_slirp_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

/* Abstract the poll structure as sim_pollfd_t */
#if SIM_USE_POLL
# if (defined(_WIN32) || defined(_WIN64))
# if defined(_WIN32) || defined(_WIN64)
typedef WSAPOLLFD sim_pollfd_t;
# else
# include <poll.h>
Expand Down
114 changes: 61 additions & 53 deletions sim_slirp/slirp_poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
# if defined(PRIu32)
# define SIM_PRIsocket PRIu32
# else
# define SIM_PRIsocket "lu"
# define SIM_PRIsocket "u"
# endif
#else
# define SIM_PRIsocket "u"
Expand All @@ -75,21 +75,21 @@ static inline uint32_t slirp_dbg_mask(const SimSlirpNetwork *slirp, size_t flag)
return (slirp != NULL && slirp->dptr != NULL) ? slirp->dptr->debflags[slirp->flag_offset + flag].mask : 0;
}

#if SIM_USE_SELECT
/* Socket identifier pretty-printer: */
static const char *print_socket(slirp_os_socket s)
/* Socket error check */
static inline int have_valid_socket(slirp_os_socket s)
{
static char retbuf[64];

#if defined(_WIN64)
sprintf(retbuf, "%llu", s);
#elif defined(_WIN32)
sprintf(retbuf, "%u", s);
#if !defined(_WIN32) && !defined(_WIN64)
return (s >= 0);
#else
sprintf(retbuf, "%d", s);
return (s != SLIRP_INVALID_SOCKET);
#endif
}

return retbuf;
#if (defined(_WIN32) || defined(_WIN64)) && SIM_USE_POLL
/* poll() wrapper for Windows: */
static inline int poll(WSAPOLLFD *fds, size_t n_fds, int timeout)
{
return WSAPoll(fds, (ULONG) n_fds, timeout);
}
#endif

Expand Down Expand Up @@ -145,13 +145,6 @@ int sim_slirp_select(SimSlirpNetwork *slirp, int ms_timeout)
* "Protocol" functions. These functions abide by the one function definition rule.
*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/

#if (defined(_WIN32) || defined(_WIN64)) && SIM_USE_POLL
static inline int poll(WSAPOLLFD *fds, size_t n_fds, int timeout)
{
return WSAPoll(fds, (ULONG) n_fds, timeout);
}
#endif

static void initialize_poll(SimSlirpNetwork *slirp, uint32 tmo, struct timeval *tv)
{
#if SIM_USE_SELECT
Expand All @@ -164,9 +157,7 @@ static void initialize_poll(SimSlirpNetwork *slirp, uint32 tmo, struct timeval *

slirp->max_fd = SIM_INVALID_MAX_FD;
#elif SIM_USE_POLL
/* Reinitialize and reset */
memset(slirp->fds, 0, slirp->fd_idx * sizeof(sim_pollfd_t));
slirp->fd_idx = 0;
/* Nothing to do. */
#endif
}

Expand Down Expand Up @@ -238,10 +229,10 @@ static void report_error(SimSlirpNetwork *slirp)
/* Add new socket file descriptors to the Slirp I/O event tracking state. */
void register_poll_socket(slirp_os_socket fd, void *opaque)
{
#if SIM_USE_SELECT
SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque;
size_t i;

#if SIM_USE_SELECT
for (i = 0; i < slirp->lut_alloc; ++i) {
if (slirp->lut[i] == INVALID_SOCKET) {
slirp->lut[i] = fd;
Expand All @@ -264,34 +255,55 @@ void register_poll_socket(slirp_os_socket fd, void *opaque)
slirp->lut[i] = fd;
}

sim_debug(slirp_dbg_mask(slirp, DBG_SOCKET), slirp->dptr, "register_poll_socket(%s) index %" SIZE_T_FMT "d\n",
print_socket(fd), i);
sim_debug(slirp_dbg_mask(slirp, DBG_SOCKET), slirp->dptr, "register_poll_socket(%" SIM_PRIsocket " index %" SIZE_T_FMT "d\n",
fd, i);
#elif SIM_USE_POLL
/* Not necessary for poll(). */
(void) opaque;
for (i = 0; i < slirp->fd_idx && have_valid_socket(slirp->fds[i].fd); ++i)
/* NOP */;

if (i >= slirp->n_fds) {
/* Resize the array... */
size_t j = slirp->n_fds;
sim_pollfd_t *new_fds;

slirp->n_fds += FDS_ALLOC_INCR;
new_fds = (sim_pollfd_t *) realloc(slirp->fds, slirp->n_fds * sizeof(sim_pollfd_t));
ASSURE(new_fds != NULL);
memset(new_fds + j, 0, (slirp->n_fds - j) * sizeof(sim_pollfd_t));
slirp->fds = new_fds;
}

slirp->fds[i].fd = fd;
slirp->fds[i].events = slirp->fds[i].revents = 0;

if (i == slirp->fd_idx)
++slirp->fd_idx;
#endif
}

/* Reap a disused socket. */
void unregister_poll_socket(slirp_os_socket fd, void *opaque)
{
GLIB_UNUSED_PARAM(opaque);

#if SIM_USE_SELECT
SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque;
size_t i;

#if SIM_USE_SELECT
for (i = 0; i < slirp->lut_alloc; ++i) {
if (slirp->lut[i] == fd) {
slirp->lut[i] = INVALID_SOCKET;
sim_debug(slirp_dbg_mask(slirp, DBG_SOCKET), slirp->dptr,
"unregister_poll_socket(%s) index %" SIZE_T_FMT "d\n", print_socket(fd), i);
"unregister_poll_socket(%" SIM_PRIsocket ") index %" SIZE_T_FMT "d\n", fd, i);
break;
}
}
#elif SIM_USE_POLL
/* Not necessary for poll(). */
(void) opaque;
for (i = 0; i < slirp->fd_idx && slirp->fds[i].fd != fd; ++i)
/* NOP */;

if (i < slirp->fd_idx) {
slirp->fds[i].fd = INVALID_SOCKET;
slirp->fds[i].events = slirp->fds[i].revents = 0;
}
#endif
}

Expand Down Expand Up @@ -339,9 +351,9 @@ static int add_poll_callback(slirp_os_socket fd, int events, void *opaque)
SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque;
int retval = -1;
char prefix[128];
size_t i;

#if SIM_USE_SELECT
size_t i;
const int event_mask = (SLIRP_POLL_IN | SLIRP_POLL_OUT | SLIRP_POLL_PRI);

for (i = 0; i < slirp->lut_alloc; ++i) {
Expand All @@ -364,21 +376,10 @@ static int add_poll_callback(slirp_os_socket fd, int events, void *opaque)
break;
}

sprintf(prefix, "add_poll_callback(%s)/select (0x%04x)", print_socket(fd), events & event_mask);
sprintf(prefix, "add_poll_callback(%" SIM_PRIsocket ")/select (0x%04x)", fd, events & event_mask);
poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, events & event_mask);
}
#elif SIM_USE_POLL
if (slirp->fd_idx == slirp->n_fds) {
size_t j = slirp->n_fds;
sim_pollfd_t *new_fds;

slirp->n_fds += FDS_ALLOC_INCR;
new_fds = (sim_pollfd_t *) realloc(slirp->fds, slirp->n_fds * sizeof(sim_pollfd_t));
ASSURE(new_fds != NULL);
memset(new_fds + j, 0, (slirp->n_fds - j) * sizeof(sim_pollfd_t));
slirp->fds = new_fds;
}

short poll_events = 0;

if (events & SLIRP_POLL_IN) {
Expand All @@ -387,7 +388,7 @@ static int add_poll_callback(slirp_os_socket fd, int events, void *opaque)
if (events & SLIRP_POLL_OUT) {
poll_events |= POLLOUT;
}
#if !defined(_WIN32) && !defined(_WIN64)
# if !defined(_WIN32) && !defined(_WIN64)
/* Not supported on Windows. Unless you like EINVAL. :-) */
if (events & SLIRP_POLL_PRI) {
poll_events |= POLLPRI;
Expand All @@ -398,16 +399,23 @@ static int add_poll_callback(slirp_os_socket fd, int events, void *opaque)
if (events & SLIRP_POLL_HUP) {
poll_events |= POLLHUP;
}
#endif
# endif
for (i = 0; i < slirp->fd_idx && slirp->fds[i].fd != fd; ++i)
/* NOP */ ;

if (i >= slirp->fd_idx) {
sim_messagef(SCPE_IOERR, "add_poll_callback: Unregistered/unknown fd %" SIM_PRIsocket "\n", fd);
return -1;
}

sprintf(prefix, "add_poll_callback(%" SIM_PRIsocket ")/poll (0x%04x)", fd, events);
poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, events);

slirp->fds[slirp->fd_idx].fd = fd;
slirp->fds[slirp->fd_idx].events = poll_events;
slirp->fds[slirp->fd_idx].revents = 0;
slirp->fds[i].fd = fd;
slirp->fds[i].events = poll_events;
slirp->fds[i].revents = 0;

retval = (int) slirp->fd_idx++;
retval = (int) i;
#endif

return retval;
Expand Down Expand Up @@ -435,7 +443,7 @@ static int get_events_callback(int idx, void *opaque)
event |= SLIRP_POLL_PRI;
}

sprintf(prefix, "get_events_callback(%s)/select (0x%04x)", print_socket(fd), event & event_mask);
sprintf(prefix, "get_events_callback(%" SIM_PRIsocket ")/select (0x%04x)", fd, event & event_mask);
poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, event & event_mask);
}
#elif SIM_USE_POLL
Expand Down

0 comments on commit 8625fb4

Please sign in to comment.