OSDN Git Service

* include/tzfile.h: Add some missing entries.
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / signal.cc
1 /* signal.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
4
5    Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com
6    Significant changes by Sergey Okhapkin <sos@prospect.com.ru>
7
8 This file is part of Cygwin.
9
10 This software is a copyrighted work licensed under the terms of the
11 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
12 details. */
13
14 #include "winsup.h"
15 #include <stdlib.h>
16 #include "cygerrno.h"
17 #include <sys/cygwin.h>
18 #include "sigproc.h"
19 #include "pinfo.h"
20 #include "hires.h"
21
22 int sigcatchers;        /* FIXME: Not thread safe. */
23
24 #define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL)
25
26 static inline void
27 set_sigcatchers (void (*oldsig) (int), void (*cursig) (int))
28 {
29 #ifdef DEBUGGING
30   int last_sigcatchers = sigcatchers;
31 #endif
32   if (!sigtrapped (oldsig) && sigtrapped (cursig))
33     sigcatchers++;
34   else if (sigtrapped (oldsig) && !sigtrapped (cursig))
35     sigcatchers--;
36 #ifdef DEBUGGING
37   if (last_sigcatchers != sigcatchers)
38     sigproc_printf ("last %d, old %d, cur %p, cur %p", last_sigcatchers,
39                     sigcatchers, oldsig, cursig);
40 #endif
41 }
42
43 extern "C" _sig_func_ptr
44 signal (int sig, _sig_func_ptr func)
45 {
46   sig_dispatch_pending ();
47   _sig_func_ptr prev;
48
49   /* check that sig is in right range */
50   if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
51     {
52       set_errno (EINVAL);
53       syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func);
54       return (_sig_func_ptr) SIG_ERR;
55     }
56
57   prev = myself->getsig (sig).sa_handler;
58   myself->getsig (sig).sa_handler = func;
59   myself->getsig (sig).sa_mask = 0;
60   /* SA_RESTART is set to maintain BSD compatible signal behaviour by default.
61      This is also compatible with the behaviour of signal(2) in Linux. */
62   myself->getsig (sig).sa_flags |= SA_RESTART;
63   set_sigcatchers (prev, func);
64
65   syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
66   return prev;
67 }
68
69 extern "C" int
70 nanosleep (const struct timespec *rqtp, struct timespec *rmtp)
71 {
72   int res = 0;
73   sig_dispatch_pending ();
74   sigframe thisframe (mainthread);
75   pthread_testcancel ();
76
77   if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1)
78       || (unsigned int) rqtp->tv_nsec > 999999999)
79     {
80       set_errno (EINVAL);
81       return -1;
82     }
83   DWORD resolution = gtod.resolution ();
84   DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000
85                 + resolution - 1) / resolution) * resolution;
86   DWORD end_time = gtod.dmsecs () + req;
87   syscall_printf ("nanosleep (%ld)", req);
88
89   int rc = pthread::cancelable_wait (signal_arrived, req);
90   DWORD rem;
91   if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX)
92     rem = 0;
93   if (rc == WAIT_OBJECT_0)
94     {
95       (void) thisframe.call_signal_handler ();
96       set_errno (EINTR);
97       res = -1;
98     }
99
100   if (rmtp)
101     {
102       rmtp->tv_sec = rem / 1000;
103       rmtp->tv_nsec = (rem % 1000) * 1000000;
104     }
105
106   syscall_printf ("%d = nanosleep (%ld, %ld)", res, req, rem);
107   return res;
108 }
109
110 extern "C" unsigned int
111 sleep (unsigned int seconds)
112 {
113   struct timespec req, rem;
114   req.tv_sec = seconds;
115   req.tv_nsec = 0;
116   nanosleep (&req, &rem);
117   return rem.tv_sec + (rem.tv_nsec > 0);
118 }
119
120 extern "C" unsigned int
121 usleep (unsigned int useconds)
122 {
123   struct timespec req;
124   req.tv_sec = useconds / 1000000;
125   req.tv_nsec = (useconds % 1000000) * 1000;
126   int res = nanosleep (&req, 0);
127   return res;
128 }
129
130 extern "C" int
131 sigprocmask (int sig, const sigset_t *set, sigset_t *oldset)
132 {
133   sig_dispatch_pending ();
134   /* check that sig is in right range */
135   if (sig < 0 || sig >= NSIG)
136     {
137       set_errno (EINVAL);
138       syscall_printf ("SIG_ERR = sigprocmask signal %d out of range", sig);
139       return -1;
140     }
141
142   if (oldset)
143     *oldset = myself->getsigmask ();
144   if (set)
145     {
146       sigset_t newmask = myself->getsigmask ();
147       switch (sig)
148         {
149         case SIG_BLOCK:
150           /* add set to current mask */
151           newmask |= *set;
152           break;
153         case SIG_UNBLOCK:
154           /* remove set from current mask */
155           newmask &= ~*set;
156           break;
157         case SIG_SETMASK:
158           /* just set it */
159           newmask = *set;
160           break;
161         default:
162           set_errno (EINVAL);
163           return -1;
164         }
165       (void) set_process_mask (newmask);
166     }
167   return 0;
168 }
169
170 static int
171 kill_worker (pid_t pid, int sig)
172 {
173   sig_dispatch_pending ();
174
175   int res = 0;
176   pinfo dest (pid, PID_MAP_RW);
177   BOOL sendSIGCONT;
178
179   if (!dest)
180     {
181       set_errno (ESRCH);
182       return -1;
183     }
184
185   if ((sendSIGCONT = (sig < 0)))
186     sig = -sig;
187
188 #if 0
189   if (dest == myself && !sendSIGCONT)
190     dest = myself_nowait_nonmain;
191 #endif
192   if (sig == 0)
193     {
194       res = proc_exists (dest) ? 0 : -1;
195       if (res < 0)
196         set_errno (ESRCH);
197     }
198   else if ((res = sig_send (dest, sig)))
199     {
200       sigproc_printf ("%d = sig_send, %E ", res);
201       res = -1;
202     }
203   else if (sendSIGCONT)
204     (void) sig_send (dest, SIGCONT);
205
206   syscall_printf ("%d = kill_worker (%d, %d)", res, pid, sig);
207   return res;
208 }
209
210 int
211 raise (int sig)
212 {
213   return kill (myself->pid, sig);
214 }
215
216 int
217 kill (pid_t pid, int sig)
218 {
219   sigframe thisframe (mainthread);
220   syscall_printf ("kill (%d, %d)", pid, sig);
221   /* check that sig is in right range */
222   if (sig < 0 || sig >= NSIG)
223     {
224       set_errno (EINVAL);
225       syscall_printf ("signal %d out of range", sig);
226       return -1;
227     }
228
229   /* Silently ignore stop signals from a member of orphaned process group.
230      FIXME: Why??? */
231   if (ISSTATE (myself, PID_ORPHANED) &&
232       (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU))
233     sig = 0;
234
235   return (pid > 0) ? kill_worker (pid, sig) : kill_pgrp (-pid, sig);
236 }
237
238 int
239 kill_pgrp (pid_t pid, int sig)
240 {
241   int res = 0;
242   int found = 0;
243   int killself = 0;
244   sigframe thisframe (mainthread);
245
246   sigproc_printf ("pid %d, signal %d", pid, sig);
247
248   winpids pids ((DWORD) PID_MAP_RW);
249   for (unsigned i = 0; i < pids.npids; i++)
250     {
251       _pinfo *p = pids[i];
252
253       if (!proc_exists (p))
254         continue;
255
256       /* Is it a process we want to kill?  */
257       if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) ||
258           (pid > 1 && p->pgid != pid) ||
259           (sig < 0 && NOTSTATE (p, PID_STOPPED)))
260         continue;
261       sigproc_printf ("killing pid %d, pgrp %d, p->ctty %d, myself->ctty %d",
262                       p->pid, p->pgid, p->ctty, myself->ctty);
263       if (p == myself)
264         killself++;
265       else if (kill_worker (p->pid, sig))
266         res = -1;
267       found++;
268     }
269
270   if (killself && kill_worker (myself->pid, sig))
271     res = -1;
272
273   if (!found)
274     {
275       set_errno (ESRCH);
276       res = -1;
277     }
278   syscall_printf ("%d = kill (%d, %d)", res, pid, sig);
279   return res;
280 }
281
282 extern "C" int
283 killpg (pid_t pgrp, int sig)
284 {
285   return kill (-pgrp, sig);
286 }
287
288 extern "C" void
289 abort (void)
290 {
291   sig_dispatch_pending ();
292   sigframe thisframe (mainthread);
293   /* Flush all streams as per SUSv2.
294      From my reading of this document, this isn't strictly correct.
295      The streams are supposed to be flushed prior to exit.  However,
296      if there is I/O in any signal handler that will not necessarily
297      be flushed.
298      However this is the way FreeBSD does it, and it is much easier to
299      do things this way, so... */
300   if (_REENT->__cleanup)
301     _REENT->__cleanup (_REENT);
302
303   /* Ensure that SIGABRT can be caught regardless of blockage. */
304   sigset_t sig_mask;
305   sigfillset (&sig_mask);
306   sigdelset (&sig_mask, SIGABRT);
307   set_process_mask (sig_mask);
308
309   raise (SIGABRT);
310   (void) thisframe.call_signal_handler (); /* Call any signal handler */
311   do_exit (1);  /* signal handler didn't exit.  Goodbye. */
312 }
313
314 extern "C" int
315 sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
316 {
317   sig_dispatch_pending ();
318   sigproc_printf ("signal %d, newact %p, oldact %p", sig, newact, oldact);
319   /* check that sig is in right range */
320   if (sig < 0 || sig >= NSIG)
321     {
322       set_errno (EINVAL);
323       syscall_printf ("SIG_ERR = sigaction signal %d out of range", sig);
324       return -1;
325     }
326
327   struct sigaction oa = myself->getsig (sig);
328
329   if (newact)
330     {
331       if (sig == SIGKILL || sig == SIGSTOP)
332         {
333           set_errno (EINVAL);
334           return -1;
335         }
336       myself->getsig (sig) = *newact;
337       if (newact->sa_handler == SIG_IGN)
338         sig_clear (sig);
339       if (newact->sa_handler == SIG_DFL && sig == SIGCHLD)
340         sig_clear (sig);
341       set_sigcatchers (oa.sa_handler, newact->sa_handler);
342       if (sig == SIGCHLD)
343         {
344           myself->process_state &= ~PID_NOCLDSTOP;
345           if (newact->sa_flags & SA_NOCLDSTOP);
346             myself->process_state |= PID_NOCLDSTOP;
347         }
348     }
349
350   if (oldact)
351     *oldact = oa;
352
353   return 0;
354 }
355
356 extern "C" int
357 sigaddset (sigset_t *set, const int sig)
358 {
359   /* check that sig is in right range */
360   if (sig <= 0 || sig >= NSIG)
361     {
362       set_errno (EINVAL);
363       syscall_printf ("SIG_ERR = sigaddset signal %d out of range", sig);
364       return -1;
365     }
366
367   *set |= SIGTOMASK (sig);
368   return 0;
369 }
370
371 extern "C" int
372 sigdelset (sigset_t *set, const int sig)
373 {
374   /* check that sig is in right range */
375   if (sig <= 0 || sig >= NSIG)
376     {
377       set_errno (EINVAL);
378       syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
379       return -1;
380     }
381
382   *set &= ~SIGTOMASK (sig);
383   return 0;
384 }
385
386 extern "C" int
387 sigismember (const sigset_t *set, int sig)
388 {
389   /* check that sig is in right range */
390   if (sig <= 0 || sig >= NSIG)
391     {
392       set_errno (EINVAL);
393       syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig);
394       return -1;
395     }
396
397   if (*set & SIGTOMASK (sig))
398     return 1;
399   else
400     return 0;
401 }
402
403 extern "C" int
404 sigemptyset (sigset_t *set)
405 {
406   *set = (sigset_t) 0;
407   return 0;
408 }
409
410 extern "C" int
411 sigfillset (sigset_t *set)
412 {
413   *set = ~((sigset_t) 0);
414   return 0;
415 }
416
417 extern "C" int
418 sigsuspend (const sigset_t *set)
419 {
420   return handle_sigsuspend (*set);
421 }
422
423 extern "C" int
424 sigpause (int signal_mask)
425 {
426   return handle_sigsuspend ((sigset_t) signal_mask);
427 }
428
429 extern "C" int
430 pause (void)
431 {
432   return handle_sigsuspend (myself->getsigmask ());
433 }
434
435 extern "C" int
436 siginterrupt (int sig, int flag)
437 {
438   struct sigaction act;
439   (void)sigaction(sig, NULL, &act);
440   if (flag)
441     act.sa_flags &= ~SA_RESTART;
442   else
443     act.sa_flags |= SA_RESTART;
444   return sigaction(sig, &act, NULL);
445 }
446