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