aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2013-07-05 21:41:07 -0400
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2013-07-05 21:41:07 -0400
commit88b8c03a11e229b29cd985cabe51cb2ed3c24b55 (patch)
tree3a46690d182cd4aa34f50f011b4a7dd788b365d0
parent633bbb9f481cd72edb7c419941a366d0efbf88b6 (diff)
downloadegawk-88b8c03a11e229b29cd985cabe51cb2ed3c24b55.tar.gz
egawk-88b8c03a11e229b29cd985cabe51cb2ed3c24b55.tar.bz2
egawk-88b8c03a11e229b29cd985cabe51cb2ed3c24b55.zip
Enhance select signal function to return info about previous handler and decide whether to override when it is unknown.
-rw-r--r--extension/ChangeLog10
-rw-r--r--extension/select.c89
2 files changed, 84 insertions, 15 deletions
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 68ba6fe2..4bfc64d4 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,5 +1,15 @@
2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+ * select.c (signal_result): New function to set result string from
+ signal function and detect when we need to roll back.
+ (do_signal): Now takes an optional 3rd override argument. Instead
+ of returning -1 or 0, we now return information about the previously
+ installed signal handler: default, ignore, trap, or unknown. An
+ empty string is returned on error. If it is an unknown handler,
+ and override is not non-zero, we roll back the handler and return "".
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
* select.c (set_non_blocking): Do not attempt F_SETFL if F_GETFL fails.
(do_set_non_blocking): Add support for case when called with a single
"" argument.
diff --git a/extension/select.c b/extension/select.c
index 4d28457d..3bcef166 100644
--- a/extension/select.c
+++ b/extension/select.c
@@ -147,6 +147,25 @@ get_signal_number(awk_value_t signame)
}
}
+static awk_value_t *
+signal_result(awk_value_t *result, void (*func)(int))
+{
+ awk_value_t override;
+
+ if (func == SIG_DFL)
+ return make_const_string("default", 7, result);
+ if (func == SIG_IGN)
+ return make_const_string("ignore", 6, result);
+ if (func == signal_handler)
+ return make_const_string("trap", 4, result);
+ if (get_argument(2, AWK_NUMBER, & override) && override.num_value)
+ return make_const_string("unknown", 7, result);
+ /* need to roll it back! */
+ update_ERRNO_string(_("select_signal: override not requested for unknown signal handler"));
+ make_null_string(result);
+ return NULL;
+}
+
/* do_signal --- trap signals */
static awk_value_t *
@@ -156,17 +175,17 @@ do_signal(int nargs, awk_value_t *result)
int signum;
void (*func)(int);
- if (do_lint && nargs > 2)
+ if (do_lint && nargs > 3)
lintwarn(ext_id, _("select_signal: called with too many arguments"));
if (! get_argument(0, AWK_UNDEFINED, & signame)) {
update_ERRNO_string(_("select_signal: missing required signal name argument"));
- return make_number(-1, result);
+ return make_null_string(result);
}
if ((signum = get_signal_number(signame)) < 0)
- return make_number(-1, result);
+ return make_null_string(result);
if (! get_argument(1, AWK_STRING, & disposition)) {
update_ERRNO_string(_("select_signal: missing required signal disposition argument"));
- return make_number(-1, result);
+ return make_null_string(result);
}
if (strcasecmp(disposition.str_value.str, "default") == 0)
func = SIG_DFL;
@@ -176,29 +195,69 @@ do_signal(int nargs, awk_value_t *result)
func = signal_handler;
else {
update_ERRNO_string(_("select_signal: invalid disposition argument"));
- return make_number(-1, result);
+ return make_null_string(result);
}
+
+#ifdef HAVE_SIGPROCMASK
+/* Temporarily block this signal in case we need to roll back the handler! */
+#define PROTECT \
+ sigset_t set, oldset; \
+ sigemptyset(& set); \
+ sigaddset(& set, signum); \
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+#define RELEASE sigprocmask(SIG_SETMASK, &oldset, NULL);
+#else
+/* Brain-damaged platform, so we will have to live with the race condition. */
+#define PROTECT
+#define RELEASE
+#endif
+
#ifdef HAVE_SIGACTION
{
- int rc;
- struct sigaction sa;
+ awk_value_t override;
+ struct sigaction sa, prev;
sa.sa_handler = func;
sigfillset(& sa.sa_mask); /* block all signals in handler */
sa.sa_flags = SA_RESTART;
- if ((rc = sigaction(signum, &sa, NULL)) < 0)
- update_ERRNO_int(errno);
- return make_number(rc, result);
+ {
+ PROTECT
+ if (sigaction(signum, &sa, &prev) < 0) {
+ update_ERRNO_int(errno);
+ RELEASE
+ return make_null_string(result);
+ }
+ if (signal_result(result, prev.sa_handler)) {
+ RELEASE
+ return result;
+ }
+ /* roll it back! */
+ sigaction(signum, &prev, NULL);
+ RELEASE
+ return result;
+ }
}
#else
/*
* Fall back to signal; this is available on all platforms. We can
* only hope that it does the right thing.
*/
- if (signal(signum, func) == SIG_ERR) {
- update_ERRNO_int(errno);
- return make_number(-1, result);
+ {
+ void (*prev)(int);
+ PROTECT
+ if ((prev = signal(signum, func)) == SIG_ERR) {
+ update_ERRNO_int(errno);
+ RELEASE
+ return make_null_string(result);
+ }
+ if (signal_result(result, prev)) {
+ RELEASE
+ return result;
+ }
+ /* roll it back! */
+ signal(signum, prev);
+ RELEASE
+ return result;
}
- return make_number(0, result);
#endif
}
@@ -461,7 +520,7 @@ do_set_non_blocking(int nargs, awk_value_t *result)
static awk_ext_func_t func_table[] = {
{ "select", do_select, 5 },
- { "select_signal", do_signal, 2 },
+ { "select_signal", do_signal, 3 },
{ "set_non_blocking", do_set_non_blocking, 2 },
{ "kill", do_kill, 2 },
};