Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/signal.cc')
-rw-r--r--winsup/cygwin/signal.cc367
1 files changed, 367 insertions, 0 deletions
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
new file mode 100644
index 000000000..5682b868b
--- /dev/null
+++ b/winsup/cygwin/signal.cc
@@ -0,0 +1,367 @@
+/* signal.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+
+ 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 <errno.h>
+#include "winsup.h"
+
+extern "C"
+_sig_func_ptr
+signal (int sig, _sig_func_ptr func)
+{
+ _sig_func_ptr prev;
+
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func);
+ return (_sig_func_ptr) SIG_ERR;
+ }
+
+ prev = myself->getsig(sig).sa_handler;
+ myself->getsig(sig).sa_handler = func;
+ myself->getsig(sig).sa_mask = 0;
+ syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
+ return prev;
+}
+
+extern "C"
+unsigned int
+sleep (unsigned int seconds)
+{
+ int res;
+ unsigned start_time;
+
+ start_time = GetTickCount ();
+
+ syscall_printf ("sleep (%d)", seconds);
+ res = WaitForSingleObject (signal_arrived, seconds * 1000);
+ if (res == WAIT_TIMEOUT)
+ {
+ syscall_printf ("0 = sleep (%d)", seconds);
+ return 0;
+ }
+ return (GetTickCount () - start_time)/1000;
+}
+
+extern "C"
+unsigned int
+usleep (unsigned int useconds)
+{
+ syscall_printf ("usleep (%d)", useconds);
+ WaitForSingleObject (signal_arrived, (useconds + 500) / 1000);
+ syscall_printf ("0 = usleep (%d)", useconds);
+ return 0;
+}
+
+extern "C"
+int
+sigprocmask (int sig, const sigset_t *set, sigset_t *oldset)
+{
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigprocmask sig %d out of range", sig);
+ return -1;
+ }
+
+ /* gcc can call sigprocmask when a builtin contructor is activated.
+ This can happen prior to the setup of myself */
+ if (!user_data)
+ return 0;
+
+ if (oldset)
+ *oldset = myself->getsigmask ();
+ if (set)
+ {
+ sigset_t newmask = myself->getsigmask ();
+ 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_process_mask (newmask);
+ }
+ return 0;
+}
+
+#if 0
+/* This is called _raise because the real raise is in newlib. */
+int
+_raise (int sig)
+{
+ if (!user_data)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+
+ return _kill (myself->pid, sig);
+}
+#endif
+
+static int
+kill_worker (pid_t pid, int sig)
+{
+ int res = 0;
+ pinfo *dest = procinfo (pid);
+ BOOL sendSIGCONT;
+
+ if (!dest)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+
+ dest->setthread2signal(NULL);
+
+ if ((sendSIGCONT = (sig < 0)))
+ sig = -sig;
+
+#if 0
+ if (dest == myself && !sendSIGCONT)
+ dest = myself_nowait_nonmain;
+#endif
+ if (sig == 0)
+ res = proc_exists (dest) ? 0 : -1;
+ 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)", res, pid, sig);
+ return res;
+}
+
+/* This is called _kill because the real kill is in newlib. */
+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 ("sig %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, sig %d", pid, sig);
+
+ for (int i = 0; i < cygwin_shared->p.size (); i++)
+ {
+ pinfo *p = &cygwin_shared->p.vec[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))
+ continue;
+ if (pid > 1 && p->pgid != pid)
+ continue;
+ if (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 (int pgrp, int sig)
+{
+ return _kill (-pgrp, sig);
+}
+
+extern "C"
+int
+sigaction (int sig,
+ const struct sigaction *newaction,
+ struct sigaction *oldaction)
+{
+ /* check that sig is in right range */
+ if (sig < 0 || sig >= NSIG)
+ {
+ set_errno (EINVAL);
+ syscall_printf ("SIG_ERR = sigaction sig %d out of range", sig);
+ return -1;
+ }
+
+ if (oldaction)
+ *oldaction = myself->getsig(sig);
+
+ if (newaction)
+ {
+ if ((sig == SIGKILL || sig == SIGSTOP) && newaction->sa_handler != SIG_DFL)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ myself->getsig(sig) = *newaction;
+ if (newaction->sa_handler == SIG_IGN)
+ sig_clear (sig);
+ if (newaction->sa_handler == SIG_DFL && sig == SIGCHLD)
+ sig_clear (sig);
+ }
+
+ 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 sig %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 sig %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 sig %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
+sigpending (sigset_t *set)
+{
+ unsigned bit;
+ *set = 0;
+ for (int sig = 1; sig < NSIG; sig++)
+ if (*myself->getsigtodo(sig) && myself->getsigmask () & (bit = SIGTOMASK (sig)))
+ *set |= bit;
+ 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 ());
+}