~ubuntu-branches/ubuntu/karmic/prelude-manager/karmic

« back to all changes in this revision

Viewing changes to libmissing/sigprocmask.c

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2008-07-29 11:51:32 UTC
  • mfrom: (1.1.9 upstream) (3.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20080729115132-gvgj6fjgatpabbkx
Tags: 0.9.14.1-1
New upstream bugfix release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* POSIX compatible signal blocking.
 
2
   Copyright (C) 2006-2008 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 Lesser 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 Lesser General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU Lesser 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
typedef void (*handler_t) (int);
 
47
 
 
48
int
 
49
sigismember (const sigset_t *set, int sig)
 
50
{
 
51
  if (sig >= 0 && sig < NSIG)
 
52
    return (*set >> sig) & 1;
 
53
  else
 
54
    return 0;
 
55
}
 
56
 
 
57
int
 
58
sigemptyset (sigset_t *set)
 
59
{
 
60
  *set = 0;
 
61
  return 0;
 
62
}
 
63
 
 
64
int
 
65
sigaddset (sigset_t *set, int sig)
 
66
{
 
67
  if (sig >= 0 && sig < NSIG)
 
68
    {
 
69
      *set |= 1U << sig;
 
70
      return 0;
 
71
    }
 
72
  else
 
73
    {
 
74
      errno = EINVAL;
 
75
      return -1;
 
76
    }
 
77
}
 
78
 
 
79
int
 
80
sigdelset (sigset_t *set, int sig)
 
81
{
 
82
  if (sig >= 0 && sig < NSIG)
 
83
    {
 
84
      *set &= ~(1U << sig);
 
85
      return 0;
 
86
    }
 
87
  else
 
88
    {
 
89
      errno = EINVAL;
 
90
      return -1;
 
91
    }
 
92
}
 
93
 
 
94
int
 
95
sigfillset (sigset_t *set)
 
96
{
 
97
  *set = (2U << (NSIG - 1)) - 1;
 
98
  return 0;
 
99
}
 
100
 
 
101
/* Set of currently blocked signals.  */
 
102
static volatile sigset_t blocked_set /* = 0 */;
 
103
 
 
104
/* Set of currently blocked and pending signals.  */
 
105
static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
 
106
 
 
107
/* Signal handler that is installed for blocked signals.  */
 
108
static void
 
109
blocked_handler (int sig)
 
110
{
 
111
  /* Reinstall the handler, in case the signal occurs multiple times
 
112
     while blocked.  There is an inherent race where an asynchronous
 
113
     signal in between when the kernel uninstalled the handler and
 
114
     when we reinstall it will trigger the default handler; oh
 
115
     well.  */
 
116
  signal (sig, blocked_handler);
 
117
  if (sig >= 0 && sig < NSIG)
 
118
    pending_array[sig] = 1;
 
119
}
 
120
 
 
121
int
 
122
sigpending (sigset_t *set)
 
123
{
 
124
  sigset_t pending = 0;
 
125
  int sig;
 
126
 
 
127
  for (sig = 0; sig < NSIG; sig++)
 
128
    if (pending_array[sig])
 
129
      pending |= 1U << sig;
 
130
  *set = pending;
 
131
  return 0;
 
132
}
 
133
 
 
134
/* The previous signal handlers.
 
135
   Only the array elements corresponding to blocked signals are relevant.  */
 
136
static volatile handler_t old_handlers[NSIG];
 
137
 
 
138
int
 
139
sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
 
140
{
 
141
  if (old_set != NULL)
 
142
    *old_set = blocked_set;
 
143
 
 
144
  if (set != NULL)
 
145
    {
 
146
      sigset_t new_blocked_set;
 
147
      sigset_t to_unblock;
 
148
      sigset_t to_block;
 
149
 
 
150
      switch (operation)
 
151
        {
 
152
        case SIG_BLOCK:
 
153
          new_blocked_set = blocked_set | *set;
 
154
          break;
 
155
        case SIG_SETMASK:
 
156
          new_blocked_set = *set;
 
157
          break;
 
158
        case SIG_UNBLOCK:
 
159
          new_blocked_set = blocked_set & ~*set;
 
160
          break;
 
161
        default:
 
162
          errno = EINVAL;
 
163
          return -1;
 
164
        }
 
165
      to_unblock = blocked_set & ~new_blocked_set;
 
166
      to_block = new_blocked_set & ~blocked_set;
 
167
 
 
168
      if (to_block != 0)
 
169
        {
 
170
          int sig;
 
171
 
 
172
          for (sig = 0; sig < NSIG; sig++)
 
173
            if ((to_block >> sig) & 1)
 
174
              {
 
175
                pending_array[sig] = 0;
 
176
                if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
 
177
                  blocked_set |= 1U << sig;
 
178
              }
 
179
        }
 
180
 
 
181
      if (to_unblock != 0)
 
182
        {
 
183
          sig_atomic_t received[NSIG];
 
184
          int sig;
 
185
 
 
186
          for (sig = 0; sig < NSIG; sig++)
 
187
            if ((to_unblock >> sig) & 1)
 
188
              {
 
189
                if (signal (sig, old_handlers[sig]) != blocked_handler)
 
190
                  /* The application changed a signal handler while the signal
 
191
                     was blocked, bypassing our rpl_signal replacement.
 
192
                     We don't support this.  */
 
193
                  abort ();
 
194
                received[sig] = pending_array[sig];
 
195
                blocked_set &= ~(1U << sig);
 
196
                pending_array[sig] = 0;
 
197
              }
 
198
            else
 
199
              received[sig] = 0;
 
200
 
 
201
          for (sig = 0; sig < NSIG; sig++)
 
202
            if (received[sig])
 
203
              raise (sig);
 
204
        }
 
205
    }
 
206
  return 0;
 
207
}
 
208
 
 
209
/* Install the handler FUNC for signal SIG, and return the previous
 
210
   handler.  */
 
211
handler_t
 
212
rpl_signal (int sig, handler_t handler)
 
213
{
 
214
  /* We must provide a wrapper, so that a user can query what handler
 
215
     they installed even if that signal is currently blocked.  */
 
216
  if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
 
217
      && handler != SIG_ERR)
 
218
    {
 
219
      if (blocked_set & (1U << sig))
 
220
        {
 
221
          /* POSIX states that sigprocmask and signal are both
 
222
             async-signal-safe.  This is not true of our
 
223
             implementation - there is a slight data race where an
 
224
             asynchronous interrupt on signal A can occur after we
 
225
             install blocked_handler but before we have updated
 
226
             old_handlers for signal B, such that handler A can see
 
227
             stale information if it calls signal(B).  Oh well -
 
228
             signal handlers really shouldn't try to manipulate the
 
229
             installed handlers of unrelated signals.  */
 
230
          handler_t result = old_handlers[sig];
 
231
          old_handlers[sig] = handler;
 
232
          return result;
 
233
        }
 
234
      else
 
235
        return signal (sig, handler);
 
236
    }
 
237
  else
 
238
    {
 
239
      errno = EINVAL;
 
240
      return SIG_ERR;
 
241
    }
 
242
}