OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libpthread/] [linuxthreads/] [signals.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* Linuxthreads - a simple clone()-based implementation of Posix        */
2
/* threads for Linux.                                                   */
3
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4
/*                                                                      */
5
/* This program is free software; you can redistribute it and/or        */
6
/* modify it under the terms of the GNU Library General Public License  */
7
/* as published by the Free Software Foundation; either version 2       */
8
/* of the License, or (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 Library General Public License for more details.                 */
14
 
15
/* Handling of signals */
16
 
17
#include <errno.h>
18
#include <signal.h>
19
#include <stdio.h>
20
#include "pthread.h"
21
#include "internals.h"
22
#include "spinlock.h"
23
#include <ucontext.h>
24
#include <bits/sigcontextinfo.h>
25
 
26
/* mods for uClibc: __libc_sigaction is not in any standard headers */
27
extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact);
28
 
29
int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
30
{
31
  sigset_t mask;
32
 
33
  if (newmask != NULL) {
34
    mask = *newmask;
35
    /* Don't allow __pthread_sig_restart to be unmasked.
36
       Don't allow __pthread_sig_cancel to be masked. */
37
    switch(how) {
38
    case SIG_SETMASK:
39
      sigaddset(&mask, __pthread_sig_restart);
40
      sigdelset(&mask, __pthread_sig_cancel);
41
      break;
42
    case SIG_BLOCK:
43
      sigdelset(&mask, __pthread_sig_cancel);
44
      break;
45
    case SIG_UNBLOCK:
46
      sigdelset(&mask, __pthread_sig_restart);
47
      break;
48
    }
49
    newmask = &mask;
50
  }
51
  if (sigprocmask(how, newmask, oldmask) == -1)
52
    return errno;
53
  else
54
    return 0;
55
}
56
 
57
int pthread_kill(pthread_t thread, int signo)
58
{
59
  pthread_handle handle = thread_handle(thread);
60
  int pid;
61
 
62
  __pthread_lock(&handle->h_lock, NULL);
63
  if (invalid_handle(handle, thread)) {
64
    __pthread_unlock(&handle->h_lock);
65
    return ESRCH;
66
  }
67
  pid = handle->h_descr->p_pid;
68
  __pthread_unlock(&handle->h_lock);
69
  if (kill(pid, signo) == -1)
70
    return errno;
71
  else
72
    return 0;
73
}
74
 
75
/* User-provided signal handlers */
76
typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT));
77
static union
78
{
79
  arch_sighandler_t old;
80
  void (*rt) (int, struct siginfo *, struct ucontext *);
81
} sighandler[NSIG];
82
 
83
/* The wrapper around user-provided signal handlers */
84
static void pthread_sighandler(int signo, SIGCONTEXT ctx)
85
{
86
  pthread_descr self = thread_self();
87
  char * in_sighandler;
88
  /* If we're in a sigwait operation, just record the signal received
89
     and return without calling the user's handler */
90
  if (THREAD_GETMEM(self, p_sigwaiting)) {
91
    THREAD_SETMEM(self, p_sigwaiting, 0);
92
    THREAD_SETMEM(self, p_signal, signo);
93
    return;
94
  }
95
  /* Record that we're in a signal handler and call the user's
96
     handler function */
97
  in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
98
  if (in_sighandler == NULL)
99
    THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
100
  sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx);
101
  if (in_sighandler == NULL)
102
    THREAD_SETMEM(self, p_in_sighandler, NULL);
103
}
104
 
105
/* The same, this time for real-time signals.  */
106
static void pthread_sighandler_rt(int signo, struct siginfo *si,
107
                                  struct ucontext *uc)
108
{
109
  pthread_descr self = thread_self();
110
  char * in_sighandler;
111
  /* If we're in a sigwait operation, just record the signal received
112
     and return without calling the user's handler */
113
  if (THREAD_GETMEM(self, p_sigwaiting)) {
114
    THREAD_SETMEM(self, p_sigwaiting, 0);
115
    THREAD_SETMEM(self, p_signal, signo);
116
    return;
117
  }
118
  /* Record that we're in a signal handler and call the user's
119
     handler function */
120
  in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
121
  if (in_sighandler == NULL)
122
    THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
123
  sighandler[signo].rt(signo, si, uc);
124
  if (in_sighandler == NULL)
125
    THREAD_SETMEM(self, p_in_sighandler, NULL);
126
}
127
 
