From fab723b9bcd1bbfed4e4b39916ae14cfeb59c0e4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 31 Jan 2019 19:30:40 +0530 Subject: [PATCH] Manage timer callback reference counts --- kitty/child-monitor.c | 9 ++++++++- kitty/timers.c | 32 +++++++++++++++++++++----------- kitty/timers.h | 5 ++++- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 103d16e02..04ebfcb0b 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -747,13 +747,19 @@ python_timer_callback(id_type timer_id, void *data) { else Py_DECREF(ret); } +static void +python_timer_cleanup(id_type timer_id UNUSED, void *data) { + if (data) Py_DECREF((PyObject*)data); +} + static PyObject* add_python_timer(PyObject *self UNUSED, PyObject *args) { PyObject *callback; double interval; const char *name; if (!PyArg_ParseTuple(args, "sOd", &name, &callback, &interval)) return NULL; - unsigned long long timer_id = add_timer(&main_event_loop, name, interval, 1, python_timer_callback, callback); + unsigned long long timer_id = add_timer(&main_event_loop, name, interval, 1, python_timer_callback, callback, python_timer_cleanup); + Py_INCREF(callback); return Py_BuildValue("K", timer_id); } @@ -860,6 +866,7 @@ main_loop(ChildMonitor *self, PyObject *a UNUSED) { } has_open_windows = process_pending_closes(self); } + remove_all_timers(&main_event_loop); if (PyErr_Occurred()) return NULL; Py_RETURN_NONE; } diff --git a/kitty/timers.c b/kitty/timers.c index 1b8e646a6..16f988b1a 100644 --- a/kitty/timers.c +++ b/kitty/timers.c @@ -22,7 +22,7 @@ update_timers(EventLoopData *eld) { } id_type -add_timer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data) { +add_timer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data, timer_cleanup_func cleanup) { if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) { fprintf(stderr, "Too many timers added\n"); return 0; @@ -33,24 +33,34 @@ add_timer(EventLoopData *eld, const char *name, double interval, int enabled, ti t->trigger_at = enabled ? monotonic() + interval : DBL_MAX; t->callback = cb; t->callback_data = cb_data; + t->cleanup = cleanup; t->id = ++timer_counter; update_timers(eld); return t->id; } -#define removeX(which, item_id, update_func) {\ - for (nfds_t i = 0; i < eld->which##_count; i++) { \ - if (eld->which[i].id == item_id) { \ - eld->which##_count--; \ - if (i < eld->which##_count) { \ - memmove(eld->which + i, eld->which + i + 1, sizeof(eld->which[0]) * (eld->which##_count - i)); \ - } \ - update_func(eld); break; \ -}}} void remove_timer(EventLoopData *eld, id_type timer_id) { - removeX(timers, timer_id, update_timers); + for (nfds_t i = 0; i < eld->timers_count; i++) { + if (eld->timers[i].id == timer_id) { + if (eld->timers[i].cleanup) eld->timers[i].cleanup(timer_id, eld->timers[i].callback_data); + eld->timers_count--; + if (i < eld->timers_count) { + memmove(eld->timers + i, eld->timers + i + 1, sizeof(eld->timers[0]) * (eld->timers_count - i)); + } + update_timers(eld); + break; + } + } +} + +void +remove_all_timers(EventLoopData *eld) { + while (eld->timers_count) { + eld->timers_count--; + if (eld->timers[eld->timers_count].cleanup) eld->timers[eld->timers_count].cleanup(eld->timers[eld->timers_count].id, eld->timers[eld->timers_count].callback_data); + } } void diff --git a/kitty/timers.h b/kitty/timers.h index cd47cdb9e..b0260a538 100644 --- a/kitty/timers.h +++ b/kitty/timers.h @@ -9,11 +9,13 @@ #include "data-types.h" typedef void(*timer_callback_func)(id_type, void*); +typedef void(*timer_cleanup_func)(id_type, void*); typedef struct { id_type id; double interval, trigger_at; timer_callback_func callback; + timer_cleanup_func cleanup; void *callback_data; const char *name; } Timer; @@ -26,8 +28,9 @@ typedef struct { double prepare_for_poll(EventLoopData *eld, double timeout); -id_type add_timer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data); +id_type add_timer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data, timer_cleanup_func cleanup); void remove_timer(EventLoopData *eld, id_type timer_id); +void remove_all_timers(EventLoopData *eld); void toggle_time(EventLoopData *eld, id_type timer_id, int enabled); void change_timer_interval(EventLoopData *eld, id_type timer_id, double interval); unsigned int dispatch_timers(EventLoopData *eld);