Back to index

glibc  2.9
signals.c
Go to the documentation of this file.
00001 /* Linuxthreads - a simple clone()-based implementation of Posix        */
00002 /* threads for Linux.                                                   */
00003 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
00004 /*                                                                      */
00005 /* This program is free software; you can redistribute it and/or        */
00006 /* modify it under the terms of the GNU Library General Public License  */
00007 /* as published by the Free Software Foundation; either version 2       */
00008 /* of the License, or (at your option) any later version.               */
00009 /*                                                                      */
00010 /* This program is distributed in the hope that it will be useful,      */
00011 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
00012 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
00013 /* GNU Library General Public License for more details.                 */
00014 
00015 /* Handling of signals */
00016 
00017 #include <errno.h>
00018 #include <signal.h>
00019 #include "pthread.h"
00020 #include "internals.h"
00021 #include "spinlock.h"
00022 #include <ucontext.h>
00023 
00024 
00025 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
00026 {
00027   sigset_t mask;
00028 
00029   if (newmask != NULL) {
00030     mask = *newmask;
00031     /* Don't allow __pthread_sig_restart to be unmasked.
00032        Don't allow __pthread_sig_cancel to be masked. */
00033     switch(how) {
00034     case SIG_SETMASK:
00035       sigaddset(&mask, __pthread_sig_restart);
00036       sigdelset(&mask, __pthread_sig_cancel);
00037       if (__pthread_sig_debug > 0)
00038        sigdelset(&mask, __pthread_sig_debug);
00039       break;
00040     case SIG_BLOCK:
00041       sigdelset(&mask, __pthread_sig_cancel);
00042       if (__pthread_sig_debug > 0)
00043        sigdelset(&mask, __pthread_sig_debug);
00044       break;
00045     case SIG_UNBLOCK:
00046       sigdelset(&mask, __pthread_sig_restart);
00047       break;
00048     }
00049     newmask = &mask;
00050   }
00051   if (sigprocmask(how, newmask, oldmask) == -1)
00052     return errno;
00053   else
00054     return 0;
00055 }
00056 
00057 int pthread_kill(pthread_t thread, int signo)
00058 {
00059   pthread_handle handle = thread_handle(thread);
00060   int pid;
00061 
00062   __pthread_lock(&handle->h_lock, NULL);
00063   if (invalid_handle(handle, thread)) {
00064     __pthread_unlock(&handle->h_lock);
00065     return ESRCH;
00066   }
00067   pid = handle->h_descr->p_pid;
00068   __pthread_unlock(&handle->h_lock);
00069   if (kill(pid, signo) == -1)
00070     return errno;
00071   else
00072     return 0;
00073 }
00074 
00075 union sighandler __sighandler[NSIG] =
00076   { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
00077 
00078 /* The wrapper around sigaction.  Install our own signal handler
00079    around the signal. */
00080 int __pthread_sigaction(int sig, const struct sigaction * act,
00081                      struct sigaction * oact)
00082 {
00083   struct sigaction newact;
00084   struct sigaction *newactp;
00085   __sighandler_t old = SIG_DFL;
00086 
00087   if (sig == __pthread_sig_restart ||
00088       sig == __pthread_sig_cancel ||
00089       (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
00090     {
00091       __set_errno (EINVAL);
00092       return -1;
00093     }
00094   if (sig > 0 && sig < NSIG)
00095     old = (__sighandler_t) __sighandler[sig].old;
00096   if (act)
00097     {
00098       newact = *act;
00099       if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
00100          && sig > 0 && sig < NSIG)
00101        {
00102          if (act->sa_flags & SA_SIGINFO)
00103            newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
00104          else
00105            newact.sa_handler = (__sighandler_t) __pthread_sighandler;
00106          if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
00107            __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
00108        }
00109       newactp = &newact;
00110     }
00111   else
00112     newactp = NULL;
00113   if (__libc_sigaction(sig, newactp, oact) == -1)
00114     {
00115       if (act)
00116        __sighandler[sig].old = (arch_sighandler_t) old;
00117       return -1;
00118     }
00119   if (sig > 0 && sig < NSIG)
00120     {
00121       if (oact != NULL
00122          /* We may have inherited SIG_IGN from the parent, so return the
00123             kernel's idea of the signal handler the first time
00124             through.  */
00125          && old != SIG_ERR)
00126        oact->sa_handler = old;
00127       if (act)
00128        /* For the assignment it does not matter whether it's a normal
00129           or real-time signal.  */
00130        __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
00131     }
00132   return 0;
00133 }
00134 #ifdef SHARED
00135 strong_alias(__pthread_sigaction, __sigaction)
00136 strong_alias(__pthread_sigaction, sigaction)
00137 #endif
00138 
00139 /* sigwait -- synchronously wait for a signal */
00140 int __pthread_sigwait(const sigset_t * set, int * sig)
00141 {
00142   volatile pthread_descr self = thread_self();
00143   sigset_t mask;
00144   int s;
00145   sigjmp_buf jmpbuf;
00146   struct sigaction sa;
00147 
00148   /* Get ready to block all signals except those in set
00149      and the cancellation signal.
00150      Also check that handlers are installed on all signals in set,
00151      and if not, install our dummy handler.  This is conformant to
00152      POSIX: "The effect of sigwait() on the signal actions for the
00153      signals in set is unspecified." */
00154   sigfillset(&mask);
00155   sigdelset(&mask, __pthread_sig_cancel);
00156   for (s = 1; s < NSIG; s++) {
00157     if (sigismember(set, s) &&
00158         s != __pthread_sig_restart &&
00159         s != __pthread_sig_cancel &&
00160         s != __pthread_sig_debug) {
00161       sigdelset(&mask, s);
00162       if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
00163           __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
00164           __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
00165         sa.sa_handler = __pthread_null_sighandler;
00166         sigfillset(&sa.sa_mask);
00167         sa.sa_flags = 0;
00168         sigaction(s, &sa, NULL);
00169       }
00170     }
00171   }
00172   /* Test for cancellation */
00173   if (sigsetjmp(jmpbuf, 1) == 0) {
00174     THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
00175     if (! (THREAD_GETMEM(self, p_canceled)
00176           && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
00177       /* Reset the signal count */
00178       THREAD_SETMEM(self, p_signal, 0);
00179       /* Say we're in sigwait */
00180       THREAD_SETMEM(self, p_sigwaiting, 1);
00181       /* Unblock the signals and wait for them */
00182       sigsuspend(&mask);
00183     }
00184   }
00185   THREAD_SETMEM(self, p_cancel_jmp, NULL);
00186   /* The signals are now reblocked.  Check for cancellation */
00187   pthread_testcancel();
00188   /* We should have self->p_signal != 0 and equal to the signal received */
00189   *sig = THREAD_GETMEM(self, p_signal);
00190   return 0;
00191 }
00192 #ifdef SHARED
00193 strong_alias (__pthread_sigwait, sigwait)
00194 #endif
00195 
00196 /* Redefine raise() to send signal to calling thread only,
00197    as per POSIX 1003.1c */
00198 int __pthread_raise (int sig)
00199 {
00200   int retcode = pthread_kill(pthread_self(), sig);
00201   if (retcode == 0)
00202     return 0;
00203   else {
00204     errno = retcode;
00205     return -1;
00206   }
00207 }
00208 #ifdef SHARED
00209 strong_alias (__pthread_raise, raise)
00210 #endif
00211 
00212 /* This files handles cancellation internally.  */
00213 LIBC_CANCEL_HANDLED ();