diff options
author | Christopher Faylor <cgf@redhat.com> | 2004-01-21 15:47:58 +0000 |
---|---|---|
committer | Christopher Faylor <cgf@redhat.com> | 2004-01-21 15:47:58 +0000 |
commit | 9fa9327b8f9df2d37347bfda904d78b7f08adffd (patch) | |
tree | a4433bd3c63066c33bcb4c93f158393bf84ff3e6 | |
parent | 8476bebae10fb86a4bf42cce42abf7b6fe49527c (diff) | |
download | gdb-9fa9327b8f9df2d37347bfda904d78b7f08adffd.tar.gz |
* signal.cc (sigaction): Fix if-statement typo.
-rw-r--r-- | winsup/cygwin/ChangeLog | 4 | ||||
-rw-r--r-- | winsup/cygwin/signal.cc | 481 |
2 files changed, 485 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d8e637c746f..07458195c62 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,7 @@ +2004-01-21 Nicholas Wourms <nwourms@netscape.net> + + * signal.cc (sigaction): Fix if-statement typo. + 2004-01-21 Christopher Faylor <cgf@redhat.com> * cygtls.cc (handle_threadlist_exception): Change logic, improve diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc new file mode 100644 index 00000000000..1c4a99810a3 --- /dev/null +++ b/winsup/cygwin/signal.cc @@ -0,0 +1,481 @@ +/* signal.cc + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. + + Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com + Significant changes by Sergey Okhapkin <sos@prospect.com.ru> + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include <stdlib.h> +#include "cygerrno.h" +#include <sys/cygwin.h> +#include "pinfo.h" +#include "sigproc.h" +#include "hires.h" +#include "security.h" +#include "cygtls.h" + +int sigcatchers; /* FIXME: Not thread safe. */ + +#define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL) + +static inline void +set_sigcatchers (void (*oldsig) (int), void (*cursig) (int)) +{ +#ifdef DEBUGGING + int last_sigcatchers = sigcatchers; +#endif + if (!sigtrapped (oldsig) && sigtrapped (cursig)) + sigcatchers++; + else if (sigtrapped (oldsig) && !sigtrapped (cursig)) + sigcatchers--; +#ifdef DEBUGGING + if (last_sigcatchers != sigcatchers) + sigproc_printf ("last %d, old %d, cur %p, cur %p", last_sigcatchers, + sigcatchers, oldsig, cursig); +#endif +} + +extern "C" _sig_func_ptr +signal (int sig, _sig_func_ptr func) +{ + sig_dispatch_pending (); + _sig_func_ptr prev; + + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func); + return (_sig_func_ptr) SIG_ERR; + } + + prev = global_sigs[sig].sa_handler; + global_sigs[sig].sa_handler = func; + global_sigs[sig].sa_mask = 0; + /* SA_RESTART is set to maintain BSD compatible signal behaviour by default. + This is also compatible with the behaviour of signal(2) in Linux. */ + global_sigs[sig].sa_flags |= SA_RESTART; + set_sigcatchers (prev, func); + + syscall_printf ("%p = signal (%d, %p)", prev, sig, func); + return prev; +} + +extern "C" int +nanosleep (const struct timespec *rqtp, struct timespec *rmtp) +{ + int res = 0; + sig_dispatch_pending (); + pthread_testcancel (); + + if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1) + || (unsigned int) rqtp->tv_nsec > 999999999) + { + set_errno (EINVAL); + return -1; + } + DWORD resolution = gtod.resolution (); + DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000 + + resolution - 1) / resolution) * resolution; + DWORD end_time = gtod.dmsecs () + req; + syscall_printf ("nanosleep (%ld)", req); + + int rc = pthread::cancelable_wait (signal_arrived, req); + DWORD rem; + if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX) + rem = 0; + if (rc == WAIT_OBJECT_0) + { + (void) call_signal_handler_now (); + set_errno (EINTR); + res = -1; + } + + if (rmtp) + { + rmtp->tv_sec = rem / 1000; + rmtp->tv_nsec = (rem % 1000) * 1000000; + } + + syscall_printf ("%d = nanosleep (%ld, %ld)", res, req, rem); + return res; +} + +extern "C" unsigned int +sleep (unsigned int seconds) +{ + struct timespec req, rem; + req.tv_sec = seconds; + req.tv_nsec = 0; + nanosleep (&req, &rem); + return rem.tv_sec + (rem.tv_nsec > 0); +} + +extern "C" unsigned int +usleep (unsigned int useconds) +{ + struct timespec req; + req.tv_sec = useconds / 1000000; + req.tv_nsec = (useconds % 1000000) * 1000; + int res = nanosleep (&req, 0); + return res; +} + +extern "C" int +sigprocmask (int sig, const sigset_t *set, sigset_t *oldset) +{ + return handle_sigprocmask (sig, set, oldset, myself->getsigmask ()); +} + +int __stdcall +handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& opmask) +{ + sig_dispatch_pending (); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (ESRCH); + syscall_printf ("SIG_ERR = sigprocmask signal %d out of range", sig); + return -1; + } + + if (oldset) + { + if (check_null_invalid_struct_errno (oldset)) + return -1; + *oldset = opmask; + } + + if (set) + { + if (check_invalid_read_struct_errno (set)) + return -1; + sigset_t newmask = opmask; + switch (sig) + { + case SIG_BLOCK: + /* add set to current mask */ + newmask |= *set; + break; + case SIG_UNBLOCK: + /* remove set from current mask */ + newmask &= ~*set; + break; + case SIG_SETMASK: + /* just set it */ + newmask = *set; + break; + default: + set_errno (EINVAL); + return -1; + } + (void) set_signal_mask (newmask, opmask); + } + return 0; +} + +static int +kill_worker (pid_t pid, int sig) +{ + sig_dispatch_pending (); + + int res = 0; + pinfo dest (pid); + BOOL sendSIGCONT; + + if (!dest) + { + set_errno (ESRCH); + return -1; + } + + if ((sendSIGCONT = (sig < 0))) + sig = -sig; + + DWORD process_state = dest->process_state; + if (sig == 0) + { + res = proc_exists (dest) ? 0 : -1; + if (res < 0) + set_errno (ESRCH); + } + else if ((res = sig_send (dest, sig))) + { + sigproc_printf ("%d = sig_send, %E ", res); + res = -1; + } + else if (sendSIGCONT) + (void) sig_send (dest, SIGCONT); + + syscall_printf ("%d = kill_worker (%d, %d), process_state %p", res, pid, sig, process_state); + return res; +} + +int +raise (int sig) +{ + return kill (myself->pid, sig); +} + +int +kill (pid_t pid, int sig) +{ + syscall_printf ("kill (%d, %d)", pid, sig); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("signal %d out of range", sig); + return -1; + } + + /* Silently ignore stop signals from a member of orphaned process group. + FIXME: Why??? */ + if (ISSTATE (myself, PID_ORPHANED) && + (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)) + sig = 0; + + return (pid > 0) ? kill_worker (pid, sig) : kill_pgrp (-pid, sig); +} + +int +kill_pgrp (pid_t pid, int sig) +{ + int res = 0; + int found = 0; + int killself = 0; + + sigproc_printf ("pid %d, signal %d", pid, sig); + + winpids pids ((DWORD) PID_MAP_RW); + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + + if (!proc_exists (p)) + continue; + + /* Is it a process we want to kill? */ + if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) || + (pid > 1 && p->pgid != pid) || + (sig < 0 && NOTSTATE (p, PID_STOPPED))) + continue; + sigproc_printf ("killing pid %d, pgrp %d, p->ctty %d, myself->ctty %d", + p->pid, p->pgid, p->ctty, myself->ctty); + if (p == myself) + killself++; + else if (kill_worker (p->pid, sig)) + res = -1; + found++; + } + + if (killself && kill_worker (myself->pid, sig)) + res = -1; + + if (!found) + { + set_errno (ESRCH); + res = -1; + } + syscall_printf ("%d = kill (%d, %d)", res, pid, sig); + return res; +} + +extern "C" int +killpg (pid_t pgrp, int sig) +{ + return kill (-pgrp, sig); +} + +extern "C" void +abort (void) +{ + sig_dispatch_pending (); + /* Flush all streams as per SUSv2. + From my reading of this document, this isn't strictly correct. + The streams are supposed to be flushed prior to exit. However, + if there is I/O in any signal handler that will not necessarily + be flushed. + However this is the way FreeBSD does it, and it is much easier to + do things this way, so... */ + if (_REENT->__cleanup) + _REENT->__cleanup (_REENT); + + /* Ensure that SIGABRT can be caught regardless of blockage. */ + sigset_t sig_mask; + sigfillset (&sig_mask); + sigdelset (&sig_mask, SIGABRT); + set_signal_mask (sig_mask); + + raise (SIGABRT); + (void) call_signal_handler_now (); /* Call any signal handler */ + do_exit (1); /* signal handler didn't exit. Goodbye. */ +} + +extern "C" int +sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact) +{ + sig_dispatch_pending (); + sigproc_printf ("signal %d, newact %p, oldact %p", sig, newact, oldact); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaction signal %d out of range", sig); + return -1; + } + + struct sigaction oa = global_sigs[sig]; + + if (newact) + { + if (sig == SIGKILL || sig == SIGSTOP) + { + set_errno (EINVAL); + return -1; + } + global_sigs[sig] = *newact; + if (newact->sa_handler == SIG_IGN) + sig_clear (sig); + if (newact->sa_handler == SIG_DFL && sig == SIGCHLD) + sig_clear (sig); + set_sigcatchers (oa.sa_handler, newact->sa_handler); + if (sig == SIGCHLD) + { + myself->process_state &= ~PID_NOCLDSTOP; + if (newact->sa_flags & SA_NOCLDSTOP) + myself->process_state |= PID_NOCLDSTOP; + } + } + + if (oldact) + *oldact = oa; + + return 0; +} + +extern "C" int +sigaddset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaddset signal %d out of range", sig); + return -1; + } + + *set |= SIGTOMASK (sig); + return 0; +} + +extern "C" int +sigdelset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig); + return -1; + } + + *set &= ~SIGTOMASK (sig); + return 0; +} + +extern "C" int +sigismember (const sigset_t *set, int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig); + return -1; + } + + if (*set & SIGTOMASK (sig)) + return 1; + else + return 0; +} + +extern "C" int +sigemptyset (sigset_t *set) +{ + *set = (sigset_t) 0; + return 0; +} + +extern "C" int +sigfillset (sigset_t *set) +{ + *set = ~((sigset_t) 0); + return 0; +} + +extern "C" int +sigsuspend (const sigset_t *set) +{ + return handle_sigsuspend (*set); +} + +extern "C" int +sigpause (int signal_mask) +{ + return handle_sigsuspend ((sigset_t) signal_mask); +} + +extern "C" int +pause (void) +{ + return handle_sigsuspend (myself->getsigmask ()); +} + +extern "C" int +siginterrupt (int sig, int flag) +{ + struct sigaction act; + (void) sigaction(sig, NULL, &act); + if (flag) + act.sa_flags &= ~SA_RESTART; + else + act.sa_flags |= SA_RESTART; + return sigaction (sig, &act, NULL); +} + + +extern "C" int +sigwait (const sigset_t *set, int *sig) +{ + pthread_testcancel (); + _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + if (!_my_tls.event) + { + __seterrno (); + return -1; + } + + _my_tls.sigwait_mask = *set; + + switch (WaitForSingleObject (_my_tls.event, INFINITE)) + { + case WAIT_OBJECT_0: + CloseHandle (_my_tls.event); + _my_tls.event = NULL; + *sig = InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0); + break; + default: + __seterrno (); + return -1; + } + return 0; +} |