handle child death and config reload for prewarmed processes

This commit is contained in:
Kovid Goyal 2022-06-08 07:10:52 +05:30
parent 90bc3ab770
commit 0c870c5fcd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 45 additions and 7 deletions

View File

@ -49,6 +49,7 @@ from .notify import notification_activated
from .options.types import Options
from .options.utils import MINIMUM_FONT_SIZE, KeyMap, SubSequenceMap
from .os_window_size import initial_window_size_func
from .prewarm import PrewarmProcess
from .rgb import color_from_int
from .session import Session, create_sessions, get_os_window_sizing_data
from .tabs import (
@ -253,10 +254,11 @@ class Boss:
self.allow_remote_control = opts.allow_remote_control
if args.listen_on and (self.allow_remote_control in ('y', 'socket-only')):
listen_fd = listen_on(args.listen_on)
self.prewarm = PrewarmProcess()
self.child_monitor = ChildMonitor(
self.on_child_death,
DumpCommands(args) if args.dump_commands or args.dump_bytes else None,
talk_fd, listen_fd
talk_fd, listen_fd, self.prewarm.take_from_worker_fd()
)
set_boss(self)
self.args = args
@ -1957,6 +1959,7 @@ class Boss:
for w in self.all_windows:
self.default_bg_changed_for(w.id)
w.refresh()
self.prewarm.reload_kitty_config()
@ac('misc', '''
Reload the config file

View File

@ -34,7 +34,7 @@ extern PyTypeObject Screen_Type;
#define EVDBG(...)
#endif
#define EXTRA_FDS 2
#define EXTRA_FDS 3
#ifndef MSG_NOSIGNAL
// Apple does not implement MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
@ -57,7 +57,7 @@ typedef struct {
bool shutting_down;
pthread_t io_thread, talk_thread;
int talk_fd, listen_fd;
int talk_fd, listen_fd, prewarm_fd;
Message *messages;
size_t messages_capacity, messages_count;
LoopData io_loop_data;
@ -124,11 +124,11 @@ static PyObject *
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
ChildMonitor *self;
PyObject *dump_callback, *death_notify;
int talk_fd = -1, listen_fd = -1;
int talk_fd = -1, listen_fd = -1, prewarm_fd = -1;
int ret;
if (the_monitor) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; }
if (!PyArg_ParseTuple(args, "OO|ii", &death_notify, &dump_callback, &talk_fd, &listen_fd)) return NULL;
if (!PyArg_ParseTuple(args, "OO|iii", &death_notify, &dump_callback, &talk_fd, &listen_fd, &prewarm_fd)) return NULL;
if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) {
PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret));
return NULL;
@ -141,6 +141,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
if (!init_loop_data(&self->io_loop_data, SIGINT, SIGHUP, SIGTERM, SIGCHLD, SIGUSR1, SIGUSR2, 0)) return PyErr_SetFromErrno(PyExc_OSError);
self->talk_fd = talk_fd;
self->listen_fd = listen_fd;
self->prewarm_fd = prewarm_fd;
if (self == NULL) return PyErr_NoMemory();
self->death_notify = death_notify; Py_INCREF(death_notify);
if (dump_callback != Py_None) {
@ -149,7 +150,8 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
} else parse_func = parse_worker;
self->count = 0;
children_fds[0].fd = self->io_loop_data.wakeup_read_fd; children_fds[1].fd = self->io_loop_data.signal_read_fd;
children_fds[0].events = POLLIN; children_fds[1].events = POLLIN;
children_fds[2].fd = self->prewarm_fd;
children_fds[0].events = POLLIN; children_fds[1].events = POLLIN; children_fds[2].events = POLLIN;
the_monitor = self;
return (PyObject*) self;
@ -175,6 +177,7 @@ dealloc(ChildMonitor* self) {
FREE_CHILD(add_queue[add_queue_count]);
}
free_loop_data(&self->io_loop_data);
safe_close(self->prewarm_fd, __FILE__, __LINE__); self->prewarm_fd = -1;
Py_TYPE(self)->tp_free((PyObject*)self);
}
@ -1302,6 +1305,34 @@ mark_monitored_pids(pid_t pid, int status) {
children_mutex(unlock);
}
static void
reap_prewarmed_children(ChildMonitor *self, int fd, bool enable_close_on_child_death) {
static char buf[256];
static size_t buf_pos = 0;
while(true) {
ssize_t len = read(fd, buf + buf_pos, sizeof(buf) - buf_pos);
if (len < 0) {
if (errno == EINTR) continue;
if (errno != EIO && errno != EAGAIN) log_error("Call to read() from reap_prewarmed_children() failed with error: %s", strerror(errno));
break;
}
buf_pos += len;
char *nl;
while (buf_pos > 1 && (nl = memchr(buf, '\n', buf_pos)) != NULL) {
size_t sz = nl - buf;
if (enable_close_on_child_death) {
*nl = 0;
int pid = atoi(buf);
if (pid) mark_child_for_removal(self, pid);
}
memmove(buf, buf + sz, sz);
buf_pos -= sz;
}
if (len == 0) break;
}
}
static void
reap_children(ChildMonitor *self, bool enable_close_on_child_death) {
int status;
@ -1392,6 +1423,9 @@ io_loop(void *data) {
}
if (ss.child_died) reap_children(self, OPT(close_on_child_death));
}
if (children_fds[2].revents && POLLIN) {
reap_prewarmed_children(self, children_fds[2].fd, OPT(close_on_child_death));
}
for (i = 0; i < self->count; i++) {
if (children_fds[EXTRA_FDS + i].revents & (POLLIN | POLLHUP)) {
data_received = true;

View File

@ -1193,7 +1193,8 @@ class ChildMonitor:
death_notify: Callable[[int], None],
dump_callback: Optional[Callable[[bytes], None]],
talk_fd: int = -1,
listen_fd: int = -1
listen_fd: int = -1,
prewarm_fd: int = -1,
):
pass