1 /* signal.c - signal handling
2  *
3  * Copyright 1999, 2000, 2001  Jochen Voss.  */
4 
5 static const  char  rcsid[] = "$Id: signal.c 4839 2003-04-13 16:50:02Z voss $";
6 
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 
11 #include <stdio.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <assert.h>
15 
16 #include "moon-buggy.h"
17 #include "darray.h"
18 
19 
20 struct sig_info {
21   int  signum;
22   volatile  sig_atomic_t  pending;
23   void (*handler) (int);
24 };
25 static struct {
26   struct sig_info *data;
27   int  slots, used;
28 } sig_info_table;
29 
30 static volatile  sig_atomic_t  signal_arrived;
31 
32 static  sigset_t  full_set, old_sigset;
33 
34 
35 void
block_all(void)36 block_all (void)
37 /* Block all signals until `unblock' is called.  */
38 {
39   sigprocmask (SIG_BLOCK, &full_set, &old_sigset);
40 }
41 
42 void
unblock(void)43 unblock (void)
44 /* Undo the effect of `block_all'.  */
45 {
46   sigprocmask (SIG_SETMASK, &old_sigset, NULL);
47 }
48 
49 static void
install_signal(int signum,RETSIGTYPE (* handler)())50 install_signal (int signum, RETSIGTYPE (*handler) ())
51 /* Emulate the `signal' function via `sigaction'.  */
52 {
53   struct sigaction  action;
54   int  ret;
55 
56   action.sa_handler = handler;
57   sigemptyset (&action.sa_mask);
58   action.sa_flags = 0;
59   ret = sigaction (signum, &action, NULL);
60   assert (ret == 0);
61 }
62 
63 static RETSIGTYPE
generic_handler(int signum)64 generic_handler (int signum)
65 /* Interrupt handlers shouldn't do much.  So we just note that the
66  * signal arrived.  */
67 {
68   int  i;
69 
70   signal_arrived = 1;
71   for (i=0; i<sig_info_table.used; ++i) {
72     if (sig_info_table.data[i].signum == signum)  break;
73   }
74   assert (i<sig_info_table.used);
75   sig_info_table.data[i].pending = 1;
76 
77   if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) {
78     /* Pressing `C-c' twice exits, even if the program hangs.  */
79     install_signal (signum, SIG_DFL);
80   } else {
81     install_signal (signum, generic_handler);
82   }
83 }
84 
85 static void
my_signal(int signum,void (* handler)(int),int ignore_test)86 my_signal (int signum, void (*handler)(int), int ignore_test)
87 /* Install HANDLER as a new signal handler for signal SIGNUM.  But if
88  * IGNORE_TEST is true and SIGNUM was ignored before, do nothing.  */
89 {
90   struct sig_info *info;
91 
92   if (ignore_test) {
93     struct sigaction  action;
94 
95     sigaction (signum, NULL, &action);
96     if (action.sa_handler == SIG_IGN)  return;
97   }
98 
99   DA_ADD_EMPTY (sig_info_table, struct sig_info, info);
100   info->signum = signum;
101   info->pending = 0;
102   info->handler = handler;
103 
104   install_signal (signum, generic_handler);
105 }
106 
107 /************************************************************
108  * signal handlers
109  */
110 
111 static void
termination_handler(int signum)112 termination_handler (int signum)
113 {
114   prepare_for_exit ();
115   fprintf (stderr, "GAME ABORTED (signal %d)\n", signum);
116   /* We did `signal (signum, SIG_DFL)' in `generic_handler'.  */
117   raise (signum);
118 }
119 
120 static void
tstp_handler(int signum)121 tstp_handler (int signum)
122 {
123   clock_freeze ();
124   mode_signal (signum);
125   prepare_for_exit ();
126   install_signal (SIGTSTP, SIG_DFL);
127   raise (SIGTSTP);
128 }
129 
130 static void
cont_handler(int signum)131 cont_handler (int signum)
132 {
133   install_signal (SIGTSTP, tstp_handler);
134 
135   refresh ();
136   prepare_screen ();
137   mode_redraw ();
138   mode_signal (signum);
139   clock_thaw ();
140 }
141 
142 static void
winch_handler(int signum)143 winch_handler (int signum)
144 {
145   clock_freeze ();
146   delwin (moon);
147   delwin (status);
148   delwin (message);
149   sleep (1);
150   endwin ();
151 
152   refresh ();
153   allocate_windows ();
154   hide_cursor ();
155   mode_redraw ();
156   clock_thaw ();
157 }
158 
159 /************************************************************
160  * The outside-visible entry point
161  */
162 
163 void
initialise_signals(void)164 initialise_signals (void)
165 {
166   DA_INIT (sig_info_table, struct sig_info);
167   my_signal (SIGINT, termination_handler, 1);
168   my_signal (SIGHUP, termination_handler, 1);
169   my_signal (SIGTERM, termination_handler, 1);
170   my_signal (SIGCONT, cont_handler, 0);
171   my_signal (SIGTSTP, tstp_handler, 0);
172 #ifdef SIGWINCH
173   my_signal (SIGWINCH, winch_handler, 0);
174 #endif
175 
176   sigfillset (&full_set);
177 }
178 
179 int
handle_signals(void)180 handle_signals (void)
181 /* Execute signal actions, for all signals, which occured before.
182  * Return 1, if any action was taken.  */
183 {
184   int  res = 0;
185 
186   while (signal_arrived) {
187     int  i;
188 
189     signal_arrived = 0;
190     res = 1;
191     for (i=0; i<sig_info_table.used; ++i) {
192       if (sig_info_table.data[i].pending) {
193 	sig_info_table.data[i].pending = 0;
194 	sig_info_table.data[i].handler (sig_info_table.data[i].signum);
195       }
196     }
197   }
198   return  res;
199 }
200