diff --git a/kitty/boss.py b/kitty/boss.py index 879a84c5a..9cc974b1c 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -3,7 +3,6 @@ # License: GPL v3 Copyright: 2016, Kovid Goyal from gettext import gettext as _ -from threading import Thread from time import monotonic from weakref import WeakValueDictionary @@ -82,12 +81,11 @@ class DumpCommands: # {{{ # }}} -class Boss(Thread): +class Boss: daemon = True def __init__(self, glfw_window, opts, args): - Thread.__init__(self, name='ChildMonitor') self.window_id_map = WeakValueDictionary() startup_session = create_session(opts, args) self.cursor_blink_zero_time = monotonic() @@ -169,8 +167,10 @@ class Boss(Thread): for window in tab: self.close_window(window) - def run(self): - self.child_monitor.loop() + def start(self): + if not getattr(self, 'io_thread_started', False): + self.child_monitor.start() + self.io_thread_started = True def on_window_resize(self, window, w, h): # debounce resize events @@ -423,7 +423,7 @@ class Boss(Thread): self.shutting_down = True self.child_monitor.shutdown() wakeup() - self.join() + self.child_monitor.join() for t in self.tab_manager: t.destroy() del self.tab_manager diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index bac5584c7..1175184c3 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -5,10 +5,15 @@ * Distributed under terms of the GPL3 license. */ +#ifndef __APPLE__ +// Need _GNU_SOURCE for pthread_setname_np on linux +#define _GNU_SOURCE +#endif +#include +#undef _GNU_SOURCE #include "data-types.h" #include #include -#include #include #include @@ -151,6 +156,25 @@ wakeup_(int fd) { } } +static void* io_loop(void *data); + +static PyObject * +start(ChildMonitor *self) { +#define start_doc "start() -> Start the I/O thread" + int ret = pthread_create(&self->io_thread, NULL, io_loop, self); + if (ret != 0) return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} + +static PyObject * +join(ChildMonitor *self) { +#define join_doc "join() -> Wait for the I/O thread to finish" + int ret = pthread_join(self->io_thread, NULL); + if (ret != 0) return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} + + static PyObject * wakeup(ChildMonitor UNUSED *self) { #define wakeup_doc "wakeup() -> wakeup the ChildMonitor I/O thread, forcing it to exit from poll() if it is waiting there." @@ -396,15 +420,21 @@ write_to_child(int fd, Screen *screen) { screen_mutex(unlock, write); } -static PyObject * -loop(ChildMonitor *self) { -#define loop_doc "loop() -> The monitor loop." +static void* +io_loop(void *data) { + // The I/O thread loop size_t i; int ret; bool has_more, data_received; Screen *screen; + ChildMonitor *self = (ChildMonitor*)data; + +#ifdef __APPLE__ + pthread_setname_np("ChildMonitor"); +#else + pthread_setname_np(self->io_thread, "ChildMonitor"); +#endif - Py_BEGIN_ALLOW_THREADS; while (LIKELY(!self->shutting_down)) { children_mutex(lock); remove_children(self); @@ -455,8 +485,7 @@ loop(ChildMonitor *self) { remove_children(self); for (i = 0; i < EXTRA_FDS; i++) close(fds[i].fd); children_mutex(unlock); - Py_END_ALLOW_THREADS; - Py_RETURN_NONE; + return 0; } // }}} @@ -464,7 +493,8 @@ loop(ChildMonitor *self) { static PyMethodDef methods[] = { METHOD(add_child, METH_VARARGS) METHOD(needs_write, METH_VARARGS) - METHOD(loop, METH_NOARGS) + METHOD(start, METH_NOARGS) + METHOD(join, METH_NOARGS) METHOD(wakeup, METH_NOARGS) METHOD(shutdown, METH_NOARGS) METHOD(parse_input, METH_NOARGS) diff --git a/kitty/data-types.h b/kitty/data-types.h index 9a01f9b75..e86ef40bf 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -284,6 +284,7 @@ typedef struct { double repaint_delay; unsigned int count; bool shutting_down; + pthread_t io_thread; } ChildMonitor; PyTypeObject ChildMonitor_Type;