aboutsummaryrefslogtreecommitdiff
path: root/jim-signal.c
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2010-03-03 15:50:50 +1000
committerSteve Bennett <steveb@workware.net.au>2010-10-15 11:02:48 +1000
commit6a9fcd338b28fe76cb980867632068dd2bec533c (patch)
tree7e4046bd5d6ae0fa018dcfc51208c010b00ef472 /jim-signal.c
parentec3d0d6cfddfa055d00c820a2ed99a7d6858aa82 (diff)
downloadjimtcl-6a9fcd338b28fe76cb980867632068dd2bec533c.zip
jimtcl-6a9fcd338b28fe76cb980867632068dd2bec533c.tar.gz
jimtcl-6a9fcd338b28fe76cb980867632068dd2bec533c.tar.bz2
Improvements to catch, return, signal, try
Improve the ability to rethrow errors * Allow return to rethrow an error by accepting '-errorinfo stacktrace' * Also, 'catch ... opts' now also stores opts(-errorinfo) on error * Use these to provide better stack traces from 'case' and 'try' * Implement 'return -level' Make try/on/finally more Tcl 8.6 compatible * With support for 'on' handlers and docs Add support for catch options to try * Otherwise it's hard to use try to catch signals Improvements to signal handling * catch -signal now sets a list of the handled signals as the result * catch -signal won't execute the body at all if a handled signal is pending * up to 64 (jim_wide) signals can now be handled * if catch -signal is nested, the innermost catch will catch the error * new 'signal catch' allows ignored/blocked signals to be examined and cleared. * update docs on signal handling exec should indicate which signal killed the child Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'jim-signal.c')
-rw-r--r--jim-signal.c98
1 files changed, 82 insertions, 16 deletions
diff --git a/jim-signal.c b/jim-signal.c
index e55134c..0760026 100644
--- a/jim-signal.c
+++ b/jim-signal.c
@@ -10,26 +10,30 @@
#include "jim.h"
#include "jim-subcmd.h"
+#include "jim-signal.h"
-#define MAX_SIGNALS 32
+#define MAX_SIGNALS (sizeof(jim_wide) * 8)
-static int *sigloc;
-static unsigned long sigsblocked;
+static jim_wide *sigloc;
+static jim_wide sigsblocked;
static struct sigaction *sa_old;
static int signal_handling[MAX_SIGNALS];
+/* Make sure to do this as a wide, not int */
+#define sig_to_bit(SIG) ((jim_wide)1 << (SIG))
+
static void signal_handler(int sig)
{
- /* We just remember which signal occurred. Jim_Eval() will
+ /* We just remember which signals occurred. Jim_Eval() will
* notice this as soon as it can and throw an error
*/
- *sigloc = sig;
+ *sigloc |= sig_to_bit(sig);
}
static void signal_ignorer(int sig)
{
/* We just remember which signals occurred */
- sigsblocked |= (1 << sig);
+ sigsblocked |= sig_to_bit(sig);
}
/*
@@ -227,11 +231,6 @@ static int do_signal_cmd(Jim_Interp *interp, int action, int argc, Jim_Obj *cons
return JIM_OK;
}
- /* Make sure we know where to store the signals which occur */
- if (!sigloc) {
- sigloc = &interp->signal;
- }
-
/* Catch all the signals we care about */
if (action != SIGNAL_ACTION_DEFAULT) {
sa.sa_flags = 0;
@@ -295,6 +294,59 @@ static int signal_cmd_default(Jim_Interp *interp, int argc, Jim_Obj *const *argv
return do_signal_cmd(interp, SIGNAL_ACTION_DEFAULT, argc, argv);
}
+static int signal_set_sigmask_result(Jim_Interp *interp, jim_wide sigmask)
+{
+ int i;
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = 0; i < MAX_SIGNALS; i++) {
+ if (sigmask & sig_to_bit(i)) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, Jim_SignalId(i), -1));
+ }
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
+static int signal_cmd_check(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int clear = 0;
+ jim_wide mask = 0;
+ jim_wide blocked;
+
+ if (argc > 0 && Jim_CompareStringImmediate(interp, argv[0], "-clear")) {
+ clear++;
+ }
+ if (argc > clear) {
+ int i;
+
+ /* Signals specified */
+ for (i = clear; i < argc; i++) {
+ int sig = find_signal_by_name(interp, Jim_GetString(argv[i], NULL));
+ if (sig < 0 || sig >= MAX_SIGNALS) {
+ return -1;
+ }
+ mask |= sig_to_bit(sig);
+ }
+ }
+ else {
+ /* No signals specified, so check/clear all */
+ mask = ~mask;
+ }
+
+ if ((sigsblocked & mask) == 0) {
+ /* No matching signals, so empty result and nothing to do */
+ return JIM_OK;
+ }
+ /* Be careful we don't have a race condition where signals are cleared but not returned */
+ blocked = sigsblocked & mask;
+ if (clear) {
+ sigsblocked &= ~blocked;
+ }
+ /* Set the result */
+ signal_set_sigmask_result(interp, blocked);
+ return JIM_OK;
+}
+
static int signal_cmd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
int sig = SIGINT;
@@ -304,13 +356,17 @@ static int signal_cmd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}
}
+ /* If the signal is ignored (blocked) ... */
+ if (signal_handling[sig] == SIGNAL_ACTION_IGNORE) {
+ sigsblocked |= sig_to_bit(sig);
+ return JIM_OK;
+ }
+
/* Just set the signal */
- interp->signal = sig;
+ interp->sigmask |= sig_to_bit(sig);
-#if 1
/* Set the canonical name of the signal as the result */
Jim_SetResultString(interp, Jim_SignalId(sig), -1);
-#endif
/* And simply say we caught the signal */
return JIM_SIGNAL;
@@ -361,6 +417,13 @@ static const jim_subcmd_type signal_command_table[] = {
.maxargs = -1,
.description = "Lists defaulted signals, or adds to defaulted signals"
},
+ { .cmd = "check",
+ .args = "?-clear? ?signals ...?",
+ .function = signal_cmd_check,
+ .minargs = 0,
+ .maxargs = -1,
+ .description = "Returns ignored signals which have occurred, and optionally clearing them"
+ },
{ .cmd = "throw",
.args = "?signal?",
.function = signal_cmd_throw,
@@ -479,8 +542,11 @@ int Jim_signalInit(Jim_Interp *interp)
if (Jim_PackageProvide(interp, "signal", "1.0", JIM_ERRMSG) != JIM_OK) {
return JIM_ERR;
}
- /* Teach the jim core how to convert signal values to names */
- interp->signal_to_name = Jim_SignalId;
+ /* Teach the jim core how to set a result from a sigmask */
+ interp->signal_set_result = signal_set_sigmask_result;
+
+ /* Make sure we know where to store the signals which occur */
+ sigloc = &interp->sigmask;
Jim_CreateCommand(interp, "signal", Jim_SubCmdProc, (void *)signal_command_table, NULL);
Jim_CreateCommand(interp, "alarm", Jim_AlarmCmd, 0, 0);