aboutsummaryrefslogtreecommitdiffstats
path: root/src/blockinput.h
diff options
context:
space:
mode:
authorPaul Eggert2012-09-23 01:44:20 -0700
committerPaul Eggert2012-09-23 01:44:20 -0700
commit4d7e6e51dd4acecff466a28d958c50f34fc130b8 (patch)
tree5e340d48fb69f9a40a4304cc94db2006caefe51f /src/blockinput.h
parent8f4635e97e1587c4026ec83fc1bd9f8954775915 (diff)
downloademacs-4d7e6e51dd4acecff466a28d958c50f34fc130b8.tar.gz
emacs-4d7e6e51dd4acecff466a28d958c50f34fc130b8.zip
Simplify and avoid signal-handling races.
* nt/inc/ms-w32.h (emacs_raise): New macro. * src/alloc.c (die): * src/sysdep.c (emacs_abort) [HAVE_NTGUI]: Avoid recursive loop if there's a fatal error in the function itself. * src/atimer.c (pending_atimers): * src/blockinput.h: Don't include "atimer.h"; no longer needed. (interrupt_input_pending): Remove. All uses removed. pending_signals now counts both atimers and ordinary interrupts. This is less racy than having three separate pending-signal flags. (block_input, unblock_input, totally_unblock_input, unblock_input_to) (input_blocked_p): Rename from their upper-case counterparts BLOCK_INPUT, UNBLOCK_INPUT, TOTALLY_UNBLOCK_INPUT, UNBLOCK_INPUT_TO, INPUT_BLOCKED_P, and turn into functions. All uses changed. This makes it easier to access volatile variables more accurately. (BLOCK_INPUT_RESIGNAL): Remove. All uses replaced by unblock_input (). (input_blocked_p): Prefer this to 'interrupt_input_blocked', as that's more reliable if the code is buggy and sets interrupt_input_blocked to a negative value. All uses changed. * src/atimer.c (deliver_alarm_signal): Remove. No need to deliver this to the parent; any thread can handle this signal now. All uses replaced by underlying handler. * src/atimer.c (turn_on_atimers): * src/dispnew.c (handle_window_change_signal): * src/emacs.c (handle_danger_signal): * src/keyboard.c (kbd_buffer_get_event): Don't reestablish signal handler; not needed with sigaction. * src/blockinput.h (UNBLOCK_INPUT_TO, TOTALLY_UNBLOCK_INPUT) (UNBLOCK_INPUT_TO): Rework to avoid unnecessary accesses to volatile variables. (UNBLOCK_INPUT_TO): Now a function. (totally_unblock_input, unblock_input): New decls. * src/data.c (handle_arith_signal, deliver_arith_signal): Move to sysdep.c (init_data): Remove. Necessary stuff now done in init_signal. * src/emacs.c, src/xdisp.c: Include "atimer.h", since we invoke atimer functions. * src/emacs.c (handle_fatal_signal, deliver_fatal_signal): Move to sysdep.c. (fatal_error_code): Remove; no longer needed. (terminate_due_to_signal): Rename from fatal_error_backtrace, since it doesn't always backtrace. All uses changed. No need to reset signal to default, since sigaction and/or die does that for us now. Use emacs_raise (FOO), not kill (getpid (), FOO). (main): Check more-accurately whether we're dumping. Move fatal-error setup to sysdep.c * src/floatfns.c: Do not include "syssignal.h"; no longer needed. * src/gtkutil.c (xg_get_file_name, xg_get_font): Remove no-longer-needed signal-mask manipulation. * src/keyboard.c, src/process.c (POLL_FOR_INPUT): Don't depend on USE_ASYNC_EVENTS, a symbol that is never defined. * src/keyboard.c (read_avail_input): Remove. All uses replaced by gobble_input. (Ftop_level): Use TOTALLY_UNBLOCK_INPUT rather than open code. (kbd_buffer_store_event_hold, gobble_input): (record_asynch_buffer_change) [USABLE_SIGIO]: (store_user_signal_events): No need to mess with signal mask. (gobble_input): If blocking input and there are terminals, simply set pending_signals to 1 and return. All hooks changed to not worry about whether input is blocked. (process_pending_signals): Clear pending_signals before processing them, in case a signal comes in while we're processing. By convention callers now test pending_signals before calling us. (UNBLOCK_INPUT_TO, unblock_input, totally_unblock_input): New functions, to support changes to blockinput.h. (handle_input_available_signal): Now extern. (reinvoke_input_signal): Remove. All uses replaced by handle_async_input. (quit_count): Now volatile, since a signal handler uses it. (handle_interrupt): Now takes bool IN_SIGNAL_HANDLER as arg. All callers changed. Block SIGINT only if not already blocked. Clear sigmask reliably, even if Fsignal returns, which it can. Omit unnecessary accesses to volatile var. (quit_throw_to_read_char): No need to restore sigmask. * src/keyboard.c (gobble_input, handle_user_signal): * src/process.c (wait_reading_process_output): Call signal-handling code rather than killing ourselves. * src/lisp.h: Include <float.h>, for... (IEEE_FLOATING_POINT): New macro, moved here to avoid duplication. (pending_signals): Now volatile. (syms_of_data): Now const if IEEE floating point. (handle_input_available_signal) [USABLE_SIGIO]: (terminate_due_to_signal, record_child_status_change): New decls. * src/process.c (create_process): Avoid disaster if memory is exhausted while we're processing a vfork, by tightening the critical section around the vfork. (send_process_frame, process_sent_to, handle_pipe_signal) (deliver_pipe_signal): Remove. No longer needed, as Emacs now ignores SIGPIPE. (send_process): No need for setjmp/longjmp any more, since the SIGPIPE stuff is now gone. Instead, report an error if errno is EPIPE. (record_child_status_change): Now extern. PID and W are now args. Return void, not bool. All callers changed. * src/sysdep.c (wait_debugging) [(BSD_SYSTEM || HPUX) && !defined (__GNU__)]: Remove. All uses removed. This bug should be fixed now in a different way. (wait_for_termination_1): Use waitpid rather than sigsuspend, and record the child status change directly. This avoids the need to futz with the signal mask. (process_fatal_action): Move here from emacs.c. (emacs_sigaction_flags): New function, containing much of what used to be in emacs_sigaction_init. (emacs_sigaction_init): Use it. Block nonfatal system signals that are caught by emacs, to make races less likely. (deliver_process_signal): Rename from handle_on_main_thread. All uses changed. (BACKTRACE_LIMIT_MAX): Now at top level. (thread_backtrace_buffer, threadback_backtrace_pointers): New static vars. (deliver_thread_signal, deliver_fatal_thread_signal): New functions, for more-accurate delivery of thread-specific signals. (handle_fatal_signal, deliver_fatal_signal): Move here from emacs.c. (deliver_arith_signal): Handle in this thread, not in the main thread, since it's triggered by this thread. (maybe_fatal_sig): New function. (init_signals): New arg DUMPING so that we can be more accurate about whether we're dumping. Caller changed. Treat thread-specific signals differently from process-general signals. Block all signals while handling fatal error; that's safer. xsignal from SIGFPE only on non-IEEE hosts, treating it as fatal on IEEE hosts. When batch, ignore SIGHUP, SIGINT, SIGTERM if they were already ignored. Ignore SIGPIPE unless batch. (emacs_backtrace): Output backtrace for the appropriate thread, which is not necessarily the main thread. * src/syssignal.h: Include <stdbool.h>. (emacs_raise): New macro. * src/xterm.c (x_connection_signal): Remove; no longer needed now that we use sigaction. (x_connection_closed): No need to mess with sigmask now. (x_initialize): No need to reset SIGPIPE handler here, since init_signals does this for us now. Fixes: debbugs:12471
Diffstat (limited to 'src/blockinput.h')
-rw-r--r--src/blockinput.h118
1 files changed, 36 insertions, 82 deletions
diff --git a/src/blockinput.h b/src/blockinput.h
index 7501bfc91a0..70822e29be7 100644
--- a/src/blockinput.h
+++ b/src/blockinput.h
@@ -19,103 +19,57 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19#ifndef EMACS_BLOCKINPUT_H 19#ifndef EMACS_BLOCKINPUT_H
20#define EMACS_BLOCKINPUT_H 20#define EMACS_BLOCKINPUT_H
21 21
22#include "atimer.h" 22INLINE_HEADER_BEGIN
23#ifndef BLOCKINPUT_INLINE
24# define BLOCKINPUT_INLINE INLINE
25#endif
23 26
24/* When Emacs is using signal-driven input, the processing of those 27/* Emacs should avoid doing anything hairy in a signal handler, because
25 input signals can get pretty hairy. For example, when Emacs is 28 so many system functions are non-reentrant. For example, malloc
26 running under X windows, handling an input signal can entail 29 and the Xlib functions aren't usually re-entrant, so if they were
27 retrieving events from the X event queue, or making other X calls. 30 used by the SIGIO handler, we'd lose.
28
29 If an input signal occurs while Emacs is in the midst of some
30 non-reentrant code, and the signal processing invokes that same
31 code, we lose. For example, malloc and the Xlib functions aren't
32 usually re-entrant, and both are used by the X input signal handler
33 - if we try to process an input signal in the midst of executing
34 any of these functions, we'll lose.
35 31
36 To avoid this, we make the following requirements: 32 To avoid this, we make the following requirements:
37 33
38 * Everyone must evaluate BLOCK_INPUT before entering these functions, 34 * Everyone must evaluate BLOCK_INPUT before performing actions that
39 and then call UNBLOCK_INPUT after performing them. Calls 35 might conflict with a signal handler, and then call UNBLOCK_INPUT
40 BLOCK_INPUT and UNBLOCK_INPUT may be nested. 36 after performing them. Calls BLOCK_INPUT and UNBLOCK_INPUT may be
37 nested.
41 38
42 * Any complicated interrupt handling code should test 39 * Any complicated interrupt handling code should test
43 interrupt_input_blocked, and put off its work until later. 40 INPUT_BLOCKED_P, and put off its work until later.
44 41
45 * If the interrupt handling code wishes, it may set 42 * If the interrupt handling code wishes, it may set
46 interrupt_input_pending to a non-zero value. If that flag is set 43 pending_signals to a non-zero value. If that flag is set
47 when input becomes unblocked, UNBLOCK_INPUT will send a new SIGIO. */ 44 when input becomes unblocked, UNBLOCK_INPUT will then read
48 45 input and process timers.
49extern volatile int interrupt_input_blocked;
50
51/* Nonzero means an input interrupt has arrived
52 during the current critical section. */
53extern int interrupt_input_pending;
54 46
47 Historically, Emacs signal handlers did much more than they do now,
48 and this caused many BLOCK_INPUT calls to be sprinkled around the code.
49 FIXME: Remove calls that aren't needed now. */
55 50
56/* Non-zero means asynchronous timers should be run when input is 51extern volatile int interrupt_input_blocked;
57 unblocked. */
58 52
59extern int pending_atimers; 53/* Begin critical section. */
60 54
55BLOCKINPUT_INLINE void
56block_input (void)
57{
58 interrupt_input_blocked++;
59}
61 60
62/* Begin critical section. */ 61extern void unblock_input (void);
63#define BLOCK_INPUT (interrupt_input_blocked++) 62extern void totally_unblock_input (void);
64 63extern void unblock_input_to (int);
65/* End critical section.
66
67 If doing signal-driven input, and a signal came in when input was
68 blocked, reinvoke the signal handler now to deal with it.
69
70 Always test interrupt_input_pending; that's not too expensive, and
71 it'll never get set if we don't need to resignal. This is simpler
72 than dealing here with every configuration option that might affect
73 whether interrupt_input_pending can be nonzero. */
74
75#define UNBLOCK_INPUT \
76 do \
77 { \
78 --interrupt_input_blocked; \
79 if (interrupt_input_blocked == 0) \
80 { \
81 if (interrupt_input_pending) \
82 reinvoke_input_signal (); \
83 if (pending_atimers) \
84 do_pending_atimers (); \
85 } \
86 else if (interrupt_input_blocked < 0) \
87 emacs_abort (); \
88 } \
89 while (0)
90
91/* Undo any number of BLOCK_INPUT calls,
92 and also reinvoke any pending signal. */
93
94#define TOTALLY_UNBLOCK_INPUT \
95 do if (interrupt_input_blocked != 0) \
96 { \
97 interrupt_input_blocked = 1; \
98 UNBLOCK_INPUT; \
99 } \
100 while (0)
101
102/* Undo any number of BLOCK_INPUT calls down to level LEVEL,
103 and also (if the level is now 0) reinvoke any pending signal. */
104
105#define UNBLOCK_INPUT_TO(LEVEL) \
106 do \
107 { \
108 interrupt_input_blocked = (LEVEL) + 1; \
109 UNBLOCK_INPUT; \
110 } \
111 while (0)
112
113#define UNBLOCK_INPUT_RESIGNAL UNBLOCK_INPUT
114 64
115/* In critical section ? */ 65/* In critical section ? */
116#define INPUT_BLOCKED_P (interrupt_input_blocked > 0)
117 66
118/* Defined in keyboard.c */ 67BLOCKINPUT_INLINE bool
119extern void reinvoke_input_signal (void); 68input_blocked_p (void)
69{
70 return 0 < interrupt_input_blocked;
71}
72
73INLINE_HEADER_END
120 74
121#endif /* EMACS_BLOCKINPUT_H */ 75#endif /* EMACS_BLOCKINPUT_H */