~ubuntu-branches/ubuntu/vivid/diffutils/vivid

« back to all changes in this revision

Viewing changes to lib/sigprocmask.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2010-02-13 11:49:00 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100213114900-09lz8jx6wct52qp8
Tags: 1:2.9-1
* New upstream release, now under GPL version 3 or later.
* There is now a --tab-size option. Closes: #82923.
* Manpage for cmp describes exit status. Closes: #200614.
* Manpage for diff describes exit status. Closes: #228441, #473233.
* The file de.po is now more recent. Closes: #313686.
* Fixed bad sdiff behaviour. Closes: #320222.
* Added wdiff to Suggests. Closes: #324627.
* Fixed cmp behaviour regarding stdout and stderr. Closes: #356083.
* The file ru.po is now more recent. Closes: #409274.
* The file es.po is now more recent. Closes: #418005, #481708.
* The file nl.po is now more recent. Closes: #427370.
* Modified watch file to use http instead of ftp.
* Removed .comment section from executables.
* Added Homepage field to control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* POSIX compatible signal blocking.
 
2
   Copyright (C) 2006-2010 Free Software Foundation, Inc.
 
3
   Written by Bruno Haible <bruno@clisp.org>, 2006.
 
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
/* We assume that a platform without POSIX signal blocking functions
 
28
   also does not have the POSIX sigaction() function, only the
 
29
   signal() function.  We also assume signal() has SysV semantics,
 
30
   where any handler is uninstalled prior to being invoked.  This is
 
31
   true for Woe32 platforms.  */
 
32
 
 
33
/* We use raw signal(), but also provide a wrapper rpl_signal() so
 
34
   that applications can query or change a blocked signal.  */
 
35
#undef signal
 
36
 
 
37
/* Provide invalid signal numbers as fallbacks if the uncatchable
 
38
   signals are not defined.  */
 
39
#ifndef SIGKILL
 
40
# define SIGKILL (-1)
 
41
#endif
 
42
#ifndef SIGSTOP
 
43
# define SIGSTOP (-1)
 
44
#endif
 
45
 
 
46
/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
 
47
   for the signal SIGABRT.  Only one signal handler is stored for both
 
48
   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
 
49
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
50
# undef SIGABRT_COMPAT
 
51
# define SIGABRT_COMPAT 6
 
52
#endif
 
53
#ifdef SIGABRT_COMPAT
 
54
# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
 
55
#else
 
56
# define SIGABRT_COMPAT_MASK 0
 
57
#endif
 
58
 
 
59
typedef void (*handler_t) (int);
 
60
 
 
61
/* Handling of gnulib defined signals.  */
 
62
 
 
63
#if GNULIB_defined_SIGPIPE
 
64
static handler_t SIGPIPE_handler = SIG_DFL;
 
65
#endif
 
66
 
 
67
#if GNULIB_defined_SIGPIPE
 
68
static handler_t
 
69
ext_signal (int sig, handler_t handler)
 
70
{
 
71
  switch (sig)
 
72
    {
 
73
    case SIGPIPE:
 
74
      {
 
75
        handler_t old_handler = SIGPIPE_handler;
 
76
        SIGPIPE_handler = handler;
 
77
        return old_handler;
 
78
      }
 
79
    default: /* System defined signal */
 
80
      return signal (sig, handler);
 
81
    }
 
82
}
 
83
# define signal ext_signal
 
84
#endif
 
85
 
 
86
int
 
87
sigismember (const sigset_t *set, int sig)
 
88
{
 
89
  if (sig >= 0 && sig < NSIG)
 
90
    {
 
91
      #ifdef SIGABRT_COMPAT
 
92
      if (sig == SIGABRT_COMPAT)
 
93
        sig = SIGABRT;
 
94
      #endif
 
95
 
 
96
      return (*set >> sig) & 1;
 
97
    }
 
98
  else
 
99
    return 0;
 
100
}
 
