Transfer data between ttys

This commit is contained in:
Kovid Goyal 2022-07-03 10:27:32 +05:30
parent 44c9d66dd4
commit a4883e6d41
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 89 additions and 2 deletions

View File

@ -496,7 +496,7 @@ def main(stdin_fd: int, stdout_fd: int, notify_child_death_fd: int, unix_socket:
if event & select.POLLHUP:
raise SystemExit(0)
if event & error_events:
raise SystemExit(err_msg)
raise SystemExit(f'Prewarm zygote process: {err_msg}')
def handle_input(event: int) -> None:
nonlocal input_buf, output_buf

View File

@ -44,8 +44,16 @@
a > b ? a : b;})
// }}}
#define err_prefix "prewarm wrapper process error: "
#define IO_BUZ_SZ 8192
typedef struct transfer_buf {
char *buf;
size_t sz;
} transfer_buf;
static transfer_buf from_child_tty = {0};
static transfer_buf to_child_tty = {0};
#define err_prefix "prewarm wrapper process error: "
static inline void
print_error(const char *s, int errnum) {
if (errnum != 0) fprintf(stderr, "%s%s: %s\n\r", err_prefix, s, strerror(errnum));
@ -93,6 +101,20 @@ safe_tcsetattr(int fd, int actions, const struct termios *tp) {
return ret == 0;
}
static ssize_t
safe_read(int fd, void *buf, size_t n) {
ssize_t ret = 0;
while((ret = read(fd, buf, n)) ==-1 && errno == EINTR);
return ret;
}
static ssize_t
safe_write(int fd, void *buf, size_t n) {
ssize_t ret = 0;
while((ret = write(fd, buf, n)) ==-1 && errno == EINTR);
return ret;
}
static size_t
strnlength(const char* s, size_t n) {
const char* found = memchr(s, '\0', n);
@ -159,6 +181,7 @@ cleanup(void) {
cfd(self_ttyfd); cfd(socket_fd); cfd(signal_read_fd); cfd(signal_write_fd);
#undef cfd
if (launch_msg_buf) { free(launch_msg_buf); launch_msg.iov_len = 0; launch_msg_buf = NULL; }
if (from_child_tty.buf) { free(from_child_tty.buf); from_child_tty.buf = NULL; }
}
static bool
@ -319,6 +342,55 @@ send_launch_msg(void) {
return true;
}
static bool
read_or_transfer(int src_fd, int dest_fd, transfer_buf *t) {
(void)dest_fd;
if (t->sz >= IO_BUZ_SZ) return true;
ssize_t n = safe_read(src_fd, t->buf + t->sz, IO_BUZ_SZ - t->sz);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) return true;
return false;
}
t->sz += n;
return true;
}
static bool
read_or_transfer_from_child_tty(void) {
return read_or_transfer(child_master_fd, self_ttyfd, &from_child_tty);
}
static bool
write_from_to(transfer_buf *src, int dest_fd) {
if (!src->sz) return true;
ssize_t n = safe_write(dest_fd, src->buf, src->sz);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) return true;
return false;
}
if (n > 0) {
src->sz -= n;
memmove(src->buf, src->buf + n, src->sz);
}
return true;
}
static bool
from_child_to_self(void) {
return write_from_to(&from_child_tty, self_ttyfd);
}
static bool
from_self_to_child(void) {
return write_from_to(&to_child_tty, child_master_fd);
}
static bool
read_or_transfer_from_self_tty(void) {
return read_or_transfer(self_ttyfd, child_master_fd, &to_child_tty);
}
static void
loop(void) {
@ -332,12 +404,22 @@ loop(void) {
while (true) {
int ret;
// self_ttyfd
poll_data[0].events = (to_child_tty.sz < IO_BUZ_SZ - 1 ? POLLIN : 0) | (from_child_tty.sz ? POLLOUT : 0);
// child_master_fd
poll_data[1].events = (from_child_tty.sz < IO_BUZ_SZ - 1 ? POLLIN : 0) | (to_child_tty.sz ? POLLOUT : 0);
// socket_fd
poll_data[2].events = POLLIN | (launch_msg.iov_len ? POLLOUT : 0);
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"); }
if (!ret) continue;
if (poll_data[1].revents & POLLIN) if (!read_or_transfer_from_child_tty()) fail("reading from child tty failed");
if (poll_data[0].revents & POLLOUT) if (!from_child_to_self()) fail("writing to self tty failed");
if (poll_data[0].revents & POLLIN) if (!read_or_transfer_from_self_tty()) fail("reading from self tty failed");
if (poll_data[1].revents & POLLOUT) if (!from_self_to_child()) fail("writing to child tty failed");
check_fd(0, self_ttyfd); check_fd(1, child_master_fd); check_fd(3, signal_read_fd);
// socket_fd
@ -379,9 +461,14 @@ use_prewarmed_process(int argc, char *argv[]) {
if (!setup_signal_handler()) fail("Failed to setup signal handling");
socket_fd = connect_to_socket_synchronously(env_addr);
if (socket_fd < 0) fail("Failed to connect to prewarm socket");
from_child_tty.buf = malloc(IO_BUZ_SZ * 2);
if (!from_child_tty.buf) fail("Out of memory allocating IO buffer");
to_child_tty.buf = from_child_tty.buf + IO_BUZ_SZ;
#undef fail
loop();
read_or_transfer_from_child_tty();
from_child_to_self();
cleanup();
exit(exit_status);
}