io->cb(io->data, IO_WRITE);
else if(FD_ISSET(io->fd, &readable))
io->cb(io->data, IO_READ);
+ else
+ continue;
+
+ /*
+ There are scenarios in which the callback will remove another io_t from the tree
+ (e.g. closing a double connection). Since splay_each does not support that, we
+ need to exit the loop now. That's okay, since any remaining events will get picked
+ up by the next select() call.
+ */
+ break;
}
}
#else
WSANETWORKEVENTS network_events;
if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
return false;
- if (network_events.lNetworkEvents & WRITE_EVENTS)
- io->cb(io->data, IO_WRITE);
if (network_events.lNetworkEvents & READ_EVENTS)
io->cb(io->data, IO_READ);
+ /*
+ The fd might be available for write too. However, if we already fired the read callback, that
+ callback might have deleted the io (e.g. through terminate_connection()), so we can't fire the
+ write callback here. Instead, we loop back and let the writable io loop above handle it.
+ */
}
}
#endif