gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, select, updated. gawk-4.1.0-55-ge3d803e


From: Andrew J. Schorr
Subject: [gawk-diffs] [SCM] gawk branch, select, updated. gawk-4.1.0-55-ge3d803e
Date: Mon, 01 Jul 2013 18:10:40 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, select has been updated
       via  e3d803ece7400aeb61e9577346e3de93ae2afccb (commit)
      from  6959e2ab216aeb1d5d8f07ce73cd8b9894b83006 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=e3d803ece7400aeb61e9577346e3de93ae2afccb

commit e3d803ece7400aeb61e9577346e3de93ae2afccb
Author: Andrew J. Schorr <address@hidden>
Date:   Mon Jul 1 14:09:49 2013 -0400

    Add signal trapping support to the select extension.

diff --git a/extension/ChangeLog b/extension/ChangeLog
index 37cfccf..e4dcf00 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,13 @@
+2013-07-01         Andrew J. Schorr     <address@hidden>
+
+       * siglist.h: New file copied from glibc to provide a mapping between
+       signal number and name.
+       * select.c: Add a new "select_signal" function and provide support
+       for trapping signals.
+       (do_select): Add support for a 5th argument to contain an array
+       of returned signals.  Improve the argument processing, and add
+       better warning messages.
+
 2013-06-30         Andrew J. Schorr     <address@hidden>
 
        * Makefile.am (pkgextension_LTLIBRARIES): Add select.la.
diff --git a/extension/select.c b/extension/select.c
index f74ae25..8729a59 100644
--- a/extension/select.c
+++ b/extension/select.c
@@ -58,7 +58,138 @@ int plugin_is_GPL_compatible;
 #include <signal.h>
 #endif
 
