From: NeilBrown Date: Fri, 15 Sep 2023 08:17:55 +0000 (+1000) Subject: Change how SIGALRM interrupts python. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=44b01f161b6d3240f0fc27839c083f49f9df8348;p=edlib.git Change how SIGALRM interrupts python. Rather than setting an resetting alarm(), set the alarm() once and set/clear a flag to say if python is running. Then interrupt python only if it is running. Signed-off-by: NeilBrown --- diff --git a/DOC/TODO.md b/DOC/TODO.md index c48117d0..fd535293 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -89,7 +89,7 @@ Core features - [ ] If a pane wants to block mouse events from parents, as lib-view does, it shouldn't need to catch all the combinations, or it should be much easier -- [ ] gather memory usage stats per-pane and allow a dump +- [ ] gather memory usage stats per-pane, ensure 0 on close, and allow a dump - [ ] show doc size in doc list - include undo size? - [X] Ensure all panes that should use "Free" properly, and find some way to encourage its use. @@ -137,7 +137,7 @@ Core features - [ ] design a way for a keystroke to interrupt a long-running function. - [ ] extend Draw:measure protocol to allow constant-width-fonts to cannot-scale displays can be detected and measurement optimised for. -- [ ] improve timeout. Set timer once, then set a flag so that all commands fail +- [X] improve timeout. Set timer once, then set a flag so that all commands fail until some top-level clears the flag. - [ ] reconsider all 'return comm_call()' calls. Do we every really care if the callback succeeded? @@ -171,6 +171,7 @@ Core features the call which gave access to it, unless it registers for notifications from the owner, and that probably only applies to points. +- [ ] do something useful on SIGINT - maybe expedite times_up(). ### Longer term @@ -182,7 +183,7 @@ Core features - [ ] support $SUBST in file-open path names ?? - [ ] Need a debug mode where every mark usage is checked for validity. also check the setref sets up all linkages. -- [ ] remove all FIXMEs (there are 65) ... and any HACKs (2). +- [ ] remove all FIXMEs (there are 77) ... and any HACKs (5). - [ ] Replace asserts with warnings where possible. - [ ] hide view-num inside pane so number cannot be misused. i.e. each view is owned by a pane and can only be used by that pane. @@ -369,7 +370,8 @@ Module features ### pygtk -- [ ] can we capture the substates of character composition, and give feed-back? +- [ ] can we capture the substates of character composition, and give + feed-back? ### display-x11-xcb @@ -413,7 +415,7 @@ Module features ### lib-macro -- [ ] don't allow starting macro inside a macro +- [X] don't allow starting macro inside a macro - [ ] detect errors including Abort and search failure etc. Abort capture or replay on error - [ ] Possibly wait for a shell-command etc to complete before continuing. @@ -443,7 +445,7 @@ Module features - [ ] things slow down after lots of edits. Maybe track number of chunk, marks, undos etc and display them somewhere - [ ] stop consistency checking a doc when it gets "big" ?? -- [ ] avoid infinite loops in consistency checks +- [X] avoid infinite loops in consistency checks - [ ] doc-text: opening file with e.g. 200,000 lines is very slow Check this.. - [ ] moving in a big file is slow - check this @@ -780,7 +782,7 @@ Module features ### lang-python - [ ] review python doc:char implementations for simplification. -- [ ] repeated alarm(10)/alarm(0) calls slow things down +- [X] repeated alarm(10)/alarm(0) calls slow things down - [ ] array index should allow two args, second being a mark for doc:get-attr etc. - [ ] should be able to test if a mark is NULL or Freed diff --git a/core-editor.c b/core-editor.c index c36eb2d7..9743689a 100644 --- a/core-editor.c +++ b/core-editor.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -202,7 +203,11 @@ DEF_CMD(editor_load_module) return 1; } #endif - if (key_lookup_prefix(map, ci) > 0) + /* Multiple modules can support module lookup, such as + * global-load-modules:python or global-load-module:lua. + * So do a prefix lookup. + */ + if (key_lookup_prefix(map, ci, False) > 0) return 1; LOG("Failed to load module: %s", name); return Efail; @@ -216,7 +221,7 @@ DEF_CMD(editor_auto_event) */ struct ed_info *ei = ci->home->data; struct map *map = ei->map; - int ret = key_lookup_prefix(map, ci); + int ret = key_lookup_prefix(map, ci, False); if (ret) return ret; @@ -224,7 +229,7 @@ DEF_CMD(editor_auto_event) /* pointless to autoload for refresh */ return Efallthrough; call("attach-libevent", ci->home); - return key_lookup_prefix(map, ci); + return key_lookup_prefix(map, ci, False); } DEF_CMD(editor_activate_display) @@ -278,7 +283,7 @@ DEF_CMD(editor_multicall) const char *key = ci->key; ((struct cmd_info*)ci)->key = ksuffix(ci, "global-multicall-"); - ret = key_lookup_prefix(map, ci); + ret = key_lookup_prefix(map, ci, False); ((struct cmd_info*)ci)->key = key; return ret; } @@ -686,6 +691,32 @@ DEF_CMD(global_find_file) return Efalse; } +static struct pane *editor; +static void catch(int sig) +{ + struct cmd_info ci; + if (!editor) + return; + signal(sig, catch); + ci.home = editor; + ci.focus = editor; + ci.num = sig; + ci.num2 = 0; + ci.str = ci.str2 = NULL; + ci.mark = ci.mark2 = NULL; + ci.x = ci.y = 0; + switch (sig) { + case SIGALRM: + ci.key = "fast-alarm-"; + key_lookup_prefix(editor->data->map, &ci, True); + break; + case SIGINT: + ci.key = "fast-interrupt-"; + key_lookup_prefix(editor->data->map, &ci, True); + break; + } +} + struct pane *editor_new(const char *comm_name) { struct pane *ed; @@ -728,5 +759,9 @@ struct pane *editor_new(const char *comm_name) log_setup(ed); window_setup(ed); + signal(SIGINT, catch); + signal(SIGALRM, catch); + + editor = ed; return ed; } diff --git a/core-keymap.c b/core-keymap.c index fdcd0cf1..fb7101b0 100644 --- a/core-keymap.c +++ b/core-keymap.c @@ -491,8 +491,12 @@ int key_lookup(struct map *m safe, const struct cmd_info *ci safe) } } -int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe) +int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe, + bool simple) { + /* A "Simple" lookup avoids the backtrace. It is used in + * signal handlers. + */ const char *k = ci->key; int len = strlen(k); int pos = key_find(m, k); @@ -508,7 +512,10 @@ int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe) if (comm && comm != prev) { ((struct cmd_info*)ci)->comm = comm; ((struct cmd_info*)ci)->key = m->keys[pos+i]; - ret = do_comm_call(comm, ci); + if (simple) + ret = comm->func(ci); + else + ret = do_comm_call(comm, ci); ASSERT(ret >= Efallthrough || ret < Eunused); prev = comm; /* something might have been added, recalc diff --git a/core-pane.h b/core-pane.h index b726acb3..58e259ba 100644 --- a/core-pane.h +++ b/core-pane.h @@ -1,3 +1,5 @@ +#include + struct pane { const char *name; /* For easy discovery in gdb */ struct pane *parent safe; @@ -69,10 +71,12 @@ static inline struct pane * safe pane_root(struct pane *p safe) static inline void time_starts(struct pane *p safe) { pane_set_time(pane_root(p)); + alarm(15); } static inline void time_ends(struct pane *p safe) { + alarm(0); pane_end_time(pane_root(p)); } diff --git a/core.h b/core.h index 330df3b9..37d37e22 100644 --- a/core.h +++ b/core.h @@ -406,7 +406,8 @@ struct map *safe key_alloc(void); void key_free(struct map *m safe); int key_handle(const struct cmd_info *ci safe); int key_lookup(struct map *m safe, const struct cmd_info *ci safe); -int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe); +int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe, + bool simple); struct command *key_lookup_cmd(struct map *m safe, const char *c safe); void key_add(struct map *map safe, const char *k safe, struct command *comm); void key_add_range(struct map *map safe, diff --git a/lang-python.c b/lang-python.c index 0539fee1..1afdf27f 100644 --- a/lang-python.c +++ b/lang-python.c @@ -453,12 +453,12 @@ static int dict_add(PyObject *kwds, char *name, PyObject *val) return 1; } -static void python_interrupt(int sig) +static bool python_running; +DEF_CB(handle_alarm) { - /* Python code has been running for too long, - * interrupt it. - */ - kill(getpid(), 2); + if (python_running) + PyErr_SetInterrupt(); + return 1; } REDEF_CB(python_call) @@ -516,11 +516,9 @@ REDEF_CB(python_call) Py_BuildValue("ii", ci->x, ci->y)); if (rv && pc->callable) { - signal(SIGALRM, python_interrupt); - alarm(10); + python_running = True; ret = PyObject_Call(pc->callable, args, kwds); - alarm(0); - signal(SIGALRM, SIG_DFL); + python_running = False; } Py_DECREF(args); @@ -1172,8 +1170,6 @@ static PyObject *Pane_call(Pane *self safe, PyObject *args safe, PyObject *kwds) int rv; PyObject *s1, *s2; struct pyret pr; - int remain; - sighandler_t oldhan; if (!pane_valid(self)) return NULL; @@ -1187,13 +1183,9 @@ static PyObject *Pane_call(Pane *self safe, PyObject *args safe, PyObject *kwds) return NULL; } - remain = alarm(0); - oldhan = signal(SIGALRM, SIG_DFL); + python_running = False; rv = key_handle(&ci); - if (oldhan != SIG_DFL) { - signal(SIGALRM, oldhan); - alarm(remain); - } + python_running = True; /* Just in case ... */ PyErr_Clear(); @@ -2950,17 +2942,25 @@ void edlib_init(struct pane *ed safe) PyObject *m; PyConfig config; char *argv[2]= { "edlib", NULL }; + sighandler_t sigint; if (edlib_module_path) module_dir = strdup(edlib_module_path); else module_dir = "."; + /* de-register SIGINT while we initialise python, + * so that Python thinks that it's registration is + * valid - so PyErr_SetInterrupt() don't think there + * is a race. + */ + sigint = signal(SIGINT, SIG_DFL); PyConfig_InitPythonConfig(&config); config.isolated = 1; PyConfig_SetBytesArgv(&config, 0, argv); Py_InitializeFromConfig(&config); PyConfig_Clear(&config); + signal(SIGINT, sigint); PaneType.tp_new = PyType_GenericNew; PaneIterType.tp_new = PyType_GenericNew; @@ -3030,6 +3030,9 @@ void edlib_init(struct pane *ed safe) EdlibModule = m; ed_pane = ed; + call_comm("global-set-command", ed, &handle_alarm, + 0, NULL, "fast-alarm-python"); + call_comm("global-set-command", ed, &python_load_module, 0, NULL, "global-load-modules:python"); }