Allow SIGINT to raise KeyboardInterrupt under the "python" command. gdb/Changelog: 2012-07-16 Khoo Yit Phang Allow SIGINT to raise KeyboardInterrupt under the "python" command. * python/python-internal.h (gdbpy_suspend_sigint_handler): New prototype> * python/python.c (gdbpy_saved_sigint_handler): New variable. (gdbpy_handle_sigint): New function. (gdbpy_restore_sigint_handler): Ditto. (gdbpy_install_sigint_handler): Ditto. (gdbpy_resume_sigint_handler): Ditto. (gdbpy_suspend_sigint_handler): Ditto. (restore_python_env): Call gdbpy_install_sigint_handler. (ensure_python_env): Call gdbpy_restore_sigint_handler. (python_command): Move call to ensure_python_env closer to Python entry. (execute_gdb_command): Call gdbpy_suspend_sigint_handler. diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -104,6 +104,8 @@ #include "exceptions.h" +struct cleanup *gdbpy_suspend_sigint_handler (void); + enum gdbpy_iter_kind { iter_keys, iter_values, iter_items }; struct block; diff --git a/gdb/python/python.c b/gdb/python/python.c --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -97,6 +97,64 @@ struct gdbarch *python_gdbarch; const struct language_defn *python_language; +/* When entering Python, install a Python-specific SIGINT handler; + restore the original handler upon exit. A global variable is + used to save GDB's SIGINT handler, such that any changes to the + SIGINT handler in a nested GDB context will propagate to the + outer GDB context, which is not necessarily the old SIGINT + handler. */ + +static sig_t gdbpy_saved_sigint_handler; + +/* SIGINT handler for Python. */ + +static void +gdbpy_handle_sigint (int sig) +{ + signal (SIGINT, gdbpy_handle_sigint); + PyErr_SetInterrupt (); +} + +/* Restore the saved SIGINT handler for GDB before returning from + Python. */ + +static void +gdbpy_restore_sigint_handler (void) +{ + signal (SIGINT, gdbpy_saved_sigint_handler); +} + +/* Save the SIGINT handler for GDB before entering Python, and install + the Python SIGINT handler. */ + +static void +gdbpy_install_sigint_handler (void) +{ + gdbpy_saved_sigint_handler = signal (SIGINT, gdbpy_handle_sigint); +} + +/* Cleanup function that restores the Python SIGINT handler. Note that + this propagates the current SIGINT handler for GDB down to the + outer GDB context. */ + +static void +gdbpy_resume_sigint_handler (void *s) +{ + gdbpy_install_sigint_handler (); +} + +/* Temporarily suspend the Python SIGINT handler and restore the + saved SIGINT handler for GDB before entering GDB. (Currently, only + called by gdb.execute since it's most likely to take a long + time.) */ + +struct cleanup * +gdbpy_suspend_sigint_handler (void) +{ + gdbpy_restore_sigint_handler (); + return make_cleanup (gdbpy_resume_sigint_handler, NULL); +} + /* Restore global language and architecture and Python GIL state when leaving the Python interpreter. */ @@ -123,6 +181,8 @@ PyErr_Restore (env->error_type, env->error_value, env->error_traceback); + gdbpy_restore_sigint_handler (); + PyGILState_Release (env->state); python_gdbarch = env->gdbarch; python_language = env->language; @@ -142,6 +202,8 @@ env->gdbarch = python_gdbarch; env->language = python_language; + gdbpy_install_sigint_handler (); + python_gdbarch = gdbarch; python_language = language; @@ -322,15 +384,15 @@ { struct cleanup *cleanup; - cleanup = ensure_python_env (get_current_arch (), current_language); - - make_cleanup_restore_integer (&interpreter_async); + cleanup = make_cleanup_restore_integer (&interpreter_async); interpreter_async = 0; while (arg && *arg && isspace (*arg)) ++arg; if (arg && *arg) { + ensure_python_env (get_current_arch (), current_language); + if (PyRun_SimpleString (arg)) error (_("Error while executing Python code.")); } @@ -503,6 +565,7 @@ char *copy = xstrdup (arg); struct cleanup *cleanup = make_cleanup (xfree, copy); + gdbpy_suspend_sigint_handler (); make_cleanup_restore_integer (&interpreter_async); interpreter_async = 0;