summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2004-01-21 15:47:58 +0000
committerChristopher Faylor <cgf@redhat.com>2004-01-21 15:47:58 +0000
commit9fa9327b8f9df2d37347bfda904d78b7f08adffd (patch)
treea4433bd3c63066c33bcb4c93f158393bf84ff3e6
parent8476bebae10fb86a4bf42cce42abf7b6fe49527c (diff)
downloadgdb-9fa9327b8f9df2d37347bfda904d78b7f08adffd.tar.gz
* signal.cc (sigaction): Fix if-statement typo.
-rw-r--r--winsup/cygwin/ChangeLog4
-rw-r--r--winsup/cygwin/signal.cc481
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;
+}