-/*  do_ord --- return numeric value of first char of string */
+static const char *const signum2name[] = {
+#define init_sig(A, B, C) [A] = B,
+#include "siglist.h"
+#undef init_sig
+};
+#define NUMSIG sizeof(signum2name)/sizeof(signum2name[0])
+
+#define MIN_VALID_SIGNAL       1               /* 0 is not allowed! */
+/*
+ * We would like to use NSIG, but I think this seems to be a BSD'ism that is 
not
+ * POSIX-compliant.  It is used internally by glibc, but not always
+ * available.  We add a buffer to the maximum number in the provided mapping
+ * in case the list is not comprehensive:
+ */
+#define MAX_VALID_SIGNAL       (NUMSIG+100)
+#define IS_VALID_SIGNAL(X) \
+       (((X) >= MIN_VALID_SIGNAL) && ((X) <= MAX_VALID_SIGNAL))
+
+static int
+signame2num(const char *name)
+{
+       size_t i;
+
+       if (strncasecmp(name, "sig", 3) == 0)
+               /* skip "sig" prefix */
+               name += 3;
+       for (i = MIN_VALID_SIGNAL; i < NUMSIG; i++) {
+               if (signum2name[i] && ! strcasecmp(signum2name[i], name))
+                       return i;
+       }
+       return -1;
+}
+
+static volatile struct {
+   int flag;
+   sigset_t mask;
+} caught;
+
+static void
+signal_handler(int signum)
+{
+       /*
+        * All signals should be blocked, so we do not have to worry about
+        * whether sigaddset is thread-safe.  It is documented to be
+        * async-signal-safe.
+        */
+       sigaddset(& caught.mask, signum);
+       caught.flag = 1;
+}
+
+static int
+integer_string(const char *s, long *x)
+{
+       char *endptr;
+
+       *x = strtol(s, & endptr, 10);
+       return ((endptr != s) && (*endptr == '\0')) ? 0 : -1;
+}
+
+static int
+get_signal_number(awk_value_t signame)
+{
+       int x;
+
+       switch (signame.val_type) {
+       case AWK_NUMBER:
+               x = signame.num_value;
+               if ((x != signame.num_value) || ! IS_VALID_SIGNAL(x)) {
+                       update_ERRNO_string(_("select_signal: invalid signal 
number"));
+                       return -1;
+               }
+               return x;
+       case AWK_STRING:
+               if ((x = signame2num(signame.str_value.str)) >= 0)
+                       return x;
+               {
+                       long z;
+                       if ((integer_string(signame.str_value.str, &z) == 0) && 
IS_VALID_SIGNAL(z))
+                               return z;
+               }
+               update_ERRNO_string(_("select_signal: invalid signal name"));
+               return -1;
+       default:
+               update_ERRNO_string(_("select_signal: signal name argument must 
be string or numeric"));
+               return -1;
+       }
+}
+
+/*  do_signal --- trap signals */
+
+static awk_value_t *
+do_signal(int nargs, awk_value_t *result)
+{
+#ifdef HAVE_SIGACTION
+       awk_value_t signame, disposition;
+       int signum;
+       struct sigaction sa;
+
+       if (! get_argument(0, AWK_UNDEFINED, & signame)) {
+               update_ERRNO_string(_("select_signal: missing required signal 
name argument"));
+               return make_number(-1, result);
+       }
+       if ((signum = get_signal_number(signame)) < 0)
+               return make_number(-1, result);
+       if (! get_argument(1, AWK_STRING, & disposition)) {
+               update_ERRNO_string(_("select_signal: missing required signal 
disposition argument"));
+               return make_number(-1, result);
+       }
+       if (strcasecmp(disposition.str_value.str, "default") == 0)
+               sa.sa_handler = SIG_DFL;
+       else if (strcasecmp(disposition.str_value.str, "ignore") == 0)
+               sa.sa_handler = SIG_IGN;
+       else if (strcasecmp(disposition.str_value.str, "trap") == 0)
+               sa.sa_handler = signal_handler;
+       else {
+               update_ERRNO_string(_("select_signal: invalid disposition 
argument"));
+               return make_number(-1, result);
+       }
+       sigfillset(& sa.sa_mask);       /* block all signals in handler */
+       sa.sa_flags = SA_RESTART;
+       if (sigaction(signum, &sa, NULL) < 0) {
+               update_ERRNO_int(errno);
+               return make_number(-1, result);
+       }
+       return make_number(0, result);
+#else
+       update_ERRNO_string(_("select_signal: not supported on this platform"));
+       return make_number(-1, result);
+#endif
+}
+
+/*  do_select --- I/O multiplexing */
 
 static awk_value_t *
 do_select(int nargs, awk_value_t *result)
@@ -76,11 +207,23 @@ do_select(int nargs, awk_value_t *result)
        struct timeval *timeout;
        int nfds = 0;
        int rc;
+       awk_value_t sigarr;
+       int dosig = 0;
 
        if (do_lint && nargs > 5)
                lintwarn(ext_id, _("select: called with too many arguments"));
 
 #define EL     fds[i].flat->elements[j]
+       if (nargs == 5) {
+               dosig = 1;
+               if (! get_argument(4, AWK_ARRAY, &sigarr)) {
+                       warning(ext_id, _("select: the signal argument must be 
an array"));
+                       update_ERRNO_string(_("select: bad signal parameter"));
+                       return make_number(-1, result);
+               }
+               clear_array(sigarr.array_cookie);
+       }
+
        for (i = 0; i < sizeof(fds)/sizeof(fds[0]); i++) {
                size_t j;
 
@@ -99,19 +242,33 @@ do_select(int nargs, awk_value_t *result)
                                case AWK_NUMBER:
                                        if (EL.index.num_value >= 0)
                                                fds[i].array2fd[j] = 
EL.index.num_value;
-                                       if (fds[i].array2fd[j] != 
EL.index.num_value)
+                                       if (fds[i].array2fd[j] != 
EL.index.num_value) {
                                                fds[i].array2fd[j] = -1;
+                                               warning(ext_id, _("select: 
invalid numeric index `%g' in `%s' array (should be a non-negative integer)"), 
EL.index.num_value, argname[i]);
+                                       }
                                        break;
                                case AWK_STRING:
-                                       if (EL.value.val_type == AWK_STRING) {
-                                               const awk_input_buf_t *buf;
-                                               if ((buf = 
get_file(EL.index.str_value.str, EL.index.str_value.len, 
EL.value.str_value.str, EL.value.str_value.len)) != NULL)
-                                                       fds[i].array2fd[j] = 
buf->fd;
+                                       {
+                                               long x;
+
+                                               if 
((integer_string(EL.index.str_value.str, &x) == 0) && (x >= 0))
+                                                       fds[i].array2fd[j] = x;
+                                               else if (EL.value.val_type == 
AWK_STRING) {
+                                                       const awk_input_buf_t 
*buf;
+                                                       if ((buf = 
get_file(EL.index.str_value.str, EL.index.str_value.len, 
EL.value.str_value.str, EL.value.str_value.len)) != NULL)
+                                                               
fds[i].array2fd[j] = buf->fd;
+                                                       else
+                                                               warning(ext_id, 
_("select: get_file(`%s', `%s') failed in `%s' array"), EL.index.str_value.str, 
EL.value.str_value.str, argname[i]);
+                                               }
+                                               else
+                                                       warning(ext_id, 
_("select: command type should be a string for `%s' in `%s' array"), 
EL.index.str_value.str, argname[i]);
                                        }
                                        break;
+                               default:
+                                       warning(ext_id, _("select: invalid 
index type in `%s' array (must be a string or a non-negative integer"), 
argname[i]);
+                                       break;
                                }
                                if (fds[i].array2fd[j] < 0) {
-                                       warning(ext_id, _("select: get_file 
failed"));
                                        update_ERRNO_string(_("select: get_file 
failed"));
                                        if (! 
release_flattened_array(fds[i].array.array_cookie, fds[i].flat))
                                                warning(ext_id, _("select: 
release_flattened_array failed"));
@@ -126,7 +283,12 @@ do_select(int nargs, awk_value_t *result)
                else
                        fds[i].flat = NULL;
        }
-        if (get_argument(3, AWK_NUMBER, &timeout_arg)) {
+       if (dosig && caught.flag) {
+               /* take a quick poll, but do not block, since signals have been 
trapped */
+               maxwait.tv_sec = maxwait.tv_usec = 0;
+               timeout = &maxwait;
+       }
+        else if (get_argument(3, AWK_NUMBER, &timeout_arg)) {
                double secs = timeout_arg.num_value;
                if (secs < 0) {
                        warning(ext_id, _("select: treating negative timeout as 
zero"));
@@ -137,10 +299,37 @@ do_select(int nargs, awk_value_t *result)
                timeout = &maxwait;
        } else
                timeout = NULL;
-       rc = select(nfds, &fds[0].bits, &fds[1].bits, &fds[2].bits, timeout);
 
-       if (rc < 0) {
+       if ((rc = select(nfds, &fds[0].bits, &fds[1].bits, &fds[2].bits, 
timeout)) < 0)
                update_ERRNO_int(errno);
+
+       if (dosig && caught.flag) {
+               int i;
+               sigset_t set, oldset, trapped;
+               sigfillset(& set);
+               sigprocmask(SIG_SETMASK, &set, &oldset);
+               trapped = caught.mask;
+               sigemptyset(& caught.mask);
+               caught.flag = 0;
+               sigprocmask(SIG_SETMASK, &oldset, NULL);
+               /* populate sigarr with trapped signals */
+               /*
+                * XXX this is very inefficient!  Note that get_signal_number
+                * ensures that we trap only signals between MIN_VALID_SIGNAL
+                * and MAX_VALID_SIGNAL.
+                */
+               for (i = MIN_VALID_SIGNAL; i <= MAX_VALID_SIGNAL; i++) {
+                       if (sigismember(& trapped, i) > 0) {
+                               awk_value_t idx, val;
+                               if ((i < NUMSIG) && signum2name[i])
+                                       set_array_element(sigarr.array_cookie, 
make_number(i, &idx), make_const_string(signum2name[i], strlen(signum2name[i]), 
&val));
+                               else
+                                       set_array_element(sigarr.array_cookie, 
make_number(i, &idx), make_null_string(&val));
+                       }
+               }
+       }
+
+       if (rc < 0) {
                /* bit masks are undefined, so delete all array entries */
                for (i = 0; i < sizeof(fds)/sizeof(fds[0]); i++) {
                        if (fds[i].flat) {
@@ -176,6 +365,7 @@ do_select(int nargs, awk_value_t *result)
 
 static awk_ext_func_t func_table[] = {
        { "select", do_select, 5 },
+       { "select_signal", do_signal, 2 },
 };
 
 /* define the dl_load function using the boilerplate macro */
diff --git a/extension/siglist.h b/extension/siglist.h
new file mode 100644
index 0000000..dacd4a1
--- /dev/null
+++ b/extension/siglist.h
@@ -0,0 +1,75 @@
+/* Canonical list of all signal names.
+   Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This file should be usable for any platform, since it just associates
+   the SIG* macros with text names and descriptions.  The actual values
+   come from <bits/signum.h> (via <signal.h>).  For any signal macros do not
+   exist on every platform, we can use #ifdef tests here and still use
+   this single common file for all platforms.  */
+
+/* This file is included multiple times.  */
+
+/* Standard signals  */
+  init_sig (SIGHUP, "HUP", N_("Hangup"))
+  init_sig (SIGINT, "INT", N_("Interrupt"))
+  init_sig (SIGQUIT, "QUIT", N_("Quit"))
+  init_sig (SIGILL, "ILL", N_("Illegal instruction"))
+  init_sig (SIGTRAP, "TRAP", N_("Trace/breakpoint trap"))
+  init_sig (SIGABRT, "ABRT", N_("Aborted"))
+  init_sig (SIGFPE, "FPE", N_("Floating point exception"))
+  init_sig (SIGKILL, "KILL", N_("Killed"))
+  init_sig (SIGBUS, "BUS", N_("Bus error"))
+  init_sig (SIGSEGV, "SEGV", N_("Segmentation fault"))
+  init_sig (SIGPIPE, "PIPE", N_("Broken pipe"))
+  init_sig (SIGALRM, "ALRM", N_("Alarm clock"))
+  init_sig (SIGTERM, "TERM", N_("Terminated"))
+  init_sig (SIGURG, "URG", N_("Urgent I/O condition"))
+  init_sig (SIGSTOP, "STOP", N_("Stopped (signal)"))
+  init_sig (SIGTSTP, "TSTP", N_("Stopped"))
+  init_sig (SIGCONT, "CONT", N_("Continued"))
+  init_sig (SIGCHLD, "CHLD", N_("Child exited"))
+  init_sig (SIGTTIN, "TTIN", N_("Stopped (tty input)"))
+  init_sig (SIGTTOU, "TTOU", N_("Stopped (tty output)"))
+  init_sig (SIGIO, "IO", N_("I/O possible"))
+  init_sig (SIGXCPU, "XCPU", N_("CPU time limit exceeded"))
+  init_sig (SIGXFSZ, "XFSZ", N_("File size limit exceeded"))
+  init_sig (SIGVTALRM, "VTALRM", N_("Virtual timer expired"))
+  init_sig (SIGPROF, "PROF", N_("Profiling timer expired"))
+  init_sig (SIGWINCH, "WINCH", N_("Window changed"))
+  init_sig (SIGUSR1, "USR1", N_("User defined signal 1"))
+  init_sig (SIGUSR2, "USR2", N_("User defined signal 2"))
+
+/* Variations  */
+#ifdef SIGEMT
+  init_sig (SIGEMT, "EMT", N_("EMT trap"))
+#endif
+#ifdef SIGSYS
+  init_sig (SIGSYS, "SYS", N_("Bad system call"))
+#endif
+#ifdef SIGSTKFLT
+  init_sig (SIGSTKFLT, "STKFLT", N_("Stack fault"))
+#endif
+#ifdef SIGINFO
+  init_sig (SIGINFO, "INFO", N_("Information request"))
+#elif defined(SIGPWR) && (!defined(SIGLOST) || (SIGPWR != SIGLOST))
+  init_sig (SIGPWR, "PWR", N_("Power failure"))
+#endif
+#ifdef SIGLOST
+  init_sig (SIGLOST, "LOST", N_("Resource lost"))
+#endif

-----------------------------------------------------------------------

Summary of changes:
 extension/ChangeLog |   10 +++
 extension/select.c  |  210 ++++++++++++++++++++++++++++++++++++++++++++++++---
 extension/siglist.h |   75 ++++++++++++++++++
 3 files changed, 285 insertions(+), 10 deletions(-)
 create mode 100644 extension/siglist.h


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]