~braiampe/+junk/cgminer

« back to all changes in this revision

Viewing changes to lib/sigaction.c

  • Committer: Braiam Peguero
  • Date: 2011-10-09 06:47:47 UTC
  • Revision ID: braiamp@gmail.com-20111009064747-iju2nhzrh6ya56zs
* Forgot adding files to the branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* POSIX compatible signal blocking.
 
2
   Copyright (C) 2008-2011 Free Software Foundation, Inc.
 
3
   Written by Eric Blake <ebb9@byu.net>, 2008.
 
4
 
 
5
   This program is free software: you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 3 of the License, or
 
8
   (at your option) any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
#include <config.h>
 
19
 
 
20
/* Specification.  */
 
21
#include <signal.h>
 
22
 
 
23
#include <errno.h>
 
24
#include <stdint.h>
 
25
#include <stdlib.h>
 
26
 
 
27
/* This implementation of sigaction is tailored to Woe32 behavior:
 
28
   signal() has SysV semantics (ie. the handler is uninstalled before
 
29
   it is invoked).  This is an inherent data race if an asynchronous
 
30
   signal is sent twice in a row before we can reinstall our handler,
 
31
   but there's nothing we can do about it.  Meanwhile, sigprocmask()
 
32
   is not present, and while we can use the gnulib replacement to
 
33
   provide critical sections, it too suffers from potential data races
 
34
   in the face of an ill-timed asynchronous signal.  And we compound
 
35
   the situation by reading static storage in a signal handler, which
 
36
   POSIX warns is not generically async-signal-safe.  Oh well.
 
37
 
 
38
   Additionally:
 
39
     - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
 
40
       is not defined.
 
41
     - We don't implement SA_ONSTACK, because sigaltstack() is not present.
 
42
     - We ignore SA_RESTART, because blocking Win32 calls are not interrupted
 
43
       anyway when an asynchronous signal occurs, and the MSVCRT runtime
 
44
       never sets errno to EINTR.
 
45
     - We don't implement SA_SIGINFO because it is impossible to do so
 
46
       portably.
 
47
 
 
48
   POSIX states that an application should not mix signal() and
 
49
   sigaction().  We support the use of signal() within the gnulib
 
50
   sigprocmask() substitute, but all other application code linked
 
51
   with this module should stick with only sigaction().  */
 
52
 
 
53
/* Check some of our assumptions.  */
 
54
#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
 
55
# error "Revisit the assumptions made in the sigaction module"
 
56
#endif
 
57
 
 
58
/* Out-of-range substitutes make a good fallback for uncatchable
 
59
   signals.  */
 
60
#ifndef SIGKILL
 
61
# define SIGKILL (-1)
 
62
#endif
 
63
#ifndef SIGSTOP
 
64
# define SIGSTOP (-1)
 
65
#endif
 
66
 
 
67
/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
 
68
   for the signal SIGABRT.  Only one signal handler is stored for both
 
69
   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
 
70
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
71
# undef SIGABRT_COMPAT
 
72
# define SIGABRT_COMPAT 6
 
73
#endif
 
74
 
 
75
/* A signal handler.  */
 
76
typedef void (*handler_t) (int signal);
 
77
 
 
78
/* Set of current actions.  If sa_handler for an entry is NULL, then
 
79
   that signal is not currently handled by the sigaction handler.  */
 
80
static struct sigaction volatile action_array[NSIG] /* = 0 */;
 
81
 
 
82
/* Signal handler that is installed for signals.  */
 
83
static void
 
84
sigaction_handler (int sig)
 
