2000-02-17 20:38:33 +01:00
|
|
|
/* signal.cc
|
|
|
|
|
2005-01-03 19:11:00 +01:00
|
|
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
2011-04-18 13:26:37 +02:00
|
|
|
2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
2000-02-17 20:38:33 +01:00
|
|
|
|
|
|
|
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"
|
2002-01-11 03:24:06 +01:00
|
|
|
#include <stdlib.h>
|
2000-09-08 04:56:55 +02:00
|
|
|
#include <sys/cygwin.h>
|
2000-08-22 07:10:20 +02:00
|
|
|
#include "pinfo.h"
|
2003-11-28 21:55:59 +01:00
|
|
|
#include "sigproc.h"
|
|
|
|
#include "cygtls.h"
|
2005-11-04 21:45:56 +01:00
|
|
|
#include "path.h"
|
|
|
|
#include "fhandler.h"
|
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2000-10-15 03:37:07 +02:00
|
|
|
int sigcatchers; /* FIXME: Not thread safe. */
|
|
|
|
|
2006-03-23 16:55:59 +01:00
|
|
|
#define _SA_NORESTART 0x8000
|
|
|
|
|
|
|
|
static int sigaction_worker (int, const struct sigaction *, struct sigaction *, bool)
|
|
|
|
__attribute__ ((regparm (3)));
|
|
|
|
|
2000-10-15 03:37:07 +02:00
|
|
|
#define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL)
|
|
|
|
|
2000-10-21 06:53:49 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" _sig_func_ptr
|
2000-02-17 20:38:33 +01:00
|
|
|
signal (int sig, _sig_func_ptr func)
|
|
|
|
{
|
2003-08-19 06:10:42 +02:00
|
|
|
sig_dispatch_pending ();
|
2000-02-17 20:38:33 +01:00
|
|
|
_sig_func_ptr prev;
|
|
|
|
|
|
|
|
/* check that sig is in right range */
|
2001-02-16 19:49:20 +01:00
|
|
|
if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func);
|
|
|
|
return (_sig_func_ptr) SIG_ERR;
|
|
|
|
}
|
|
|
|
|
2003-11-28 23:13:57 +01:00
|
|
|
prev = global_sigs[sig].sa_handler;
|
2006-03-23 16:55:59 +01:00
|
|
|
struct sigaction& gs = global_sigs[sig];
|
|
|
|
if (gs.sa_flags & _SA_NORESTART)
|
|
|
|
gs.sa_flags &= ~SA_RESTART;
|
|
|
|
else
|
|
|
|
gs.sa_flags |= SA_RESTART;
|
|
|
|
|
2006-07-05 01:57:43 +02:00
|
|
|
gs.sa_mask = SIGTOMASK (sig);
|
2006-03-23 16:55:59 +01:00
|
|
|
gs.sa_handler = func;
|
|
|
|
gs.sa_flags &= ~SA_SIGINFO;
|
|
|
|
|
2000-10-21 06:53:49 +02:00
|
|
|
set_sigcatchers (prev, func);
|
2000-10-28 07:41:44 +02:00
|
|
|
|
2000-02-17 20:38:33 +01:00
|
|
|
syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
|
|
|
|
return prev;
|
|
|
|
}
|
|
|
|
|
2003-01-22 11:43:39 +01:00
|
|
|
extern "C" int
|
|
|
|
nanosleep (const struct timespec *rqtp, struct timespec *rmtp)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2003-01-22 11:43:39 +01:00
|
|
|
int res = 0;
|
2003-08-19 06:10:42 +02:00
|
|
|
sig_dispatch_pending ();
|
2003-01-14 21:05:49 +01:00
|
|
|
pthread_testcancel ();
|
|
|
|
|
2009-12-17 15:04:04 +01:00
|
|
|
if ((unsigned int) rqtp->tv_nsec > 999999999)
|
2003-01-22 11:43:39 +01:00
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-12-17 15:04:04 +01:00
|
|
|
unsigned int sec = rqtp->tv_sec;
|
2003-09-07 07:18:01 +02:00
|
|
|
DWORD resolution = gtod.resolution ();
|
2009-12-17 15:04:04 +01:00
|
|
|
bool done = false;
|
|
|
|
DWORD req;
|
2003-09-07 07:18:01 +02:00
|
|
|
DWORD rem;
|
2009-12-17 15:04:04 +01:00
|
|
|
|
|
|
|
while (!done)
|
2003-01-22 11:43:39 +01:00
|
|
|
{
|
2009-12-17 15:04:04 +01:00
|
|
|
/* Divide user's input into transactions no larger than 49.7
|
|
|
|
days at a time. */
|
2009-12-19 01:58:34 +01:00
|
|
|
if (sec > HIRES_DELAY_MAX / 1000)
|
2009-12-17 15:04:04 +01:00
|
|
|
{
|
2009-12-19 01:58:34 +01:00
|
|
|
req = ((HIRES_DELAY_MAX + resolution - 1)
|
2009-12-17 15:04:04 +01:00
|
|
|
/ resolution * resolution);
|
2009-12-19 01:58:34 +01:00
|
|
|
sec -= HIRES_DELAY_MAX / 1000;
|
2009-12-17 15:04:04 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
req = ((sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000
|
|
|
|
+ resolution - 1) / resolution) * resolution;
|
|
|
|
sec = 0;
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD end_time = gtod.dmsecs () + req;
|
|
|
|
syscall_printf ("nanosleep (%ld)", req);
|
|
|
|
|
|
|
|
int rc = cancelable_wait (signal_arrived, req);
|
|
|
|
if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX)
|
|
|
|
rem = 0;
|
|
|
|
if (rc == WAIT_OBJECT_0)
|
|
|
|
{
|
|
|
|
_my_tls.call_signal_handler ();
|
|
|
|
set_errno (EINTR);
|
|
|
|
res = -1;
|
|
|
|
break;
|
|
|
|
}
|
2003-01-22 11:43:39 +01:00
|
|
|
}
|
2000-09-16 15:19:52 +02:00
|
|
|
|
2003-01-22 11:43:39 +01:00
|
|
|
if (rmtp)
|
|
|
|
{
|
2009-12-17 15:04:04 +01:00
|
|
|
rmtp->tv_sec = sec + rem / 1000;
|
2003-01-22 11:43:39 +01:00
|
|
|
rmtp->tv_nsec = (rem % 1000) * 1000000;
|
2009-12-17 15:04:04 +01:00
|
|
|
if (sec)
|
|
|
|
{
|
|
|
|
rmtp->tv_nsec += rqtp->tv_nsec;
|
|
|
|
if (rmtp->tv_nsec >= 1000000000)
|
|
|
|
{
|
|
|
|
rmtp->tv_nsec -= 1000000000;
|
|
|
|
rmtp->tv_sec++;
|
|
|
|
}
|
|
|
|
}
|
2003-01-22 11:43:39 +01:00
|
|
|
}
|
2000-09-16 15:19:52 +02:00
|
|
|
|
2003-01-22 11:43:39 +01:00
|
|
|
syscall_printf ("%d = nanosleep (%ld, %ld)", res, req, rem);
|
2000-09-16 15:19:52 +02:00
|
|
|
return res;
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" unsigned int
|
2003-01-22 11:43:39 +01:00
|
|
|
sleep (unsigned int seconds)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2003-01-22 11:43:39 +01:00
|
|
|
struct timespec req, rem;
|
|
|
|
req.tv_sec = seconds;
|
|
|
|
req.tv_nsec = 0;
|
2009-12-17 15:04:04 +01:00
|
|
|
if (nanosleep (&req, &rem))
|
|
|
|
return rem.tv_sec + (rem.tv_nsec > 0);
|
|
|
|
return 0;
|
2003-01-22 11:43:39 +01:00
|
|
|
}
|
2003-01-14 21:05:49 +01:00
|
|
|
|
2003-01-22 11:43:39 +01:00
|
|
|
extern "C" unsigned int
|
2007-06-12 22:49:48 +02:00
|
|
|
usleep (useconds_t useconds)
|
2003-01-22 11:43:39 +01:00
|
|
|
{
|
|
|
|
struct timespec req;
|
|
|
|
req.tv_sec = useconds / 1000000;
|
|
|
|
req.tv_nsec = (useconds % 1000000) * 1000;
|
2009-12-17 15:04:04 +01:00
|
|
|
int res = nanosleep (&req, NULL);
|
2003-01-22 11:43:39 +01:00
|
|
|
return res;
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2005-03-09 22:07:56 +01:00
|
|
|
sigprocmask (int how, const sigset_t *set, sigset_t *oldset)
|
2003-11-28 21:55:59 +01:00
|
|
|
{
|
2008-02-15 18:53:11 +01:00
|
|
|
return handle_sigprocmask (how, set, oldset, _my_tls.sigmask);
|
2003-11-28 21:55:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int __stdcall
|
2005-03-09 22:07:56 +01:00
|
|
|
handle_sigprocmask (int how, const sigset_t *set, sigset_t *oldset, sigset_t& opmask)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2005-03-09 22:07:56 +01:00
|
|
|
/* check that how is in right range */
|
|
|
|
if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2005-03-09 22:07:56 +01:00
|
|
|
syscall_printf ("Invalid how value %d", how);
|
2004-02-26 06:10:49 +01:00
|
|
|
set_errno (EINVAL);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-07-03 04:40:30 +02:00
|
|
|
myfault efault;
|
|
|
|
if (efault.faulted (EFAULT))
|
|
|
|
return -1;
|
|
|
|
|
2000-02-17 20:38:33 +01:00
|
|
|
if (oldset)
|
2005-07-03 04:40:30 +02:00
|
|
|
*oldset = opmask;
|
2003-11-28 21:55:59 +01:00
|
|
|
|
2000-02-17 20:38:33 +01:00
|
|
|
if (set)
|
|
|
|
{
|
2003-11-28 21:55:59 +01:00
|
|
|
sigset_t newmask = opmask;
|
2005-03-09 22:07:56 +01:00
|
|
|
switch (how)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-07-06 22:05:03 +02:00
|
|
|
set_signal_mask (newmask, opmask);
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-26 21:50:25 +01:00
|
|
|
int __stdcall
|
|
|
|
_pinfo::kill (siginfo_t& si)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2011-04-17 23:45:28 +02:00
|
|
|
int res;
|
|
|
|
DWORD this_process_state;
|
2002-11-22 21:51:13 +01:00
|
|
|
|
2011-04-17 23:45:28 +02:00
|
|
|
sig_dispatch_pending ();
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2011-04-17 23:45:28 +02:00
|
|
|
if (exists ())
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2011-04-17 23:45:28 +02:00
|
|
|
bool sendSIGCONT;
|
2011-04-18 03:46:57 +02:00
|
|
|
this_process_state = process_state;
|
2011-04-17 23:45:28 +02:00
|
|
|
if ((sendSIGCONT = (si.si_signo < 0)))
|
|
|
|
si.si_signo = -si.si_signo;
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2011-04-17 23:45:28 +02:00
|
|
|
if (si.si_signo == 0)
|
|
|
|
res = 0;
|
|
|
|
else if ((res = sig_send (this, si)))
|
|
|
|
{
|
|
|
|
sigproc_printf ("%d = sig_send, %E ", res);
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
else if (sendSIGCONT)
|
|
|
|
{
|
|
|
|
siginfo_t si2 = {0};
|
|
|
|
si2.si_signo = SIGCONT;
|
|
|
|
si2.si_code = SI_KERNEL;
|
|
|
|
sig_send (this, si2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (si.si_signo == 0 && this)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2011-04-17 23:45:28 +02:00
|
|
|
this_process_state = process_state;
|
|
|
|
res = 0;
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
2011-04-17 23:45:28 +02:00
|
|
|
else
|
2004-01-19 06:46:54 +01:00
|
|
|
{
|
2011-04-17 23:45:28 +02:00
|
|
|
set_errno (ESRCH);
|
|
|
|
this_process_state = 0;
|
|
|
|
res = -1;
|
2004-01-19 06:46:54 +01:00
|
|
|
}
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2005-02-26 21:50:25 +01:00
|
|
|
syscall_printf ("%d = _pinfo::kill (%d, %d), process_state %p", res, pid,
|
|
|
|
si.si_signo, this_process_state);
|
2000-02-17 20:38:33 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-08-29 04:06:49 +02:00
|
|
|
int
|
2002-10-20 06:15:50 +02:00
|
|
|
raise (int sig)
|
2000-08-29 04:06:49 +02:00
|
|
|
{
|
2002-10-20 06:15:50 +02:00
|
|
|
return kill (myself->pid, sig);
|
2000-08-29 04:06:49 +02:00
|
|
|
}
|
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
static int
|
|
|
|
kill0 (pid_t pid, siginfo_t& si)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2004-01-19 06:46:54 +01:00
|
|
|
syscall_printf ("kill (%d, %d)", pid, si.si_signo);
|
2000-02-17 20:38:33 +01:00
|
|
|
/* check that sig is in right range */
|
2004-01-19 06:46:54 +01:00
|
|
|
if (si.si_signo < 0 || si.si_signo >= NSIG)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2004-01-19 06:46:54 +01:00
|
|
|
syscall_printf ("signal %d out of range", si.si_signo);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-02-26 21:50:25 +01:00
|
|
|
return (pid > 0) ? pinfo (pid)->kill (si) : kill_pgrp (-pid, si);
|
2004-01-19 06:46:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
killsys (pid_t pid, int sig)
|
|
|
|
{
|
2006-02-06 19:24:11 +01:00
|
|
|
siginfo_t si = {0};
|
2004-01-19 06:46:54 +01:00
|
|
|
si.si_signo = sig;
|
|
|
|
si.si_code = SI_KERNEL;
|
|
|
|
return kill0 (pid, si);
|
|
|
|
}
|
2005-12-23 23:50:20 +01:00
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
int
|
|
|
|
kill (pid_t pid, int sig)
|
|
|
|
{
|
2006-02-06 19:24:11 +01:00
|
|
|
siginfo_t si = {0};
|
2004-01-19 06:46:54 +01:00
|
|
|
si.si_signo = sig;
|
|
|
|
si.si_code = SI_USER;
|
|
|
|
return kill0 (pid, si);
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-01-19 06:46:54 +01:00
|
|
|
kill_pgrp (pid_t pid, siginfo_t& si)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
int found = 0;
|
|
|
|
int killself = 0;
|
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
sigproc_printf ("pid %d, signal %d", pid, si.si_signo);
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2003-09-17 03:15:56 +02:00
|
|
|
winpids pids ((DWORD) PID_MAP_RW);
|
2000-07-29 18:24:59 +02:00
|
|
|
for (unsigned i = 0; i < pids.npids; i++)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2000-11-05 07:42:23 +01:00
|
|
|
_pinfo *p = pids[i];
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2005-02-26 21:50:25 +01:00
|
|
|
if (!p->exists ())
|
2000-02-17 20:38:33 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is it a process we want to kill? */
|
2001-01-17 15:57:09 +01:00
|
|
|
if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) ||
|
2001-09-07 23:32:07 +02:00
|
|
|
(pid > 1 && p->pgid != pid) ||
|
2004-01-19 06:46:54 +01:00
|
|
|
(si.si_signo < 0 && NOTSTATE (p, PID_STOPPED)))
|
2000-10-31 00:19:45 +01:00
|
|
|
continue;
|
2005-11-14 05:28:45 +01:00
|
|
|
sigproc_printf ("killing pid %d, pgrp %d, p->%s, %s", p->pid, p->pgid,
|
|
|
|
p->__ctty (), myctty ());
|
2000-02-17 20:38:33 +01:00
|
|
|
if (p == myself)
|
|
|
|
killself++;
|
2005-02-26 21:50:25 +01:00
|
|
|
else if (p->kill (si))
|
2000-02-17 20:38:33 +01:00
|
|
|
res = -1;
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
|
2005-02-26 21:50:25 +01:00
|
|
|
if (killself && !exit_state && myself->kill (si))
|
2000-02-17 20:38:33 +01:00
|
|
|
res = -1;
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
set_errno (ESRCH);
|
|
|
|
res = -1;
|
|
|
|
}
|
2004-01-19 06:46:54 +01:00
|
|
|
syscall_printf ("%d = kill (%d, %d)", res, pid, si.si_signo);
|
2000-02-17 20:38:33 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2001-02-08 00:48:09 +01:00
|
|
|
killpg (pid_t pgrp, int sig)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2002-10-20 06:15:50 +02:00
|
|
|
return kill (-pgrp, sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
|
2002-01-11 03:24:06 +01:00
|
|
|
extern "C" void
|
|
|
|
abort (void)
|
|
|
|
{
|
2006-04-23 01:13:18 +02:00
|
|
|
_my_tls.incyg++;
|
2003-08-19 06:10:42 +02:00
|
|
|
sig_dispatch_pending ();
|
2002-01-11 03:24:06 +01:00
|
|
|
/* Ensure that SIGABRT can be caught regardless of blockage. */
|
|
|
|
sigset_t sig_mask;
|
|
|
|
sigfillset (&sig_mask);
|
|
|
|
sigdelset (&sig_mask, SIGABRT);
|
2008-02-15 18:53:11 +01:00
|
|
|
set_signal_mask (sig_mask, _my_tls.sigmask);
|
2002-01-11 03:24:06 +01:00
|
|
|
|
2002-10-20 06:15:50 +02:00
|
|
|
raise (SIGABRT);
|
2005-07-06 22:05:03 +02:00
|
|
|
_my_tls.call_signal_handler (); /* Call any signal handler */
|
2008-06-09 15:45:59 +02:00
|
|
|
|
|
|
|
/* Flush all streams as per SUSv2. */
|
|
|
|
if (_GLOBAL_REENT->__cleanup)
|
|
|
|
_GLOBAL_REENT->__cleanup (_GLOBAL_REENT);
|
2004-11-26 05:15:10 +01:00
|
|
|
do_exit (SIGABRT); /* signal handler didn't exit. Goodbye. */
|
2002-01-11 03:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-03-23 16:55:59 +01:00
|
|
|
static int
|
|
|
|
sigaction_worker (int sig, const struct sigaction *newact, struct sigaction *oldact, bool isinternal)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2003-08-19 06:10:42 +02:00
|
|
|
sig_dispatch_pending ();
|
2000-02-17 20:38:33 +01:00
|
|
|
/* check that sig is in right range */
|
|
|
|
if (sig < 0 || sig >= NSIG)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2004-03-25 16:15:27 +01:00
|
|
|
sigproc_printf ("signal %d, newact %p, oldact %p", sig, newact, oldact);
|
2001-04-01 02:06:17 +02:00
|
|
|
syscall_printf ("SIG_ERR = sigaction signal %d out of range", sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-11-28 23:13:57 +01:00
|
|
|
struct sigaction oa = global_sigs[sig];
|
2000-02-17 20:38:33 +01:00
|
|
|
|
2005-12-23 23:50:20 +01:00
|
|
|
if (!newact)
|
2004-03-25 16:15:27 +01:00
|
|
|
sigproc_printf ("signal %d, newact %p, oa %p", sig, newact, oa, oa.sa_handler);
|
2005-12-23 23:50:20 +01:00
|
|
|
else
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
2005-12-23 23:50:20 +01:00
|
|
|
sigproc_printf ("signal %d, newact %p (handler %p), oa %p", sig, newact, newact->sa_handler, oa, oa.sa_handler);
|
2001-02-16 19:49:20 +01:00
|
|
|
if (sig == SIGKILL || sig == SIGSTOP)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-03-23 16:55:59 +01:00
|
|
|
struct sigaction na = *newact;
|
|
|
|
struct sigaction& gs = global_sigs[sig];
|
|
|
|
if (!isinternal)
|
|
|
|
na.sa_flags &= ~_SA_INTERNAL_MASK;
|
|
|
|
gs = na;
|
|
|
|
if (!(gs.sa_flags & SA_NODEFER))
|
|
|
|
gs.sa_mask |= SIGTOMASK(sig);
|
|
|
|
if (gs.sa_handler == SIG_IGN)
|
2000-02-17 20:38:33 +01:00
|
|
|
sig_clear (sig);
|
2006-03-23 16:55:59 +01:00
|
|
|
if (gs.sa_handler == SIG_DFL && sig == SIGCHLD)
|
2000-02-17 20:38:33 +01:00
|
|
|
sig_clear (sig);
|
2006-03-23 16:55:59 +01:00
|
|
|
set_sigcatchers (oa.sa_handler, gs.sa_handler);
|
2003-09-01 04:05:32 +02:00
|
|
|
if (sig == SIGCHLD)
|
|
|
|
{
|
|
|
|
myself->process_state &= ~PID_NOCLDSTOP;
|
2006-03-23 16:55:59 +01:00
|
|
|
if (gs.sa_flags & SA_NOCLDSTOP)
|
2003-09-01 04:05:32 +02:00
|
|
|
myself->process_state |= PID_NOCLDSTOP;
|
|
|
|
}
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
|
|
|
|
2000-10-15 03:37:07 +02:00
|
|
|
if (oldact)
|
2006-03-23 16:55:59 +01:00
|
|
|
{
|
|
|
|
*oldact = oa;
|
|
|
|
oa.sa_flags &= ~_SA_INTERNAL_MASK;
|
|
|
|
}
|
2000-10-02 21:19:21 +02:00
|
|
|
|
2000-02-17 20:38:33 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-23 16:55:59 +01:00
|
|
|
extern "C" int
|
|
|
|
sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
|
|
|
|
{
|
|
|
|
return sigaction_worker (sig, newact, oldact, false);
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigaddset (sigset_t *set, const int sig)
|
|
|
|
{
|
|
|
|
/* check that sig is in right range */
|
|
|
|
if (sig <= 0 || sig >= NSIG)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2001-04-01 02:06:17 +02:00
|
|
|
syscall_printf ("SIG_ERR = sigaddset signal %d out of range", sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*set |= SIGTOMASK (sig);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigdelset (sigset_t *set, const int sig)
|
|
|
|
{
|
|
|
|
/* check that sig is in right range */
|
|
|
|
if (sig <= 0 || sig >= NSIG)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2001-04-01 02:06:17 +02:00
|
|
|
syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*set &= ~SIGTOMASK (sig);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigismember (const sigset_t *set, int sig)
|
|
|
|
{
|
|
|
|
/* check that sig is in right range */
|
|
|
|
if (sig <= 0 || sig >= NSIG)
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2001-04-01 02:06:17 +02:00
|
|
|
syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*set & SIGTOMASK (sig))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigemptyset (sigset_t *set)
|
|
|
|
{
|
|
|
|
*set = (sigset_t) 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigfillset (sigset_t *set)
|
|
|
|
{
|
|
|
|
*set = ~((sigset_t) 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigsuspend (const sigset_t *set)
|
|
|
|
{
|
|
|
|
return handle_sigsuspend (*set);
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
sigpause (int signal_mask)
|
|
|
|
{
|
|
|
|
return handle_sigsuspend ((sigset_t) signal_mask);
|
|
|
|
}
|
|
|
|
|
2000-10-02 21:19:21 +02:00
|
|
|
extern "C" int
|
2000-02-17 20:38:33 +01:00
|
|
|
pause (void)
|
|
|
|
{
|
2008-02-15 18:53:11 +01:00
|
|
|
return handle_sigsuspend (_my_tls.sigmask);
|
2000-02-17 20:38:33 +01:00
|
|
|
}
|
2002-11-15 20:04:36 +01:00
|
|
|
|
|
|
|
extern "C" int
|
|
|
|
siginterrupt (int sig, int flag)
|
|
|
|
{
|
|
|
|
struct sigaction act;
|
2006-03-22 05:13:55 +01:00
|
|
|
sigaction (sig, NULL, &act);
|
2002-11-15 20:04:36 +01:00
|
|
|
if (flag)
|
2006-03-23 16:55:59 +01:00
|
|
|
{
|
|
|
|
act.sa_flags &= ~SA_RESTART;
|
|
|
|
act.sa_flags |= _SA_NORESTART;
|
|
|
|
}
|
2002-11-15 20:04:36 +01:00
|
|
|
else
|
2006-03-23 16:55:59 +01:00
|
|
|
{
|
|
|
|
act.sa_flags &= ~_SA_NORESTART;
|
|
|
|
act.sa_flags |= SA_RESTART;
|
|
|
|
}
|
|
|
|
return sigaction_worker (sig, &act, NULL, true);
|
2002-11-15 20:04:36 +01:00
|
|
|
}
|
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
extern "C" int
|
|
|
|
sigwait (const sigset_t *set, int *sig_ptr)
|
|
|
|
{
|
|
|
|
int sig = sigwaitinfo (set, NULL);
|
|
|
|
if (sig > 0)
|
|
|
|
*sig_ptr = sig;
|
|
|
|
return sig > 0 ? 0 : -1;
|
|
|
|
}
|
2003-11-28 21:55:59 +01:00
|
|
|
|
|
|
|
extern "C" int
|
2004-01-19 06:46:54 +01:00
|
|
|
sigwaitinfo (const sigset_t *set, siginfo_t *info)
|
2003-11-28 21:55:59 +01:00
|
|
|
{
|
|
|
|
pthread_testcancel ();
|
2004-01-19 06:46:54 +01:00
|
|
|
HANDLE h;
|
|
|
|
h = _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
|
2004-02-26 06:10:49 +01:00
|
|
|
if (!h)
|
2003-11-28 21:55:59 +01:00
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_my_tls.sigwait_mask = *set;
|
2004-02-26 06:10:49 +01:00
|
|
|
sig_dispatch_pending (true);
|
2003-11-28 21:55:59 +01:00
|
|
|
|
2004-01-19 06:46:54 +01:00
|
|
|
int res;
|
2004-02-26 06:10:49 +01:00
|
|
|
switch (WaitForSingleObject (h, INFINITE))
|
2003-11-28 21:55:59 +01:00
|
|
|
{
|
|
|
|
case WAIT_OBJECT_0:
|
2004-02-26 06:10:49 +01:00
|
|
|
if (!sigismember (set, _my_tls.infodata.si_signo))
|
|
|
|
{
|
|
|
|
set_errno (EINTR);
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (info)
|
|
|
|
*info = _my_tls.infodata;
|
|
|
|
res = _my_tls.infodata.si_signo;
|
|
|
|
InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0);
|
|
|
|
}
|
2003-11-28 21:55:59 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
__seterrno ();
|
2004-01-19 06:46:54 +01:00
|
|
|
res = -1;
|
2003-11-28 21:55:59 +01:00
|
|
|
}
|
2004-01-19 06:46:54 +01:00
|
|
|
CloseHandle (h);
|
2004-02-26 06:10:49 +01:00
|
|
|
sigproc_printf ("returning sig %d", res);
|
2004-01-19 06:46:54 +01:00
|
|
|
return res;
|
2003-11-28 21:55:59 +01:00
|
|
|
}
|
2004-02-26 06:10:49 +01:00
|
|
|
|
2005-09-26 16:51:48 +02:00
|
|
|
/* FIXME: SUSv3 says that this function should block until the signal has
|
|
|
|
actually been delivered. Currently, this will only happen when sending
|
|
|
|
signals to the current process. It will not happen when sending signals
|
|
|
|
to other processes. */
|
2004-02-26 06:10:49 +01:00
|
|
|
extern "C" int
|
|
|
|
sigqueue (pid_t pid, int sig, const union sigval value)
|
|
|
|
{
|
2006-02-06 19:24:11 +01:00
|
|
|
siginfo_t si = {0};
|
2004-02-26 06:10:49 +01:00
|
|
|
pinfo dest (pid);
|
|
|
|
if (!dest)
|
|
|
|
{
|
|
|
|
set_errno (ESRCH);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
si.si_signo = sig;
|
2005-09-26 16:51:48 +02:00
|
|
|
si.si_code = SI_QUEUE;
|
2004-02-26 06:10:49 +01:00
|
|
|
si.si_value = value;
|
|
|
|
return sig_send (dest, si);
|
|
|
|
}
|