OSDN Git Service

[Refactor] #40233 Moved display_store() from store.c to display-store.c/h
[hengband/hengband.git] / src / io / signal-handlers.c
1 /*!
2  * @file signal-handlers.c
3  * @brief シグナルハンドラの管理 / Controlling signal handlers
4  * @date 2020/02/23
5  * @author Hourier
6  */
7
8 #include "io/signal-handlers.h"
9 #include "cmd-io/cmd-dump.h"
10 #include "core/game-closer.h"
11 #include "floor/floor-events.h"
12 #include "io/write-diary.h"
13 #include "savedata/save.h"
14 #include "system/system-variables.h"
15 #include "term/term-color-types.h"
16 #include "world/world.h"
17
18 s16b signal_count; /* Hack -- Count interupts */
19
20 #ifdef HANDLE_SIGNALS
21
22 #include <signal.h>
23
24 /*!
25  * @brief OSからのシグナルを受けてサスペンド状態に入る /
26  * Handle signals -- suspend
27  * @param sig 受け取ったシグナル
28  * @details
29  * Actually suspend the game, and then resume cleanly
30  */
31 static void handle_signal_suspend(int sig)
32 {
33     (void)signal(sig, SIG_IGN);
34 #ifdef SIGSTOP
35     term_fresh();
36     term_xtra(TERM_XTRA_ALIVE, 0);
37     (void)kill(0, SIGSTOP);
38     term_xtra(TERM_XTRA_ALIVE, 1);
39     term_redraw();
40     term_fresh();
41 #endif
42     (void)signal(sig, handle_signal_suspend);
43 }
44
45 /*!
46  * todo ここにplayer_typeを追加すると関数ポインタ周りの収拾がつかなくなるので保留
47  * @brief OSからのシグナルを受けて中断、終了する /
48  * Handle signals -- simple (interrupt and quit)
49  * @param sig 受け取ったシグナル
50  * @details
51  * <pre>
52  * This function was causing a *huge* number of problems, so it has
53  * been simplified greatly.  We keep a global variable which counts
54  * the number of times the user attempts to kill the process, and
55  * we commit suicide if the user does this a certain number of times.
56  * We attempt to give "feedback" to the user as he approaches the
57  * suicide thresh-hold, but without penalizing accidental keypresses.
58  * To prevent messy accidents, we should reset this global variable
59  * whenever the user enters a keypress, or something like that.
60  * </pre>
61  */
62 static void handle_signal_simple(int sig)
63 {
64     (void)signal(sig, SIG_IGN);
65     if (!current_world_ptr->character_generated || current_world_ptr->character_saved)
66         quit(NULL);
67
68     signal_count++;
69     if (p_ptr->is_dead) {
70         (void)strcpy(p_ptr->died_from, _("強制終了", "Abortion"));
71         forget_lite(p_ptr->current_floor_ptr);
72         forget_view(p_ptr->current_floor_ptr);
73         clear_mon_lite(p_ptr->current_floor_ptr);
74         close_game(p_ptr);
75         quit(_("強制終了", "interrupt"));
76     } else if (signal_count >= 5) {
77         (void)strcpy(p_ptr->died_from, _("強制終了中", "Interrupting"));
78         forget_lite(p_ptr->current_floor_ptr);
79         forget_view(p_ptr->current_floor_ptr);
80         clear_mon_lite(p_ptr->current_floor_ptr);
81         p_ptr->playing = FALSE;
82         p_ptr->is_dead = TRUE;
83         p_ptr->leaving = TRUE;
84         close_game(p_ptr);
85         quit(_("強制終了", "interrupt"));
86     } else if (signal_count >= 4) {
87         term_xtra(TERM_XTRA_NOISE, 0);
88         term_erase(0, 0, 255);
89         term_putstr(0, 0, -1, TERM_WHITE, _("熟慮の上の自殺!", "Contemplating suicide!"));
90         term_fresh();
91     } else if (signal_count >= 2) {
92         term_xtra(TERM_XTRA_NOISE, 0);
93     }
94
95     (void)signal(sig, handle_signal_simple);
96 }
97
98 /*!
99  * todo ここにp_ptrを追加すると関数ポインタ周りの収拾がつかなくなるので保留
100  * @brief OSからのシグナルを受けて強制終了する /
101  * Handle signal -- abort, kill, etc
102  * @param sig 受け取ったシグナル
103  * @return なし
104  * @details
105  * <pre>
106  * This function was causing a *huge* number of problems, so it has
107  * been simplified greatly.  We keep a global variable which counts
108  * the number of times the user attempts to kill the process, and
109  * we commit suicide if the user does this a certain number of times.
110  * We attempt to give "feedback" to the user as he approaches the
111  * suicide thresh-hold, but without penalizing accidental keypresses.
112  * To prevent messy accidents, we should reset this global variable
113  * whenever the user enters a keypress, or something like that.
114  * </pre>
115  */
116 static void handle_signal_abort(int sig)
117 {
118     int wid, hgt;
119     term_get_size(&wid, &hgt);
120
121     (void)signal(sig, SIG_IGN);
122     if (!current_world_ptr->character_generated || current_world_ptr->character_saved)
123         quit(NULL);
124
125     forget_lite(p_ptr->current_floor_ptr);
126     forget_view(p_ptr->current_floor_ptr);
127     clear_mon_lite(p_ptr->current_floor_ptr);
128
129     term_erase(0, hgt - 1, 255);
130     term_putstr(0, hgt - 1, -1, TERM_RED, _("恐ろしいソフトのバグが飛びかかってきた!", "A gruesome software bug LEAPS out at you!"));
131
132     term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ...", "Panic save..."));
133
134     exe_write_diary(p_ptr, DIARY_GAMESTART, 0, _("----ゲーム異常終了----", "-- Tried Panic Save and Aborted Game --"));
135     term_fresh();
136
137     p_ptr->panic_save = 1;
138     (void)strcpy(p_ptr->died_from, _("(緊急セーブ)", "(panic save)"));
139
140     signals_ignore_tstp();
141
142     if (save_player(p_ptr)) {
143         term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ成功!", "Panic save succeeded!"));
144     } else {
145         term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ失敗!", "Panic save failed!"));
146     }
147
148     term_fresh();
149     quit(_("ソフトのバグ", "software bug"));
150 }
151
152 /*!
153  * @brief OSからのSIGTSTPシグナルを無視する関数 /
154  * Ignore SIGTSTP signals (keyboard suspend)
155  * @return なし
156  * @details
157  */
158 void signals_ignore_tstp(void)
159 {
160 #ifdef SIGTSTP
161     (void)signal(SIGTSTP, SIG_IGN);
162 #endif
163 }
164
165 /*!
166  * @brief OSからのSIGTSTPシグナルハンドラ /
167  * Handle SIGTSTP signals (keyboard suspend)
168  * @return なし
169  * @details
170  */
171 void signals_handle_tstp(void)
172 {
173 #ifdef SIGTSTP
174     (void)signal(SIGTSTP, handle_signal_suspend);
175 #endif
176 }
177
178 /*!
179  * @brief OSからのシグナルハンドルを初期化する /
180  * Prepare to handle the relevant signals
181  * @return なし
182  * @details
183  */
184 void signals_init(void)
185 {
186 #ifdef SIGHUP
187     (void)signal(SIGHUP, SIG_IGN);
188 #endif
189
190 #ifdef SIGTSTP
191     (void)signal(SIGTSTP, handle_signal_suspend);
192 #endif
193
194 #ifdef SIGINT
195     (void)signal(SIGINT, handle_signal_simple);
196 #endif
197
198 #ifdef SIGQUIT
199     (void)signal(SIGQUIT, handle_signal_simple);
200 #endif
201
202 #ifdef SIGFPE
203     (void)signal(SIGFPE, handle_signal_abort);
204 #endif
205
206 #ifdef SIGILL
207     (void)signal(SIGILL, handle_signal_abort);
208 #endif
209
210 #ifdef SIGTRAP
211     (void)signal(SIGTRAP, handle_signal_abort);
212 #endif
213
214 #ifdef SIGIOT
215     (void)signal(SIGIOT, handle_signal_abort);
216 #endif
217
218 #ifdef SIGKILL
219     (void)signal(SIGKILL, handle_signal_abort);
220 #endif
221
222 #ifdef SIGBUS
223     (void)signal(SIGBUS, handle_signal_abort);
224 #endif
225
226 #ifdef SIGSEGV
227     (void)signal(SIGSEGV, handle_signal_abort);
228 #endif
229
230 #ifdef SIGTERM
231     (void)signal(SIGTERM, handle_signal_abort);
232 #endif
233
234 #ifdef SIGPIPE
235     (void)signal(SIGPIPE, handle_signal_abort);
236 #endif
237
238 #ifdef SIGEMT
239     (void)signal(SIGEMT, handle_signal_abort);
240 #endif
241
242 #ifdef SIGDANGER
243     (void)signal(SIGDANGER, handle_signal_abort);
244 #endif
245
246 #ifdef SIGSYS
247     (void)signal(SIGSYS, handle_signal_abort);
248 #endif
249
250 #ifdef SIGXCPU
251     (void)signal(SIGXCPU, handle_signal_abort);
252 #endif
253
254 #ifdef SIGPWR
255     (void)signal(SIGPWR, handle_signal_abort);
256 #endif
257 }
258
259 #else
260
261 /*!
262  * @brief ダミー /
263  * Do nothing
264  */
265 void signals_ignore_tstp(void) {}
266
267 /*!
268  * @brief ダミー /
269  * Do nothing
270  */
271 void signals_handle_tstp(void) {}
272
273 /*!
274  * @brief ダミー /
275  * Do nothing
276  */
277 void signals_init(void) {}
278 #endif