Even more flexible management of poll data

This commit is contained in:
Kovid Goyal 2022-07-07 16:10:48 +05:30
parent 5d1cf49fb6
commit cf8113ea24
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -47,6 +47,12 @@
// }}}
#define IO_BUZ_SZ 8192
#define remove_i_from_array(array, i, count) { \
(count)--; \
if ((i) < (count)) { \
memmove((array) + (i), (array) + (i) + 1, sizeof((array)[0]) * ((count) - (i))); \
}}
typedef struct transfer_buf {
char *buf;
@ -454,24 +460,31 @@ read_signals(void) {
return true;
}
struct pollees {
struct pollfd poll_data[8];
struct {
int self_ttyfd, signal_read_fd, socket_fd, child_master_fd;
} idx;
size_t num_fds;
};
static struct pollees pollees = {0};
#define register_for_poll(which) pollees.poll_data[pollees.num_fds].fd = which; pollees.poll_data[pollees.num_fds].events = POLLIN; pollees.idx.which = pollees.num_fds++;
#define unregister_for_poll(which) if (pollees.idx.which > -1) { remove_i_from_array(pollees.poll_data, pollees.idx.which, pollees.num_fds); pollees.idx.which = -1; }
#define set_poll_events(which, val) if (pollees.idx.which > -1) { pollees.poll_data[pollees.idx.which].events = (val); }
#define poll_revents(which) ((pollees.idx.which > -1) ? pollees.poll_data[pollees.idx.which].revents : 0)
static void
loop(void) {
#define fail(s) { print_error(s, errno); return; }
#define pd(which) poll_data[which##_idx]
#define check_fd(name) { if (pd(name).revents & POLLERR) { pe("File descriptor %s failed", #name); return; } if (pd(name).revents & POLLHUP) { pe("File descriptor %s hungup", #name); return; } }
struct pollfd poll_data[4];
enum { self_ttyfd_idx, signal_read_fd_idx, socket_fd_idx, child_master_fd_idx };
#define init(name) pd(name).fd = name; pd(name).events = POLLIN;
init(self_ttyfd); init(socket_fd); init(signal_read_fd); init(child_master_fd);
#undef init
#define check_fd(name) { if (poll_revents(name) & POLLERR) { pe("File descriptor %s failed", #name); return; } if (poll_revents(name) & POLLHUP) { pe("File descriptor %s hungup", #name); return; } }
register_for_poll(self_ttyfd); register_for_poll(socket_fd); register_for_poll(signal_read_fd); register_for_poll(child_master_fd);
while (true) {
int ret;
pd(self_ttyfd).events = (to_child_tty.sz < IO_BUZ_SZ ? POLLIN : 0) | (from_child_tty.sz ? POLLOUT : 0);
if (socket_fd > -1) pd(socket_fd).events = POLLIN | (launch_msg.iov_len ? POLLOUT : 0);
else pd(socket_fd).events = 0;
if (child_master_fd > -1) pd(child_master_fd).events = (from_child_tty.sz < IO_BUZ_SZ ? POLLIN : 0) | (to_child_tty.sz ? POLLOUT : 0);
else pd(child_master_fd).events = 0;
set_poll_events(self_ttyfd, (to_child_tty.sz < IO_BUZ_SZ ? POLLIN : 0) | (from_child_tty.sz ? POLLOUT : 0));
set_poll_events(socket_fd, POLLIN | (launch_msg.iov_len ? POLLOUT : 0));
set_poll_events(child_master_fd, (from_child_tty.sz < IO_BUZ_SZ ? POLLIN : 0) | (to_child_tty.sz ? POLLOUT : 0));
if (window_size_dirty && child_master_fd > -1 ) {
if (!get_window_size()) fail("getting window size for self tty failed");
@ -479,44 +492,43 @@ loop(void) {
window_size_dirty = false;
}
for (size_t i = 0; i < arraysz(poll_data); i++) poll_data[i].revents = 0;
while ((ret = poll(poll_data, arraysz(poll_data), -1)) == -1) { if (errno != EINTR) fail("poll() failed"); }
for (size_t i = 0; i < pollees.num_fds; i++) pollees.poll_data[i].revents = 0;
while ((ret = poll(pollees.poll_data, pollees.num_fds, -1)) == -1) { if (errno != EINTR) fail("poll() failed"); }
if (!ret) continue;
if (pd(child_master_fd).revents & POLLIN) if (!read_or_transfer_from_child_tty()) fail("reading from child tty failed");
if (pd(self_ttyfd).revents & POLLOUT) if (!from_child_to_self()) fail("writing to self tty failed");
if (pd(self_ttyfd).revents & POLLIN) if (!read_or_transfer_from_self_tty()) fail("reading from self tty failed");
if (pd(child_master_fd).revents & POLLOUT) if (!from_self_to_child()) fail("writing to child tty failed");
if (pd(child_master_fd).revents & POLLHUP) {
if (poll_revents(child_master_fd) & POLLIN) if (!read_or_transfer_from_child_tty()) fail("reading from child tty failed");
if (poll_revents(self_ttyfd) & POLLOUT) if (!from_child_to_self()) fail("writing to self tty failed");
if (poll_revents(self_ttyfd) & POLLIN) if (!read_or_transfer_from_self_tty()) fail("reading from self tty failed");
if (poll_revents(child_master_fd) & POLLOUT) if (!from_self_to_child()) fail("writing to child tty failed");
if (poll_revents(child_master_fd) & POLLHUP) {
// child has closed its tty, wait for exit code from prewarm zygote
safe_close(child_master_fd); child_master_fd = -1;
unregister_for_poll(child_master_fd);
if (!child_pid) return;
}
check_fd(self_ttyfd);
if (child_master_fd > -1) check_fd(child_master_fd);
check_fd(signal_read_fd);
check_fd(self_ttyfd); check_fd(child_master_fd); check_fd(signal_read_fd);
// signal_read_fd
if (pd(signal_read_fd).revents & POLLIN) if (!read_signals()) fail("reading from signal fd failed");
if (poll_revents(signal_read_fd) & POLLIN) if (!read_signals()) fail("reading from signal fd failed");
// socket_fd
if (pd(socket_fd).revents & POLLERR) {
if (poll_revents(socket_fd) & POLLERR) {
print_error("File descriptor socket_fd failed", 0); return;
}
if (pd(socket_fd).revents & POLLIN) {
if (poll_revents(socket_fd) & POLLIN) {
if (!read_child_data()) fail("reading information about child failed");
}
if (pd(socket_fd).revents & POLLHUP) {
if (poll_revents(socket_fd) & POLLHUP) {
if (from_child_buf[0]) { parse_int(from_child_buf, &exit_status); }
child_pid = 0;
child_pid = 0; safe_close(socket_fd); socket_fd = -1;
unregister_for_poll(socket_fd);
if (child_master_fd < 0) return;
}
if (pd(socket_fd).revents & POLLOUT) {
if (poll_revents(socket_fd) & POLLOUT) {
if (!send_launch_msg()) fail("sending launch message failed");
}
}
#undef pd
#undef check_fd
#undef fail
}