1/* This testcase is part of GDB, the GNU debugger.
2
3   Copyright 2004, 2005, 2007, 2008, 2009, 2010, 2011
4   Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <signal.h>
25#include <sys/time.h>
26
27static volatile int done[2];
28static volatile int repeats[2];
29static int itimer[2] = { ITIMER_REAL, ITIMER_VIRTUAL };
30static int alarm[2] = { SIGALRM, SIGVTALRM };
31
32static void
33handler (int sig)
34{
35  int sigi;
36  switch (sig)
37    {
38    case SIGALRM: sigi = 0; break;
39    case SIGVTALRM: sigi = 1; break;
40    default: abort ();
41    }
42  if (repeats[sigi]++ > 3)
43    {
44      /* Hit with enough signals, cancel everything and get out.  */
45      {
46	struct itimerval itime;
47	memset (&itime, 0, sizeof (itime));
48	setitimer (itimer[sigi], &itime, NULL);
49      }
50      {
51	struct sigaction action;
52	memset (&action, 0, sizeof (action));
53	action.sa_handler = SIG_IGN;
54	sigaction (sig, &action, NULL);
55      }
56      done[sigi] = 1;
57      return;
58    }
59  /* Set up a nested virtual timer.  */
60  while (1)
61    {
62      /* Wait until a signal has become pending, that way when this
63	 handler returns it will be immediatly delivered leading to
64	 back-to-back signals.  */
65      sigset_t set;
66      sigemptyset (&set);
67      if (sigpending (&set) < 0)
68	{
69	  perror ("sigrepeat");
70	  abort ();
71	}
72      if (sigismember (&set, sig))
73	break;
74    }
75} /* handler */
76
77int
78main ()
79{
80  int i;
81  /* Set up the signal handler.  */
82  for (i = 0; i < 2; i++)
83    {
84      struct sigaction action;
85      memset (&action, 0, sizeof (action));
86      action.sa_handler = handler;
87      sigaction (alarm[i], &action, NULL);
88    }
89
90  /* Set up a rapidly repeating timers.  A timer, rather than SIGSEGV,
91     is used as after a timer handler returns the interrupted code can
92     safely resume.  The intent is for the program to swamp GDB with a
93     backlog of pending signals.  */
94  for (i = 0; i < 2; i++)
95    {
96      struct itimerval itime;
97      memset (&itime, 0, sizeof (itime));
98      itime.it_interval.tv_usec = 1;
99      itime.it_value.tv_usec = 250 * 1000;
100      setitimer (itimer[i], &itime, NULL);
101    }
102
103  /* Wait.  */
104  while (!done[0] && !done[1]); /* infinite loop */
105  return 0;
106}
107