]> git.neil.brown.name Git - edlib.git/commitdiff
Change how SIGALRM interrupts python.
authorNeilBrown <neil@brown.name>
Fri, 15 Sep 2023 08:17:55 +0000 (18:17 +1000)
committerNeilBrown <neil@brown.name>
Fri, 15 Sep 2023 08:25:18 +0000 (18:25 +1000)
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 <neil@brown.name>
DOC/TODO.md
core-editor.c
core-keymap.c
core-pane.h
core.h
lang-python.c

index c48117d0fdff489b6f81f8b590d80292e21b8e1e..fd5352933da907059276838ebbcc41d8a19d0b58 100644 (file)
@@ -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
index c36eb2d7270fb74a55ba2d5a040633074246353a..9743689a0009b0b248e63568246faa6dc3ad2447 100644 (file)
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include <signal.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <dlfcn.h>
@@ -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;
 }
index fdcd0cf1a1b4342b70beb37df74de4151f753a0d..fb7101b0511c7e51b9879df5b045a6666446512a 100644 (file)
@@ -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
index b726acb3faa45490c3234828a192c0e6f85bdc3c..58e259ba5810995755aefa9cd83bef77f0e29fe2 100644 (file)
@@ -1,3 +1,5 @@
+#include <unistd.h>
+
 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 330df3b98f441cfe89c3179e46e00c27c5f95589..37d37e225a499ef8c26781a1fb1a366edaa30117 100644 (file)
--- 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,
index 0539fee1d6493aa1c337bf8630dae391fb6b51a6..1afdf27f92c71c9ee0feefde914ae5668591a944 100644 (file)
@@ -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");
 }