wrapper process should exit with signal if prewarmed worker exits with signal
This commit is contained in:
parent
a3f1a44d83
commit
624e96df9b
@ -8,6 +8,7 @@ import os
|
|||||||
import select
|
import select
|
||||||
import signal
|
import signal
|
||||||
import socket
|
import socket
|
||||||
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
@ -525,15 +526,8 @@ class SocketChild:
|
|||||||
def handle_death(self, status: int) -> None:
|
def handle_death(self, status: int) -> None:
|
||||||
if self.closed:
|
if self.closed:
|
||||||
return
|
return
|
||||||
if hasattr(os, 'waitstatus_to_exitcode'):
|
|
||||||
status = os.waitstatus_to_exitcode(status)
|
|
||||||
# negative numbers are signals usually and shells report these as
|
|
||||||
# 128 + signal number, so do the same. There is no API to exit a
|
|
||||||
# process with full 32bit status information.
|
|
||||||
if -128 < status < 0:
|
|
||||||
status = 128 - status
|
|
||||||
try:
|
try:
|
||||||
self.conn.sendall(f'{status}'.encode('ascii'))
|
self.conn.sendall(struct.pack('q', status))
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print_error(f'Failed to send exit status of socket child with error: {e}')
|
print_error(f'Failed to send exit status of socket child with error: {e}')
|
||||||
|
|
||||||
@ -541,7 +535,7 @@ class SocketChild:
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
self.conn.sendall(f'{self.pid}:'.encode('ascii'))
|
self.conn.sendall(struct.pack('q', self.pid))
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print_error(f'Failed to send pid of socket child with error: {e}')
|
print_error(f'Failed to send pid of socket child with error: {e}')
|
||||||
return False
|
return False
|
||||||
|
|||||||
@ -69,6 +69,10 @@ def socket_child_main(exit_code=0, initial_print=''):
|
|||||||
if status is None:
|
if status is None:
|
||||||
os.kill(pty.child_pid, signal.SIGKILL)
|
os.kill(pty.child_pid, signal.SIGKILL)
|
||||||
self.assertIsNotNone(status, f'prewarm wrapper process did not exit. Screen contents: {pty.screen_contents()}')
|
self.assertIsNotNone(status, f'prewarm wrapper process did not exit. Screen contents: {pty.screen_contents()}')
|
||||||
|
if isinstance(exit_code, signal.Signals):
|
||||||
|
self.assertTrue(os.WIFSIGNALED(status), 'prewarm wrapper did not die with a signal')
|
||||||
|
self.assertEqual(os.WTERMSIG(status), exit_code.value)
|
||||||
|
else:
|
||||||
with suppress(AttributeError):
|
with suppress(AttributeError):
|
||||||
self.assertEqual(os.waitstatus_to_exitcode(status), exit_code, pty.screen_contents())
|
self.assertEqual(os.waitstatus_to_exitcode(status), exit_code, pty.screen_contents())
|
||||||
|
|
||||||
@ -89,7 +93,7 @@ def socket_child_main(exit_code=0, initial_print=''):
|
|||||||
pty.wait_till(lambda: f'Screen size changed: {cols + 3}' in pty.screen_contents())
|
pty.wait_till(lambda: f'Screen size changed: {cols + 3}' in pty.screen_contents())
|
||||||
pty.write_to_child('\x03')
|
pty.write_to_child('\x03')
|
||||||
pty.wait_till(lambda: 'KeyboardInterrupt' in pty.screen_contents())
|
pty.wait_till(lambda: 'KeyboardInterrupt' in pty.screen_contents())
|
||||||
wait_for_death(128 + signal.SIGINT)
|
wait_for_death(signal.SIGINT)
|
||||||
|
|
||||||
# test passing of data via cwd, env vars and stdin/stdout redirection
|
# test passing of data via cwd, env vars and stdin/stdout redirection
|
||||||
stdin_r, stdin_w = os.pipe()
|
stdin_r, stdin_w = os.pipe()
|
||||||
|
|||||||
@ -83,14 +83,6 @@ parse_long(const char *str, long *val) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
parse_int(const char *str, int *val) {
|
|
||||||
long lval = 0;
|
|
||||||
if (!parse_long(str, &lval)) return false;
|
|
||||||
*val = lval;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
safe_open(const char *path, int flags, mode_t mode) {
|
safe_open(const char *path, int flags, mode_t mode) {
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -355,26 +347,20 @@ static enum ChildState child_state = CHILD_NOT_STARTED;
|
|||||||
static bool
|
static bool
|
||||||
read_child_data(void) {
|
read_child_data(void) {
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
if (from_child_buf_pos >= sizeof(from_child_buf) - 2) { print_error("Too much data from prewarm socket", 0); return false; }
|
if (from_child_buf_pos >= sizeof(from_child_buf)) { print_error("Too much data from prewarm socket", 0); return false; }
|
||||||
n = safe_read(socket_fd, from_child_buf, sizeof(from_child_buf) - 2 - from_child_buf_pos);
|
n = safe_read(socket_fd, from_child_buf + from_child_buf_pos, sizeof(from_child_buf) - from_child_buf_pos);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EIO || errno == EPIPE) { socket_fd = -1; return true; }
|
if (errno == EIO || errno == EPIPE) { socket_fd = -1; return true; }
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (n) {
|
if (n) {
|
||||||
from_child_buf_pos += n;
|
from_child_buf_pos += n;
|
||||||
char *p = memchr(from_child_buf, ':', from_child_buf_pos);
|
if (from_child_buf_pos >= sizeof(long long)) {
|
||||||
if (p && child_pid == 0) {
|
pid_t cp = *((long long*)from_child_buf);
|
||||||
*p = 0;
|
|
||||||
long cp = 0;
|
|
||||||
if (!parse_long(from_child_buf, &cp)) { print_error("Could not parse child pid from prewarm socket", 0); return false; }
|
|
||||||
if (cp == 0) { print_error("Got zero child pid from prewarm socket", 0); return false; }
|
if (cp == 0) { print_error("Got zero child pid from prewarm socket", 0); return false; }
|
||||||
child_pid = cp;
|
child_pid = cp;
|
||||||
child_state = CHILD_STARTED;
|
child_state = CHILD_STARTED;
|
||||||
if (child_slave_fd > -1) { safe_close(child_slave_fd); child_slave_fd = -1; }
|
if (child_slave_fd > -1) { safe_close(child_slave_fd); child_slave_fd = -1; }
|
||||||
memset(from_child_buf, 0, (p - from_child_buf) + 1);
|
|
||||||
from_child_buf_pos -= (p - from_child_buf) + 1;
|
|
||||||
if (from_child_buf_pos) memmove(from_child_buf, p + 1, from_child_buf_pos);
|
|
||||||
for (size_t i = 0; i < arraysz(pending_signals) && pending_signals[i]; i++) {
|
for (size_t i = 0; i < arraysz(pending_signals) && pending_signals[i]; i++) {
|
||||||
kill(child_pid, pending_signals[i]);
|
kill(child_pid, pending_signals[i]);
|
||||||
}
|
}
|
||||||
@ -612,7 +598,18 @@ loop(void) {
|
|||||||
if (FD_ISSET(socket_fd, &readable)) {
|
if (FD_ISSET(socket_fd, &readable)) {
|
||||||
if (!read_child_data()) fail("reading information about child failed");
|
if (!read_child_data()) fail("reading information about child failed");
|
||||||
if (socket_fd < 0) { // hangup
|
if (socket_fd < 0) { // hangup
|
||||||
if (from_child_buf[0]) { parse_int(from_child_buf, &exit_status); }
|
if (from_child_buf_pos >= 2 * sizeof(long long)) {
|
||||||
|
int child_exit_status = *((long long*)(from_child_buf + sizeof(long long)));
|
||||||
|
if (WIFEXITED(child_exit_status)) {
|
||||||
|
exit_status = WEXITSTATUS(child_exit_status);
|
||||||
|
} else if (WIFSIGNALED(child_exit_status)) {
|
||||||
|
int signum = WTERMSIG(child_exit_status);
|
||||||
|
if (signum > 0) {
|
||||||
|
signal(signum, SIG_DFL);
|
||||||
|
kill(getpid(), signum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
child_pid = 0;
|
child_pid = 0;
|
||||||
child_state = CHILD_EXITED;
|
child_state = CHILD_EXITED;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user