newlib/winsup/cygwin/signal.cc
Christopher Faylor 1dc16fc74b * exceptions.cc (set_console_handler): Don't allocate
console_handler_thread_waiter.  It is obsolete.
(ctrl_c_handler): Don't use console_handler_thread_waiter.
* path.cc (hash_path_name): Fix handling of relative names.  Make case
insensitive.
* path.h (suffix_info): Use initializers.
* pinfo.h (_pinfo): Avoid initializers for null case.
* resource.cc (fill_rusage): Zero rest of rusage structure.
* security.cc (set_process_privileges): Don't reopen parent process.  Just use
hMainProc.
* signal.cc (signal): Track when a signal handler has been used.
(sigaction): Ditto.
* sigproc.cc (pchildren): Use default initializer.
(zombies): Ditto.
(sigproc_terminate): Avoid closing handles that will be closed on exit anyway.
(wait_sig): Send signal to "parent" on EXECing, not FORKing.
(wait_subproc): Send SIGCHLD here rather than in proc_wait to avoid potential
muto conflicts.
* sigproc.h (sigthread): Don't initialize to zero.  It's the default.
* spawn.cc (spawn_guts): Fill in resources from exec parent prior to
termination.
* sync.h (muto): Don't initialize to zero.
* syscalls.cc (close_all_files): Use one lock around entire loop and call
fhandler close/release stuff directly.
(_read): Don't use ready_for_read if there are not signal handlers active.
* dcrt0.cc (dll_crt0_1): Fix display of "title".
(do_exit): Use pinfo exit method to exit.
(__api_fatal): Ditto.
* exceptions.cc (signal_exit): Ditto.
* fork.cc (fork_child): Remove debugging stuff.  Use pinfo_fixup_after fork in
place of exec_fixup_after_fork.
* pinfo.cc (pinfo_fixup_after_fork): New method.
(pinfo_fixup_in_spawned_child): Ditto.
(_pinfo::exit): New method.
(_pinfo::init): Remove recursion.  Detect pathological case where pinfo
structure already exists for new pid.
* pinfo.h (_pinfo): Reorganize slightly.  Add new method and new function
declarations.
* sigproc.cc (proc_exists): Previous simplification was a little to simple.
Try harder to detect if a process exists.
(proc_terminate): Use PID_EXITED setting to determine if process is still
around.
(WFSO): Remove debugging statement.
(WFMO): Ditto.
* spawn.cc (exec_fixup_after_fork): Eliminate.
(spawn_guts): Always set old_title to NULL.  Is it really needed?  Move
hexec_proc to pinfo.cc.  Call pinfo_fixup_in_spawned_child to eliminate handle
link after a spawn.
* include/sys/cygwin.h: Remove PID_NOT_IN_USE.  Add PID_EXITED.
2000-10-15 01:37:07 +00:00

361 lines
7.4 KiB
C++

/* 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 "winsup.h"
#include <errno.h>
#include "cygerrno.h"
#include <sys/cygwin.h>
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
int sigcatchers; /* FIXME: Not thread safe. */
#define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL)
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;
if (!sigtrapped (prev) && sigtrapped (func))
sigcatchers++;
else if (sigtrapped (prev) && !sigtrapped (func))
sigcatchers--;
syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
return prev;
}
extern "C" unsigned int
sleep (unsigned int seconds)
{
int rc;
unsigned start_time;
unsigned int res;
start_time = GetTickCount ();
syscall_printf ("sleep (%d)", seconds);
rc = WaitForSingleObject (signal_arrived, seconds * 1000);
if (rc == WAIT_TIMEOUT)
res = 0;
else
res = seconds - (GetTickCount () - start_time)/1000;
syscall_printf ("%d = sleep (%d)", res, seconds);
return res;
}
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;
}
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;
}
static int
kill_worker (pid_t pid, int sig)
{
int res = 0;
pinfo dest (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;
}
int
_raise (int sig)
{
return _kill (myself->pid, sig);
}
/* 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);
winpids pids;
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))
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 *newact, struct sigaction *oldact)
{
/* 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;
}
struct sigaction oa = myself->getsig (sig);
if (newact)
{
if ((sig == SIGKILL || sig == SIGSTOP) && newact->sa_handler != SIG_DFL)
{
set_errno (EINVAL);
return -1;
}
myself->getsig (sig) = *newact;
if (newact->sa_handler == SIG_IGN)
sig_clear (sig);
if (newact->sa_handler == SIG_DFL && sig == SIGCHLD)
sig_clear (sig);
if (!sigtrapped (oa.sa_handler) && sigtrapped (newact->sa_handler))
sigcatchers++;
else if (sigtrapped (oa.sa_handler) && !sigtrapped (newact->sa_handler))
sigcatchers--;
}
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 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 ());
}