128
/* The wrapper around sigaction.  Install our own signal handler
129
   around the signal. */
130
int __sigaction(int sig, const struct sigaction * act,
131
              struct sigaction * oact)
132
{
133
  struct sigaction newact;
134
  struct sigaction *newactp;
135
 
136
#ifdef DEBUG_PT
137
printf(__FUNCTION__": pthreads wrapper!\n");
138
#endif
139
  if (sig == __pthread_sig_restart ||
140
      sig == __pthread_sig_cancel ||
141
      (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
142
    return EINVAL;
143
  if (act)
144
    {
145
      newact = *act;
146
      if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
147
          && sig > 0 && sig < NSIG)
148
        {
149
          if (act->sa_flags & SA_SIGINFO)
150
            newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
151
          else
152
            newact.sa_handler = (__sighandler_t) pthread_sighandler;
153
        }
154
      newactp = &newact;
155
    }
156
  else
157
    newactp = NULL;
158
  if (__libc_sigaction(sig, newactp, oact) == -1)
159
    return -1;
160
#ifdef DEBUG_PT
161
printf(__FUNCTION__": signahdler installed, __sigaction successful\n");
162
#endif
163
  if (sig > 0 && sig < NSIG)
164
    {
165
      if (oact != NULL)
166
        oact->sa_handler = (__sighandler_t) sighandler[sig].old;
167
      if (act)
168
        /* For the assignment is does not matter whether it's a normal
169
           or real-time signal.  */
170
        sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
171
    }
172
  return 0;
173
}
174
strong_alias(__sigaction, sigaction)
175
 
176
/* A signal handler that does nothing */
177
static void pthread_null_sighandler(int sig) { }
178
 
179
/* sigwait -- synchronously wait for a signal */
180
int sigwait(const sigset_t * set, int * sig)
181
{
182
  volatile pthread_descr self = thread_self();
183
  sigset_t mask;
184
  int s;
185
  sigjmp_buf jmpbuf;
186
  struct sigaction sa;
187
 
188
  /* Get ready to block all signals except those in set
189
     and the cancellation signal.
190
     Also check that handlers are installed on all signals in set,
191
     and if not, install our dummy handler.  This is conformant to
192
     POSIX: "The effect of sigwait() on the signal actions for the
193
     signals in set is unspecified." */
194
  sigfillset(&mask);
195
  sigdelset(&mask, __pthread_sig_cancel);
196
  for (s = 1; s <= NSIG; s++) {
197
    if (sigismember(set, s) &&
198
        s != __pthread_sig_restart &&
199
        s != __pthread_sig_cancel &&
200
        s != __pthread_sig_debug) {
201
      sigdelset(&mask, s);
202
      if (sighandler[s].old == NULL ||
203
          sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
204
          sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
205
        sa.sa_handler = pthread_null_sighandler;
206
        sigemptyset(&sa.sa_mask);
207
        sa.sa_flags = 0;
208
        sigaction(s, &sa, NULL);
209
      }
210
    }
211
  }
212
  /* Test for cancellation */
213
  if (sigsetjmp(jmpbuf, 1) == 0) {
214
    THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
215
    if (! (THREAD_GETMEM(self, p_canceled)
216
           && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
217
      /* Reset the signal count */
218
      THREAD_SETMEM(self, p_signal, 0);
219
      /* Say we're in sigwait */
220
      THREAD_SETMEM(self, p_sigwaiting, 1);
221
      /* Unblock the signals and wait for them */
222
      sigsuspend(&mask);
223
    }
224
  }
225
  THREAD_SETMEM(self, p_cancel_jmp, NULL);
226
  /* The signals are now reblocked.  Check for cancellation */
227
  pthread_testcancel();
228
  /* We should have self->p_signal != 0 and equal to the signal received */
229
  *sig = THREAD_GETMEM(self, p_signal);
230
  return 0;
231
}
232
 
233
/* Redefine raise() to send signal to calling thread only,
234
   as per POSIX 1003.1c */
235
int raise (int sig)
236
{
237
  int retcode = pthread_kill(pthread_self(), sig);
238
  if (retcode == 0)
239
    return 0;
240
  else {
241
    errno = retcode;
242
    return -1;
243
  }
244
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.