Mercurial > hg > xemacs-beta
comparison src/signal.c @ 593:5fd7ba8b56e7
[xemacs-hg @ 2001-05-31 12:45:27 by ben]
xemacs-faq.texi: Major rewrite.
Update all MS Windows info to current.
Redo section 6.1 almost completely.
Incorporate sections 1 and 2 of Hrvoje's FAQ.
etags.el: Fix infloop when going up to the root.
s\cygwin32.h: Don't unilaterally include ntplay, but only when we're compiling
with native sound (look in configure now).
event-msw.c: Fix yet more problems with C-g handling.
Implement debug-mswindows-events.
event-stream.c, events.h, signal.c, sysdep.h:
Rearrange the signal-handling code to eliminate the former
spaghetti logic paths in it. Document clearly what
"low-level" and "high-level" timeouts are. Rename some
functions with unclear names (e.g. "...alarm...") to names
that reflect what they actually do (e.g. "...async_timeout...").
Fix numerous bugs discovered in the process.
console-x.h, event-Xt.c, event-msw.c, frame-x.c:
Hopefully make XEmacs properly maintain the "iconified"
state on frames at all times. This should fix the "can't
delete a frame with C-x 5 0 when there's another iconified
frame out there" bug.
Put a notice in of further changes that should probably
be made to clean up the frame-visibility support.
(especially directed at Jan Vroonhof)
lisp.h, miscplay.c:
Rename SBufbyte to CBufbyte to avoid a misleading name.
Eliminate UChar, which is not used anywhere and contributes
no semantic info. Add a comment about the documentation-only
properties of the char/unsigned char typedefs. Add
SChar_Binary as an explicitly `signed' version of Char_Binary
and put back the `signed' declarations in miscplay.c.
alloc.c:
Use char typedefs.
console-msw.c, device-msw.c, dialog-msw.c, editfns.c, fileio.c, glyphs-eimage.c, menubar-msw.c, ntplay.c, objects-msw.c, realpath.c, redisplay-msw.c, select-msw.c, syswindows.h, win32.c:
Eliminate numerous C++ errors.
frame-msw.c:
Eliminate numerous C++ errors and Mule-ize.
glyphs-msw.c:
Eliminate numerous C++ errors and use char typedefs.
configure.in:
Fix problems detecting both native and Linux sound on Cygwin
when compiled with --with-msw=no.
Rearrange file-coding handling a bit to avoid warning when
compiling with Mule.
configure.in, configure.usage, INSTALL:
Document XEMACS_CC and corresponding compiler option --xemacs-compiler.
Explain how to build xemacs using a C++ compiler.
author | ben |
---|---|
date | Thu, 31 May 2001 12:45:41 +0000 |
parents | abe6d1db359e |
children | 38db05db9cb5 |
comparison
equal
deleted
inserted
replaced
592:4f6ba8f1fb3d | 593:5fd7ba8b56e7 |
---|---|
1 /* Handling asynchronous signals. | 1 /* Handling asynchronous signals. |
2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. | 2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. |
3 Copyright (C) 1995, 1996 Ben Wing. | 3 Copyright (C) 1995, 1996, 2001 Ben Wing. |
4 | 4 |
5 This file is part of XEmacs. | 5 This file is part of XEmacs. |
6 | 6 |
7 XEmacs is free software; you can redistribute it and/or modify it | 7 XEmacs is free software; you can redistribute it and/or modify it |
8 under the terms of the GNU General Public License as published by the | 8 under the terms of the GNU General Public License as published by the |
25 #include "lisp.h" | 25 #include "lisp.h" |
26 | 26 |
27 #include "console.h" | 27 #include "console.h" |
28 #include "events.h" /* for signal_fake_event() */ | 28 #include "events.h" /* for signal_fake_event() */ |
29 #include "frame.h" | 29 #include "frame.h" |
30 #include "process.h" | |
30 #include "sysdep.h" | 31 #include "sysdep.h" |
31 #include "syssignal.h" | 32 #include "syssignal.h" |
32 #include "systime.h" | 33 #include "systime.h" |
33 | 34 |
34 #include "sysfile.h" | 35 #include "sysfile.h" |
45 /* Set to 1 when a SIGINT (or SIGQUIT) interrupt is processed. | 46 /* Set to 1 when a SIGINT (or SIGQUIT) interrupt is processed. |
46 maybe_read_quit_event() looks at this. */ | 47 maybe_read_quit_event() looks at this. */ |
47 volatile int sigint_happened; | 48 volatile int sigint_happened; |
48 | 49 |
49 /* Set to 1 when an asynch. timeout signal occurs. */ | 50 /* Set to 1 when an asynch. timeout signal occurs. */ |
50 static volatile int alarm_happened; | 51 static volatile int async_timeout_happened; |
52 | |
53 /* Set to 1 when a multiple of SLOWED_DOWN_INTERRUPTS_SECS elapses, | |
54 after slow_down_interrupts() is called. */ | |
55 static volatile int slowed_interrupt_timeout_happened; | |
51 | 56 |
52 /* This is used to synchronize setting the waiting_for_user_input_p | 57 /* This is used to synchronize setting the waiting_for_user_input_p |
53 flag. */ | 58 flag. */ |
54 static volatile int alarm_happened_while_emacs_was_blocking; | 59 static volatile int async_timeout_happened_while_emacs_was_blocking; |
55 | 60 |
56 /* See check_quit() for when this is set. */ | 61 /* See check_quit() for when this is set. */ |
57 int dont_check_for_quit; | 62 int dont_check_for_quit; |
58 | 63 |
59 #if !defined (SIGIO) && !defined (DONT_POLL_FOR_QUIT) | 64 static int poll_for_quit_id; |
60 int poll_for_quit_id; | 65 static int poll_for_sigchld_id; |
61 #endif | |
62 | |
63 #if defined(HAVE_UNIX_PROCESSES) && !defined(SIGCHLD) | |
64 int poll_for_sigchld_id; | |
65 #endif | |
66 | 66 |
67 /* This variable is used to communicate to a lisp | 67 /* This variable is used to communicate to a lisp |
68 process-filter/sentinel/asynchronous callback (via the function | 68 process-filter/sentinel/asynchronous callback (via the function |
69 Fwaiting_for_user_input_p below) whether XEmacs was waiting for | 69 Fwaiting_for_user_input_p below) whether XEmacs was waiting for |
70 user-input when that process-filter was called. */ | 70 user-input when that process-filter was called. */ |
80 naturally interruptible. */ | 80 naturally interruptible. */ |
81 | 81 |
82 JMP_BUF break_system_call_jump; | 82 JMP_BUF break_system_call_jump; |
83 volatile int can_break_system_calls; | 83 volatile int can_break_system_calls; |
84 | 84 |
85 static SIGTYPE alarm_signal (int signo); | |
86 | |
87 | |
85 | 88 |
86 /**********************************************************************/ | 89 /**********************************************************************/ |
87 /* Asynchronous timeout functions */ | 90 /* Asynchronous timeout functions */ |
88 /**********************************************************************/ | 91 /**********************************************************************/ |
92 | |
93 /* See the comment in event-stream.c, under major heading "Timeouts", | |
94 for the difference between low-level (one-shot) and high-level | |
95 (periodic/resignaling) timeouts. */ | |
89 | 96 |
90 /* The pending timers are stored in an ordered list, where the first timer | 97 /* The pending timers are stored in an ordered list, where the first timer |
91 on the list is the first one to fire. Times recorded here are | 98 on the list is the first one to fire. Times recorded here are |
92 absolute. */ | 99 absolute. */ |
93 static struct low_level_timeout *async_timer_queue; | 100 static struct low_level_timeout *async_timer_queue; |
129 EMACS_SET_SECS_USECS (interval, 0, 0); | 136 EMACS_SET_SECS_USECS (interval, 0, 0); |
130 | 137 |
131 set_one_shot_timer (interval); | 138 set_one_shot_timer (interval); |
132 } | 139 } |
133 | 140 |
141 | |
142 static void | |
143 init_async_timeouts (void) | |
144 { | |
145 signal (SIGALRM, alarm_signal); | |
146 async_timer_suppress_count = 0; | |
147 } | |
148 | |
149 /* Turn off async timeouts. */ | |
150 | |
151 static void | |
152 stop_async_timeouts (void) | |
153 { | |
154 if (async_timer_suppress_count == 0) | |
155 { | |
156 /* If timer was on, turn it off. */ | |
157 EMACS_TIME thyme; | |
158 EMACS_SET_SECS_USECS (thyme, 0, 0); | |
159 set_one_shot_timer (thyme); | |
160 } | |
161 async_timer_suppress_count++; | |
162 } | |
163 | |
164 /* Turn on async timeouts again. */ | |
165 | |
166 static void | |
167 start_async_timeouts (void) | |
168 { | |
169 assert (async_timer_suppress_count > 0); | |
170 async_timer_suppress_count--; | |
171 if (async_timer_suppress_count == 0) | |
172 { | |
173 /* Some callers turn off async timeouts and then use the alarm | |
174 for their own purposes; so reinitialize everything. */ | |
175 signal (SIGALRM, alarm_signal); | |
176 reset_interval_timer (); | |
177 } | |
178 } | |
179 | |
180 static void | |
181 handle_async_timeout_signal (void) | |
182 { | |
183 int interval_id; | |
184 int wakeup_id; | |
185 Lisp_Object fun, arg; | |
186 | |
187 /* No checks for Vinhibit_quit here or anywhere else in this file!!! | |
188 Otherwise critical quit will not work right. | |
189 The only check for Vinhibit_quit is in QUIT itself. */ | |
190 interval_id = pop_low_level_timeout (&async_timer_queue, 0); | |
191 | |
192 reset_interval_timer (); | |
193 if (async_timeout_happened_while_emacs_was_blocking) | |
194 { | |
195 async_timeout_happened_while_emacs_was_blocking = 0; | |
196 waiting_for_user_input_p = 1; | |
197 } | |
198 | |
199 wakeup_id = event_stream_resignal_wakeup (interval_id, 1, &fun, &arg); | |
200 | |
201 if (wakeup_id == poll_for_quit_id) | |
202 { | |
203 quit_check_signal_happened = 1; | |
204 quit_check_signal_tick_count++; | |
205 } | |
206 else if (wakeup_id == poll_for_sigchld_id) | |
207 { | |
208 kick_status_notify (); | |
209 } | |
210 else | |
211 /* call1 GC-protects its arguments */ | |
212 call1_trapping_errors ("Error in asynchronous timeout callback", | |
213 fun, arg); | |
214 | |
215 waiting_for_user_input_p = 0; | |
216 } | |
217 | |
218 /* The following two functions are the external interface onto | |
219 creating/deleting asynchronous interval timeouts, and are | |
220 called by event-stream.c. We call back to event-stream.c using | |
221 event_stream_resignal_wakeup(), when an interval goes off. */ | |
222 | |
134 int | 223 int |
135 event_stream_add_async_timeout (EMACS_TIME thyme) | 224 signal_add_async_interval_timeout (EMACS_TIME thyme) |
136 { | 225 { |
137 int id = add_low_level_timeout (&async_timer_queue, thyme); | 226 int id = add_low_level_timeout (&async_timer_queue, thyme); |
138 | 227 |
139 /* If this timeout is at the head of the queue, then we need to | 228 /* If this timeout is at the head of the queue, then we need to |
140 set the timer right now for this timeout. Otherwise, things | 229 set the timer right now for this timeout. Otherwise, things |
146 | 235 |
147 return id; | 236 return id; |
148 } | 237 } |
149 | 238 |
150 void | 239 void |
151 event_stream_remove_async_timeout (int id) | 240 signal_remove_async_interval_timeout (int id) |
152 { | 241 { |
153 int first = (async_timer_queue && async_timer_queue->id == id); | 242 int first = (async_timer_queue && async_timer_queue->id == id); |
154 remove_low_level_timeout (&async_timer_queue, id); | 243 remove_low_level_timeout (&async_timer_queue, id); |
155 | 244 |
156 /* If we removed the timeout from the head of the queue, then | 245 /* If we removed the timeout from the head of the queue, then |
157 we need to reset the interval timer right now. */ | 246 we need to reset the interval timer right now. */ |
158 if (first) | 247 if (first) |
159 reset_interval_timer (); | 248 reset_interval_timer (); |
160 } | 249 } |
161 | 250 |
162 /* Handle an alarm once each second and read pending input | 251 /* If alarm() gets called when polling isn't disabled, it will mess up |
163 so as to handle a C-g if it comes in. */ | 252 the asynchronous timeouts, and then C-g checking won't work again. |
164 | 253 Some libraries call alarm() directly, so we override the standard |
165 static SIGTYPE | 254 library's alarm() and abort() if the caller of the library function |
166 alarm_signal (int signo) | 255 didn't wrap in stop_interrupts()/start_interrupts(). |
167 { | 256 |
168 if (interrupts_slowed_down) | 257 NOTE: We could potentially avoid the need to wrap by adding a |
169 { | 258 one-shot timeout to simulate the alarm(), smashing our signal |
170 something_happened = 1; /* tell QUIT to wake up */ | 259 handler back into place, and calling the library function when the |
171 /* we are in "slowed-down interrupts" mode; the only alarm | 260 alarm goes off. But do we want to? We're not going to gain the |
172 happening here is the slowed-down quit-check alarm, so | 261 ability to C-g out of library functions this way (unless we forcibly |
173 we set this flag. | 262 longjmp() out of a signal handler, which is likely to lead to a |
174 | 263 crash). --ben */ |
175 Do NOT set alarm_happened, because we don't want anyone | 264 |
176 looking at the timeout queue. We didn't set it and | 265 #ifdef HAVE_SETITIMER |
177 it needs to stay the way it is. */ | 266 unsigned int |
178 quit_check_signal_happened = 1; | 267 alarm (unsigned int howlong) |
179 | 268 { |
180 #ifdef WIN32_NATIVE | 269 struct itimerval old_it, new_it; |
181 can_break_system_calls = 0; | 270 |
182 #else | |
183 /* can_break_system_calls is set when we want to break out of | |
184 non-interruptible system calls. */ | |
185 if (can_break_system_calls) | |
186 { | |
187 /* reset the flag for safety and such. Do this *before* | |
188 unblocking or reestablishing the signal to avoid potential | |
189 race conditions. */ | |
190 can_break_system_calls = 0; | |
191 EMACS_UNBLOCK_SIGNAL (signo); | |
192 EMACS_REESTABLISH_SIGNAL (signo, alarm_signal); | |
193 LONGJMP (break_system_call_jump, 0); | |
194 } | |
195 #endif | |
196 | |
197 EMACS_REESTABLISH_SIGNAL (signo, alarm_signal); | |
198 SIGRETURN; | |
199 } | |
200 | |
201 something_happened = 1; /* tell QUIT to wake up */ | |
202 alarm_happened = 1; | |
203 if (emacs_is_blocking) | |
204 alarm_happened_while_emacs_was_blocking = 1; | |
205 /* #### This is for QUITP. When it is run, it may not be the | |
206 place to do arbitrary stuff like run asynch. handlers, but | |
207 it needs to know whether the poll-for-quit asynch. timeout | |
208 went off. Rather than put the code in to compute this | |
209 specially, we just set this flag. Should fix this. */ | |
210 quit_check_signal_happened = 1; | |
211 | |
212 #ifdef HAVE_UNIXOID_EVENT_LOOP | |
213 signal_fake_event (); | |
214 #endif | |
215 | |
216 EMACS_REESTABLISH_SIGNAL (signo, alarm_signal); | |
217 SIGRETURN; | |
218 } | |
219 | |
220 static void | |
221 init_async_timeouts (void) | |
222 { | |
223 signal (SIGALRM, alarm_signal); | |
224 async_timer_suppress_count = 0; | |
225 } | |
226 | |
227 /* Turn off async timeouts. */ | |
228 | |
229 static void | |
230 stop_async_timeouts (void) | |
231 { | |
232 if (async_timer_suppress_count == 0) | |
233 { | |
234 /* If timer was on, turn it off. */ | |
235 EMACS_TIME thyme; | |
236 EMACS_SET_SECS_USECS (thyme, 0, 0); | |
237 set_one_shot_timer (thyme); | |
238 } | |
239 async_timer_suppress_count++; | |
240 } | |
241 | |
242 /* Turn on async timeouts again. */ | |
243 | |
244 static void | |
245 start_async_timeouts (void) | |
246 { | |
247 assert (async_timer_suppress_count > 0); | 271 assert (async_timer_suppress_count > 0); |
248 async_timer_suppress_count--; | 272 |
249 if (async_timer_suppress_count == 0) | 273 new_it.it_value.tv_sec = howlong; |
250 { | 274 new_it.it_value.tv_usec = 0; |
251 /* Some callers turn off async timeouts and then use the alarm | 275 new_it.it_interval.tv_sec = 0; |
252 for their own purposes; so reinitialize everything. */ | 276 new_it.it_interval.tv_usec = 0; |
253 signal (SIGALRM, alarm_signal); | 277 setitimer (ITIMER_REAL, &new_it, &old_it); |
254 reset_interval_timer (); | 278 |
255 } | 279 /* Never return zero if there was a timer outstanding. */ |
280 return old_it.it_value.tv_sec + (old_it.it_value.tv_usec > 0 ? 1 : 0); | |
281 } | |
282 #endif | |
283 | |
284 DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, 0, 0, 0, /* | |
285 Return non-nil if XEmacs is waiting for input from the user. | |
286 This is intended for use by asynchronous timeout callbacks and by | |
287 asynchronous process output filters and sentinels (not yet implemented | |
288 in XEmacs). It will always be nil if XEmacs is not inside of | |
289 an asynchronous timeout or process callback. | |
290 */ | |
291 ()) | |
292 { | |
293 return waiting_for_user_input_p ? Qt : Qnil; | |
294 } | |
295 | |
296 | |
297 /**********************************************************************/ | |
298 /* Enabling/disabling signals */ | |
299 /**********************************************************************/ | |
300 | |
301 static int interrupts_initted; | |
302 | |
303 void | |
304 stop_interrupts (void) | |
305 { | |
306 if (!interrupts_initted) | |
307 return; | |
308 #if defined(SIGIO) && !defined(BROKEN_SIGIO) | |
309 unrequest_sigio (); | |
310 #endif | |
311 stop_async_timeouts (); | |
312 } | |
313 | |
314 void | |
315 start_interrupts (void) | |
316 { | |
317 if (!interrupts_initted) | |
318 return; | |
319 #if defined(SIGIO) && !defined(BROKEN_SIGIO) | |
320 request_sigio (); | |
321 #endif | |
322 start_async_timeouts (); | |
323 } | |
324 | |
325 | |
326 static void | |
327 establish_slow_interrupt_timer (void) | |
328 { | |
329 EMACS_TIME thyme; | |
330 | |
331 EMACS_SET_SECS_USECS (thyme, SLOWED_DOWN_INTERRUPTS_SECS, 0); | |
332 set_one_shot_timer (thyme); | |
256 } | 333 } |
257 | 334 |
258 /* Some functions don't like being interrupted with SIGALRM or SIGIO. | 335 /* Some functions don't like being interrupted with SIGALRM or SIGIO. |
259 Previously we were calling stop_interrupts() / start_interrupts(), | 336 Previously we were calling stop_interrupts() / start_interrupts(), |
260 but then if the program hangs in one of those functions, e.g. | 337 but then if the program hangs in one of those functions, e.g. |
266 interrupt bogus ones. */ | 343 interrupt bogus ones. */ |
267 | 344 |
268 void | 345 void |
269 slow_down_interrupts (void) | 346 slow_down_interrupts (void) |
270 { | 347 { |
271 EMACS_TIME thyme; | |
272 | |
273 /* We have to set the flag *before* setting the slowed-down timer, | 348 /* We have to set the flag *before* setting the slowed-down timer, |
274 to avoid a race condition -- if the signal occurs between the | 349 to avoid a race condition -- if the signal occurs between the |
275 call to set_one_shot_timer() and the setting of this flag, | 350 call to set_one_shot_timer() and the setting of this flag, |
276 alarm_happened will get set, which will be a Bad Thing if | 351 async_timeout_happened will get set, which will be a Bad Thing if |
277 there were no timeouts on the queue. */ | 352 there were no timeouts on the queue. */ |
278 interrupts_slowed_down++; | 353 interrupts_slowed_down++; |
279 if (interrupts_slowed_down == 1) | 354 if (interrupts_slowed_down == 1) |
280 { | 355 { |
281 stop_interrupts (); | 356 stop_interrupts (); |
282 EMACS_SET_SECS_USECS (thyme, SLOWED_DOWN_INTERRUPTS_SECS, 0); | 357 establish_slow_interrupt_timer (); |
283 set_one_shot_timer (thyme); | |
284 } | 358 } |
285 } | 359 } |
286 | 360 |
287 void | 361 void |
288 speed_up_interrupts (void) | 362 speed_up_interrupts (void) |
294 race-condition reasons as above. */ | 368 race-condition reasons as above. */ |
295 interrupts_slowed_down--; | 369 interrupts_slowed_down--; |
296 } | 370 } |
297 } | 371 } |
298 | 372 |
299 static void | 373 /* Cheesy but workable implementation of sleep() that doesn't |
300 handle_alarm_going_off (void) | 374 interfere with our periodic timers. */ |
301 { | 375 |
302 int interval_id; | 376 void |
303 | 377 emacs_sleep (int secs) |
304 /* If asynch. timeouts are blocked, then don't do anything now, | 378 { |
305 but make this function get called again next QUIT. | 379 stop_interrupts (); |
306 | 380 sleep (secs); |
307 #### This is a bit inefficient because there will be function call | 381 start_interrupts (); |
308 overhead each time QUIT occurs. */ | |
309 | |
310 if (!NILP (Vinhibit_quit)) | |
311 { | |
312 something_happened = 1; | |
313 alarm_happened = 1; | |
314 return; | |
315 } | |
316 | |
317 interval_id = pop_low_level_timeout (&async_timer_queue, 0); | |
318 | |
319 reset_interval_timer (); | |
320 if (alarm_happened_while_emacs_was_blocking) | |
321 { | |
322 alarm_happened_while_emacs_was_blocking = 0; | |
323 waiting_for_user_input_p = 1; | |
324 } | |
325 event_stream_deal_with_async_timeout (interval_id); | |
326 waiting_for_user_input_p = 0; | |
327 } | |
328 | |
329 #ifdef HAVE_SETITIMER | |
330 unsigned int | |
331 alarm (unsigned int howlong) | |
332 { | |
333 struct itimerval old_it, new_it; | |
334 | |
335 /* If alarm() gets called when polling isn't disabled, it can mess | |
336 up the periodic timer. */ | |
337 assert (async_timer_suppress_count > 0); | |
338 | |
339 new_it.it_value.tv_sec = howlong; | |
340 new_it.it_value.tv_usec = 0; | |
341 new_it.it_interval.tv_sec = 0; | |
342 new_it.it_interval.tv_usec = 0; | |
343 setitimer (ITIMER_REAL, &new_it, &old_it); | |
344 | |
345 /* Never return zero if there was a timer outstanding. */ | |
346 return old_it.it_value.tv_sec + (old_it.it_value.tv_usec > 0 ? 1 : 0); | |
347 } | |
348 #endif | |
349 | |
350 DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, 0, 0, 0, /* | |
351 Return non-nil if XEmacs is waiting for input from the user. | |
352 This is intended for use by asynchronous timeout callbacks and by | |
353 asynchronous process output filters and sentinels (not yet implemented | |
354 in XEmacs). It will always be nil if XEmacs is not inside of | |
355 an asynchronous timeout or process callback. | |
356 */ | |
357 ()) | |
358 { | |
359 return waiting_for_user_input_p ? Qt : Qnil; | |
360 } | 382 } |
361 | 383 |
362 | 384 |
363 /**********************************************************************/ | 385 /**********************************************************************/ |
364 /* Control-G checking */ | 386 /* The mechanism that drives it all */ |
365 /**********************************************************************/ | 387 /**********************************************************************/ |
388 | |
389 /* called from QUIT when something_happened gets set (as a result of | |
390 a signal) */ | |
391 | |
392 int | |
393 check_what_happened (void) | |
394 { | |
395 something_happened = 0; | |
396 if (async_timeout_happened) | |
397 { | |
398 async_timeout_happened = 0; | |
399 handle_async_timeout_signal (); | |
400 } | |
401 if (slowed_interrupt_timeout_happened) | |
402 { | |
403 slowed_interrupt_timeout_happened = 0; | |
404 establish_slow_interrupt_timer (); | |
405 } | |
406 | |
407 return check_quit (); | |
408 } | |
409 | |
410 #ifdef SIGIO | |
411 | |
412 /* Signal handler for SIGIO. */ | |
413 | |
414 static void | |
415 input_available_signal (int signo) | |
416 { | |
417 something_happened = 1; /* tell QUIT to wake up */ | |
418 quit_check_signal_happened = 1; | |
419 quit_check_signal_tick_count++; | |
420 EMACS_REESTABLISH_SIGNAL (signo, input_available_signal); | |
421 SIGRETURN; | |
422 } | |
423 | |
424 #endif /* SIGIO */ | |
425 | |
426 /* Actual signal handler for SIGALRM. Called when: | |
427 | |
428 -- asynchronous timeouts (added with `add-async-timeout') go off | |
429 | |
430 -- when the poll-for-quit timer (used for C-g handling; more or | |
431 less when SIGIO is unavailable or BROKEN_SIGIO is defined) or | |
432 poll-for-sigchld timer (used when BROKEN_SIGCHLD is defined) go | |
433 off. The latter two timers, if set, normally go off every 1/4 | |
434 of a second -- see NORMAL_QUIT_CHECK_TIMEOUT_MSECS and | |
435 NORMAL_SIGCHLD_CHECK_TIMEOUT_MSECS. (Both of these timers are | |
436 treated like other asynchronous timeouts, but special-cased | |
437 in handle_async_timeout_signal().) | |
438 | |
439 -- we called slow_down_interrupts() and SLOWED_DOWN_INTERRUPTS_SECS | |
440 (or a multiple of it) has elapsed. | |
441 | |
442 Note that under Windows, we have no working setitimer(), so we | |
443 simulate it using the multimedia timeout functions, | |
444 e.g. timeSetEvent(). See setitimer() in nt.c. | |
445 | |
446 Note also that we don't actually *do* anything here (except in the | |
447 case of can_break_system_calls). Instead, we just set various | |
448 flags; next time QUIT is called, the flags will cause | |
449 check_what_happened() to be called, at which point we do everything | |
450 indicated by the flags. | |
451 */ | |
452 | |
453 static SIGTYPE | |
454 alarm_signal (int signo) | |
455 { | |
456 something_happened = 1; /* tell QUIT to wake up and call | |
457 check_what_happened() */ | |
458 | |
459 if (interrupts_slowed_down) | |
460 { | |
461 /* we are in "slowed-down interrupts" mode; the only alarm | |
462 happening here is the slowed-down quit-check alarm, so | |
463 we set this flag. | |
464 | |
465 Do NOT set async_timeout_happened, because we don't want | |
466 anyone looking at the timeout queue -- async timeouts | |
467 are disabled. */ | |
468 quit_check_signal_happened = 1; | |
469 quit_check_signal_tick_count++; | |
470 /* make sure we establish the slow timer again. */ | |
471 slowed_interrupt_timeout_happened = 1; | |
472 | |
473 /* can_break_system_calls is set when we want to break out of | |
474 non-interruptible system calls. */ | |
475 if (can_break_system_calls) | |
476 { | |
477 /* reset the flag for safety and such. Do this *before* | |
478 unblocking or reestablishing the signal to avoid potential | |
479 race conditions. */ | |
480 can_break_system_calls = 0; | |
481 #ifndef WIN32_NATIVE | |
482 /* #### I didn't add this WIN32_NATIVE check. I'm not sure | |
483 why it's here. But then again, someone needs to review | |
484 this can_break_system_calls stuff and see if it still | |
485 makes sense. --ben */ | |
486 EMACS_UNBLOCK_SIGNAL (signo); | |
487 EMACS_REESTABLISH_SIGNAL (signo, alarm_signal); | |
488 LONGJMP (break_system_call_jump, 0); | |
489 #endif | |
490 } | |
491 } | |
492 else | |
493 { | |
494 async_timeout_happened = 1; | |
495 if (emacs_is_blocking) | |
496 async_timeout_happened_while_emacs_was_blocking = 1; | |
497 /* #### This is for QUITP. When it is run, it may not be the | |
498 place to do arbitrary stuff like run asynch. handlers, but | |
499 it needs to know whether the poll-for-quit asynch. timeout | |
500 went off. Rather than put the code in to compute this | |
501 specially, we just set this flag. Should fix this. */ | |
502 quit_check_signal_happened = 1; | |
503 | |
504 #ifdef HAVE_UNIXOID_EVENT_LOOP | |
505 signal_fake_event (); | |
506 #endif | |
507 } | |
508 | |
509 EMACS_REESTABLISH_SIGNAL (signo, alarm_signal); | |
510 SIGRETURN; | |
511 } | |
366 | 512 |
367 /* Set this for debugging, to have a way to get out */ | 513 /* Set this for debugging, to have a way to get out */ |
368 int stop_character; /* #### not currently implemented */ | 514 int stop_character; /* #### not currently implemented */ |
369 | 515 |
370 /* This routine is called in response to a SIGINT or SIGQUIT. | 516 /* Signal handler for SIGINT and SIGQUIT. On TTY's, one of these two |
371 On TTY's, one of these two signals will get generated in response | 517 signals will get generated in response to C-g. (When running under |
372 to C-g. (When running under X, C-g is handled using the SIGIO | 518 X, C-g is handled using the SIGIO handler, which sets a flag |
373 handler, which sets a flag telling the QUIT macro to scan the | 519 telling the QUIT macro to scan the unread events for a ^G.) |
374 unread events for a ^G.) | 520 */ |
375 | |
376 Otherwise it sets the Lisp variable quit-flag not-nil. | |
377 This causes eval to throw, when it gets a chance. | |
378 If quit-flag is already non-nil, it stops the job right away. */ | |
379 | 521 |
380 static SIGTYPE | 522 static SIGTYPE |
381 interrupt_signal (int sig) | 523 interrupt_signal (int sig) |
382 { | 524 { |
383 /* This function can call lisp */ | 525 /* This function can call lisp */ |
386 /* Must preserve main program's value of errno. */ | 528 /* Must preserve main program's value of errno. */ |
387 int old_errno = errno; | 529 int old_errno = errno; |
388 | 530 |
389 EMACS_REESTABLISH_SIGNAL (sig, interrupt_signal); | 531 EMACS_REESTABLISH_SIGNAL (sig, interrupt_signal); |
390 | 532 |
391 /* with the macroized error-checking stuff, the garbage below | |
392 may mess things up because XCONSOLE() and such can use and | |
393 change global vars. */ | |
394 #if ! (defined (ERROR_CHECK_TYPECHECK) && defined (MACROIZE_ERROR_CHECKING)) | |
395 if (sigint_happened && CONSOLEP (Vcontrolling_terminal) && | 533 if (sigint_happened && CONSOLEP (Vcontrolling_terminal) && |
396 CONSOLE_LIVE_P (XCONSOLE (Vcontrolling_terminal)) && | 534 CONSOLE_LIVE_P (XCONSOLE (Vcontrolling_terminal)) && |
397 !emacs_is_blocking) | 535 !emacs_is_blocking) |
398 { | 536 { |
537 /* #### this is inherited from GNU Emacs. Do we really want this? | |
538 --ben */ | |
399 char c; | 539 char c; |
400 fflush (stdout); | 540 fflush (stdout); |
401 reset_initial_console (); | 541 reset_initial_console (); |
402 EMACS_UNBLOCK_SIGNAL (sig); | 542 EMACS_UNBLOCK_SIGNAL (sig); |
403 #ifdef SIGTSTP /* Support possible in later USG versions */ | 543 #ifdef SIGTSTP /* Support possible in later USG versions */ |
432 (XDEVICE (CONSOLE_SELECTED_DEVICE | 572 (XDEVICE (CONSOLE_SELECTED_DEVICE |
433 (XCONSOLE | 573 (XCONSOLE |
434 (Vcontrolling_terminal)))))); | 574 (Vcontrolling_terminal)))))); |
435 } | 575 } |
436 else | 576 else |
437 #endif /* ! (defined (ERROR_CHECKING) && defined (MACROIZE_ERROR_CHECKING)) */ | |
438 { | 577 { |
439 /* Else request quit when it's safe */ | 578 /* Else request quit when it's safe */ |
440 Vquit_flag = Qt; | 579 Vquit_flag = Qt; |
441 sigint_happened = 1; | 580 sigint_happened = 1; |
442 #ifdef HAVE_UNIXOID_EVENT_LOOP | 581 #ifdef HAVE_UNIXOID_EVENT_LOOP |
444 #endif | 583 #endif |
445 } | 584 } |
446 errno = old_errno; | 585 errno = old_errno; |
447 SIGRETURN; | 586 SIGRETURN; |
448 } | 587 } |
588 | |
589 | |
590 /**********************************************************************/ | |
591 /* Control-G checking */ | |
592 /**********************************************************************/ | |
449 | 593 |
450 static Lisp_Object | 594 static Lisp_Object |
451 restore_dont_check_for_quit (Lisp_Object val) | 595 restore_dont_check_for_quit (Lisp_Object val) |
452 { | 596 { |
453 dont_check_for_quit = XINT (val); | 597 dont_check_for_quit = XINT (val); |
497 event_stream_quit_p (); | 641 event_stream_quit_p (); |
498 return 1; | 642 return 1; |
499 } | 643 } |
500 else | 644 else |
501 return 0; | 645 return 0; |
502 } | |
503 | |
504 int | |
505 check_what_happened (void) /* called from QUIT when | |
506 something_happened gets set */ | |
507 { | |
508 something_happened = 0; | |
509 if (alarm_happened) | |
510 { | |
511 alarm_happened = 0; | |
512 handle_alarm_going_off (); | |
513 } | |
514 return check_quit (); | |
515 } | 646 } |
516 | 647 |
517 | 648 |
518 | 649 |
519 void | 650 void |
532 NORMAL_QUIT_CHECK_TIMEOUT_MSECS, | 663 NORMAL_QUIT_CHECK_TIMEOUT_MSECS, |
533 Qnil, Qnil, 1); | 664 Qnil, Qnil, 1); |
534 #endif /* not SIGIO and not DONT_POLL_FOR_QUIT */ | 665 #endif /* not SIGIO and not DONT_POLL_FOR_QUIT */ |
535 } | 666 } |
536 | 667 |
668 #if 0 /* not used anywhere */ | |
669 | |
537 void | 670 void |
538 reset_poll_for_quit (void) | 671 reset_poll_for_quit (void) |
539 { | 672 { |
540 #if !defined (SIGIO) && !defined (DONT_POLL_FOR_QUIT) | 673 #if !defined (SIGIO) && !defined (DONT_POLL_FOR_QUIT) |
541 if (poll_for_quit_id) | 674 if (poll_for_quit_id) |
543 event_stream_disable_wakeup (poll_for_quit_id, 1); | 676 event_stream_disable_wakeup (poll_for_quit_id, 1); |
544 poll_for_quit_id = 0; | 677 poll_for_quit_id = 0; |
545 } | 678 } |
546 #endif /* not SIGIO and not DONT_POLL_FOR_QUIT */ | 679 #endif /* not SIGIO and not DONT_POLL_FOR_QUIT */ |
547 } | 680 } |
681 | |
682 #endif /* 0 */ | |
548 | 683 |
549 #if defined(HAVE_UNIX_PROCESSES) && !defined(SIGCHLD) | 684 #if defined(HAVE_UNIX_PROCESSES) && !defined(SIGCHLD) |
550 | 685 |
551 static void | 686 static void |
552 init_poll_for_sigchld (void) | 687 init_poll_for_sigchld (void) |
563 NORMAL_SIGCHLD_CHECK_TIMEOUT_MSECS, | 698 NORMAL_SIGCHLD_CHECK_TIMEOUT_MSECS, |
564 Qnil, Qnil, 1); | 699 Qnil, Qnil, 1); |
565 } | 700 } |
566 | 701 |
567 #endif /* not SIGCHLD */ | 702 #endif /* not SIGCHLD */ |
568 | |
569 #ifdef SIGIO | |
570 | |
571 static void | |
572 input_available_signal (int signo) | |
573 { | |
574 something_happened = 1; /* tell QUIT to wake up */ | |
575 quit_check_signal_happened = 1; | |
576 quit_check_signal_tick_count++; | |
577 EMACS_REESTABLISH_SIGNAL (signo, input_available_signal); | |
578 SIGRETURN; | |
579 } | |
580 | |
581 #endif /* SIGIO */ | |
582 | |
583 | |
584 /**********************************************************************/ | |
585 /* Enabling/disabling signals */ | |
586 /**********************************************************************/ | |
587 | |
588 static int interrupts_initted; | |
589 | |
590 void | |
591 stop_interrupts (void) | |
592 { | |
593 if (!interrupts_initted) | |
594 return; | |
595 #if defined(SIGIO) && !defined(BROKEN_SIGIO) | |
596 unrequest_sigio (); | |
597 #endif | |
598 stop_async_timeouts (); | |
599 } | |
600 | |
601 void | |
602 start_interrupts (void) | |
603 { | |
604 if (!interrupts_initted) | |
605 return; | |
606 #if defined(SIGIO) && !defined(BROKEN_SIGIO) | |
607 request_sigio (); | |
608 #endif | |
609 start_async_timeouts (); | |
610 } | |
611 | |
612 /* Cheesy but workable implementation of sleep() that doesn't | |
613 interfere with our periodic timers. */ | |
614 | |
615 void | |
616 emacs_sleep (int secs) | |
617 { | |
618 stop_interrupts (); | |
619 sleep (secs); | |
620 start_interrupts (); | |
621 } | |
622 | 703 |
623 | 704 |
624 /************************************************************************/ | 705 /************************************************************************/ |
625 /* initialization */ | 706 /* initialization */ |
626 /************************************************************************/ | 707 /************************************************************************/ |