mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-18 12:29:32 +08:00
84c7d40932
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.
349 lines
6.7 KiB
C++
349 lines
6.7 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 <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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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 *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 ());
|
|
}
|