newlib/winsup/cygwin/signal.cc

360 lines
6.9 KiB
C++
Raw Normal View History

2000-02-17 20:38:33 +01:00
/* 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"
2000-02-17 20:38:33 +01:00
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;
}
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;
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-29 18:24:59 +02:00
pinfo dest (pid);
2000-02-17 20:38:33 +01:00
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);
}
2000-02-17 20:38:33 +01:00
/* 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);
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-29 18:24:59 +02:00
winpids pids;
for (unsigned i = 0; i < pids.npids; i++)
2000-02-17 20:38:33 +01:00
{
pinfo p (pids[i]);
2000-02-17 20:38:33 +01:00
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 ());
}