85
{
 
86
  handler_t handler;
 
87
  sigset_t mask;
 
88
  sigset_t oldmask;
 
89
  int saved_errno = errno;
 
90
  if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
 
91
    {
 
92
      /* Unexpected situation; be careful to avoid recursive abort.  */
 
93
      if (sig == SIGABRT)
 
94
        signal (SIGABRT, SIG_DFL);
 
95
      abort ();
 
96
    }
 
97
 
 
98
  /* Reinstall the signal handler when required; otherwise update the
 
99
     bookkeeping so that the user's handler may call sigaction and get
 
100
     accurate results.  We know the signal isn't currently blocked, or
 
101
     we wouldn't be in its handler, therefore we know that we are not
 
102
     interrupting a sigaction() call.  There is a race where any
 
103
     asynchronous instance of the same signal occurring before we
 
104
     reinstall the handler will trigger the default handler; oh
 
105
     well.  */
 
106
  handler = action_array[sig].sa_handler;
 
107
  if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
 
108
    signal (sig, sigaction_handler);
 
109
  else
 
110
    action_array[sig].sa_handler = NULL;
 
111
 
 
112
  /* Block appropriate signals.  */
 
113
  mask = action_array[sig].sa_mask;
 
114
  if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
 
115
    sigaddset (&mask, sig);
 
116
  sigprocmask (SIG_BLOCK, &mask, &oldmask);
 
117
 
 
118
  /* Invoke the user's handler, then restore prior mask.  */
 
119
  errno = saved_errno;
 
120
  handler (sig);
 
121
  saved_errno = errno;
 
122
  sigprocmask (SIG_SETMASK, &oldmask, NULL);
 
123
  errno = saved_errno;
 
124
}
 
125
 
 
126
/* Change and/or query the action that will be taken on delivery of
 
127
   signal SIG.  If not NULL, ACT describes the new behavior.  If not
 
128
   NULL, OACT is set to the prior behavior.  Return 0 on success, or
 
129
   set errno and return -1 on failure.  */
 
130
int
 
131
sigaction (int sig, const struct sigaction *restrict act,
 
132
           struct sigaction *restrict oact)
 
133
{
 
134
  sigset_t mask;
 
135
  sigset_t oldmask;
 
136
  int saved_errno;
 
137
 
 
138
  if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
 
139
      || (act && act->sa_handler == SIG_ERR))
 
140
    {
 
141
      errno = EINVAL;
 
142
      return -1;
 
143
    }
 
144
 
 
145
#ifdef SIGABRT_COMPAT
 
146
  if (sig == SIGABRT_COMPAT)
 
147
    sig = SIGABRT;
 
148
#endif
 
149
 
 
150
  /* POSIX requires sigaction() to be async-signal-safe.  In other
 
151
     words, if an asynchronous signal can occur while we are anywhere
 
152
     inside this function, the user's handler could then call
 
153
     sigaction() recursively and expect consistent results.  We meet
 
154
     this rule by using sigprocmask to block all signals before
 
155
     modifying any data structure that could be read from a signal
 
156
     handler; this works since we know that the gnulib sigprocmask
 
157
     replacement does not try to use sigaction() from its handler.  */
 
158
  if (!act && !oact)
 
159
    return 0;
 
160
  sigfillset (&mask);
 
161
  sigprocmask (SIG_BLOCK, &mask, &oldmask);
 
162
  if (oact)
 
163
    {
 
164
      if (action_array[sig].sa_handler)
 
165
        *oact = action_array[sig];
 
166
      else
 
167
        {
 
168
          /* Safe to change the handler at will here, since all
 
169
             signals are currently blocked.  */
 
170
          oact->sa_handler = signal (sig, SIG_DFL);
 
171
          if (oact->sa_handler == SIG_ERR)
 
172
            goto failure;
 
173
          signal (sig, oact->sa_handler);
 
174
          oact->sa_flags = SA_RESETHAND | SA_NODEFER;
 
175
          sigemptyset (&oact->sa_mask);
 
176
        }
 
177
    }
 
178
 
 
179
  if (act)
 
180
    {
 
181
      /* Safe to install the handler before updating action_array,
 
182
         since all signals are currently blocked.  */
 
183
      if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
 
184
        {
 
185
          if (signal (sig, act->sa_handler) == SIG_ERR)
 
186
            goto failure;
 
187
          action_array[sig].sa_handler = NULL;
 
188
        }
 
189
      else
 
190
        {
 
191
          if (signal (sig, sigaction_handler) == SIG_ERR)
 
192
            goto failure;
 
193
          action_array[sig] = *act;
 
194
        }
 
195
    }
 
196
  sigprocmask (SIG_SETMASK, &oldmask, NULL);
 
197
  return 0;
 
198
 
 
199
 failure:
 
200
  saved_errno = errno;
 
201
  sigprocmask (SIG_SETMASK, &oldmask, NULL);
 
202
  errno = saved_errno;
 
203
  return -1;
 
204
}