101
 
 
102
int
 
103
sigemptyset (sigset_t *set)
 
104
{
 
105
  *set = 0;
 
106
  return 0;
 
107
}
 
108
 
 
109
int
 
110
sigaddset (sigset_t *set, int sig)
 
111
{
 
112
  if (sig >= 0 && sig < NSIG)
 
113
    {
 
114
      #ifdef SIGABRT_COMPAT
 
115
      if (sig == SIGABRT_COMPAT)
 
116
        sig = SIGABRT;
 
117
      #endif
 
118
 
 
119
      *set |= 1U << sig;
 
120
      return 0;
 
121
    }
 
122
  else
 
123
    {
 
124
      errno = EINVAL;
 
125
      return -1;
 
126
    }
 
127
}
 
128
 
 
129
int
 
130
sigdelset (sigset_t *set, int sig)
 
131
{
 
132
  if (sig >= 0 && sig < NSIG)
 
133
    {
 
134
      #ifdef SIGABRT_COMPAT
 
135
      if (sig == SIGABRT_COMPAT)
 
136
        sig = SIGABRT;
 
137
      #endif
 
138
 
 
139
      *set &= ~(1U << sig);
 
140
      return 0;
 
141
    }
 
142
  else
 
143
    {
 
144
      errno = EINVAL;
 
145
      return -1;
 
146
    }
 
147
}
 
148
 
 
149
 
 
150
int
 
151
sigfillset (sigset_t *set)
 
152
{
 
153
  *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
 
154
  return 0;
 
155
}
 
156
 
 
157
/* Set of currently blocked signals.  */
 
158
static volatile sigset_t blocked_set /* = 0 */;
 
159
 
 
160
/* Set of currently blocked and pending signals.  */
 
161
static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
 
162
 
 
163
/* Signal handler that is installed for blocked signals.  */
 
164
static void
 
165
blocked_handler (int sig)
 
166
{
 
167
  /* Reinstall the handler, in case the signal occurs multiple times
 
168
     while blocked.  There is an inherent race where an asynchronous
 
169
     signal in between when the kernel uninstalled the handler and
 
170
     when we reinstall it will trigger the default handler; oh
 
171
     well.  */
 
172
  signal (sig, blocked_handler);
 
173
  if (sig >= 0 && sig < NSIG)
 
174
    pending_array[sig] = 1;
 
175
}
 
176
 
 
177
int
 
178
sigpending (sigset_t *set)
 
179
{
 
180
  sigset_t pending = 0;
 
181
  int sig;
 
182
 
 
183
  for (sig = 0; sig < NSIG; sig++)
 
184
    if (pending_array[sig])
 
185
      pending |= 1U << sig;
 
186
  *set = pending;
 
187
  return 0;
 
188
}
 
189
 
 
190
/* The previous signal handlers.
 
191
   Only the array elements corresponding to blocked signals are relevant.  */
 
192
static volatile handler_t old_handlers[NSIG];
 
193
 
 
194
int
 
195
sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
 
196
{
 
197
  if (old_set != NULL)
 
198
    *old_set = blocked_set;
 
199
 
 
200
  if (set != NULL)
 
201
    {
 
202
      sigset_t new_blocked_set;
 
203
      sigset_t to_unblock;
 
204
      sigset_t to_block;
 
205
 
 
206
      switch (operation)
 
207
        {
 
208
        case SIG_BLOCK:
 
209
          new_blocked_set = blocked_set | *set;
 
210
          break;
 
211
        case SIG_SETMASK:
 
212
          new_blocked_set = *set;
 
213
          break;
 
214
        case SIG_UNBLOCK:
 
215
          new_blocked_set = blocked_set & ~*set;
 
216
          break;
 
217
        default:
 
218
          errno = EINVAL;
 
219
          return -1;
 
220
        }
 
221
      to_unblock = blocked_set & ~new_blocked_set;
 
222
      to_block = new_blocked_set & ~blocked_set;
 
223
 
 
224
      if (to_block != 0)
 
225
        {
 
226
          int sig;
 
227
 
 
228
          for (sig = 0; sig < NSIG; sig++)
 
229
            if ((to_block >> sig) & 1)
 
230
              {
 
231
                pending_array[sig] = 0;
 
232
                if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
 
233
                  blocked_set |= 1U << sig;
 
234
              }
 
235
        }
 
236
 
 
237
      if (to_unblock != 0)
 
238
        {
 
239
          sig_atomic_t received[NSIG];
 
240
          int sig;
 
241
 
 
242
          for (sig = 0; sig < NSIG; sig++)
 
243
            if ((to_unblock >> sig) & 1)
 
244
              {
 
245
                if (signal (sig, old_handlers[sig]) != blocked_handler)
 
246
                  /* The application changed a signal handler while the signal
 
247
                     was blocked, bypassing our rpl_signal replacement.
 
248
                     We don't support this.  */
 
249
                  abort ();
 
250
                received[sig] = pending_array[sig];
 
251
                blocked_set &= ~(1U << sig);
 
252
                pending_array[sig] = 0;
 
253
              }
 
254
            else
 
255
              received[sig] = 0;
 
256
 
 
257
          for (sig = 0; sig < NSIG; sig++)
 
258
            if (received[sig])
 
259
              raise (sig);
 
260
        }
 
261
    }
 
262
  return 0;
 
263
}
 
264
 
 
265
/* Install the handler FUNC for signal SIG, and return the previous
 
266
   handler.  */
 
267
handler_t
 
268
rpl_signal (int sig, handler_t handler)
 
269
{
 
270
  /* We must provide a wrapper, so that a user can query what handler
 
271
     they installed even if that signal is currently blocked.  */
 
272
  if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
 
273
      && handler != SIG_ERR)
 
274
    {
 
275
      #ifdef SIGABRT_COMPAT
 
276
      if (sig == SIGABRT_COMPAT)
 
277
        sig = SIGABRT;
 
278
      #endif
 
279
 
 
280
      if (blocked_set & (1U << sig))
 
281
        {
 
282
          /* POSIX states that sigprocmask and signal are both
 
283
             async-signal-safe.  This is not true of our
 
284
             implementation - there is a slight data race where an
 
285
             asynchronous interrupt on signal A can occur after we
 
286
             install blocked_handler but before we have updated
 
287
             old_handlers for signal B, such that handler A can see
 
288
             stale information if it calls signal(B).  Oh well -
 
289
             signal handlers really shouldn't try to manipulate the
 
290
             installed handlers of unrelated signals.  */
 
291
          handler_t result = old_handlers[sig];
 
292
          old_handlers[sig] = handler;
 
293
          return result;
 
294
        }
 
295
      else
 
296
        return signal (sig, handler);
 
297
    }
 
298
  else
 
299
    {
 
300
      errno = EINVAL;
 
301
      return SIG_ERR;
 
302
    }
 
303
}
 
304
 
 
305
#if GNULIB_defined_SIGPIPE
 
306
/* Raise the signal SIG.  */
 
307
int
 
308
rpl_raise (int sig)
 
309
# undef raise
 
310
{
 
311
  switch (sig)
 
312
    {
 
313
    case SIGPIPE:
 
314
      if (blocked_set & (1U << sig))
 
315
        pending_array[sig] = 1;
 
316
      else
 
317
        {
 
318
          handler_t handler = SIGPIPE_handler;
 
319
          if (handler == SIG_DFL)
 
320
            exit (128 + SIGPIPE);
 
321
          else if (handler != SIG_IGN)
 
322
            (*handler) (sig);
 
323
        }
 
324
      return 0;
 
325
    default: /* System defined signal */
 
326
      return raise (sig);
 
327
    }
 
328
}
 
329
#endif