Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : // Note that this file is `#include`d by "signal-handling.c"
4 : :
5 : : #include <signal.h>
6 : : #include <sys/types.h>
7 : : #include <sys/stat.h>
8 : : #include <sys/mman.h>
9 : : #include <pthread.h>
10 : : #include <time.h>
11 : : #include <errno.h>
12 : : #if defined(_OS_DARWIN_) && !defined(MAP_ANONYMOUS)
13 : : #define MAP_ANONYMOUS MAP_ANON
14 : : #endif
15 : :
16 : : #ifdef __APPLE__
17 : : #include <AvailabilityMacros.h>
18 : : #ifdef MAC_OS_X_VERSION_10_9
19 : : #include <sys/_types/_ucontext64.h>
20 : : #else
21 : : #define __need_ucontext64_t
22 : : #include <machine/_structs.h>
23 : : #endif
24 : : #endif
25 : :
26 : : // Figure out the best signals/timers to use for this platform
27 : : #ifdef __APPLE__ // Darwin's mach ports allow signal-free thread management
28 : : #define HAVE_MACH
29 : : #define HAVE_KEVENT
30 : : #elif defined(__FreeBSD__) // generic bsd
31 : : #define HAVE_ITIMER
32 : : #else // generic linux
33 : : #define HAVE_TIMER
34 : : #endif
35 : :
36 : : #ifdef HAVE_KEVENT
37 : : #include <sys/event.h>
38 : : #endif
39 : :
40 : : // 8M signal stack, same as default stack size and enough
41 : : // for reasonable finalizers.
42 : : // Should also be enough for parallel GC when we have it =)
43 : : #define sig_stack_size (8 * 1024 * 1024)
44 : :
45 : : #include "julia_assert.h"
46 : :
47 : : // helper function for returning the unw_context_t inside a ucontext_t
48 : : // (also used by stackwalk.c)
49 : 5266 : bt_context_t *jl_to_bt_context(void *sigctx)
50 : : {
51 : : #ifdef __APPLE__
52 : : return (bt_context_t*)&((ucontext64_t*)sigctx)->uc_mcontext64->__ss;
53 : : #elif defined(_CPU_ARM_)
54 : : // libunwind does not use `ucontext_t` on ARM.
55 : : // `unw_context_t` is a struct of 16 `unsigned long` which should
56 : : // have the same layout as the `arm_r0` to `arm_pc` fields in `sigcontext`
57 : : ucontext_t *ctx = (ucontext_t*)sigctx;
58 : : return (bt_context_t*)&ctx->uc_mcontext.arm_r0;
59 : : #else
60 : 5266 : return (bt_context_t*)sigctx;
61 : : #endif
62 : : }
63 : :
64 : : static int thread0_exit_count = 0;
65 : : static void jl_exit_thread0(int exitstate, jl_bt_element_t *bt_data, size_t bt_size);
66 : :
67 : 8 : static inline __attribute__((unused)) uintptr_t jl_get_rsp_from_ctx(const void *_ctx)
68 : : {
69 : : #if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
70 : 8 : const ucontext_t *ctx = (const ucontext_t*)_ctx;
71 : 8 : return ctx->uc_mcontext.gregs[REG_RSP];
72 : : #elif defined(_OS_LINUX_) && defined(_CPU_X86_)
73 : : const ucontext_t *ctx = (const ucontext_t*)_ctx;
74 : : return ctx->uc_mcontext.gregs[REG_ESP];
75 : : #elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
76 : : const ucontext_t *ctx = (const ucontext_t*)_ctx;
77 : : return ctx->uc_mcontext.sp;
78 : : #elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
79 : : const ucontext_t *ctx = (const ucontext_t*)_ctx;
80 : : return ctx->uc_mcontext.arm_sp;
81 : : #elif defined(_OS_DARWIN_) && defined(_CPU_X86_64_)
82 : : const ucontext64_t *ctx = (const ucontext64_t*)_ctx;
83 : : return ctx->uc_mcontext64->__ss.__rsp;
84 : : #elif defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
85 : : const ucontext64_t *ctx = (const ucontext64_t*)_ctx;
86 : : return ctx->uc_mcontext64->__ss.__sp;
87 : : #elif defined(_OS_FREEBSD_) && defined(_CPU_X86_64_)
88 : : const ucontext_t *ctx = (const ucontext_t*)_ctx;
89 : : return ctx->uc_mcontext.mc_rsp;
90 : : #else
91 : : // TODO Add support for PowerPC(64)?
92 : : return 0;
93 : : #endif
94 : : }
95 : :
96 : 15 : static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr)
97 : : {
98 : : // One guard page for signal_stack.
99 [ + + ]: 20 : return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size ||
100 [ - + ]: 5 : (char*)ptr > (char*)ptls->signal_stack + sig_stack_size);
101 : : }
102 : :
103 : : // Modify signal context `_ctx` so that `fptr` will execute when the signal
104 : : // returns. `fptr` will execute on the signal stack, and must not return.
105 : : // jl_call_in_ctx is also currently executing on that signal stack,
106 : : // so be careful not to smash it
107 : 8 : static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int sig, void *_ctx)
108 : : {
109 : : // Modifying the ucontext should work but there is concern that
110 : : // sigreturn oriented programming mitigation can work against us
111 : : // by rejecting ucontext that is modified.
112 : : // The current (staged) implementation in the Linux Kernel only
113 : : // checks that the syscall is made in the signal handler and that
114 : : // the ucontext address is valid. Hopefully the value of the ucontext
115 : : // will not be part of the validation...
116 [ + - - + ]: 8 : if (!ptls || !ptls->signal_stack) {
117 : : sigset_t sset;
118 : 0 : sigemptyset(&sset);
119 : 0 : sigaddset(&sset, sig);
120 : 0 : sigprocmask(SIG_UNBLOCK, &sset, NULL);
121 : 0 : fptr();
122 : 0 : return;
123 : : }
124 : 8 : uintptr_t rsp = jl_get_rsp_from_ctx(_ctx);
125 [ - + ]: 8 : if (is_addr_on_sigstack(ptls, (void*)rsp)) {
126 : 0 : rsp = (rsp - 256) & ~(uintptr_t)15; // redzone and re-alignment
127 : : }
128 : : else {
129 : 8 : rsp = (uintptr_t)ptls->signal_stack + sig_stack_size;
130 : : }
131 [ - + ]: 8 : assert(rsp % 16 == 0);
132 : : #if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
133 : 8 : ucontext_t *ctx = (ucontext_t*)_ctx;
134 : 8 : rsp -= sizeof(void*);
135 : 8 : ctx->uc_mcontext.gregs[REG_RSP] = rsp;
136 : 8 : ctx->uc_mcontext.gregs[REG_RIP] = (uintptr_t)fptr;
137 : : #elif defined(_OS_FREEBSD_) && defined(_CPU_X86_64_)
138 : : ucontext_t *ctx = (ucontext_t*)_ctx;
139 : : rsp -= sizeof(void*);
140 : : ctx->uc_mcontext.mc_rsp = rsp;
141 : : ctx->uc_mcontext.mc_rip = (uintptr_t)fptr;
142 : : #elif defined(_OS_LINUX_) && defined(_CPU_X86_)
143 : : ucontext_t *ctx = (ucontext_t*)_ctx;
144 : : rsp -= sizeof(void*);
145 : : ctx->uc_mcontext.gregs[REG_ESP] = rsp;
146 : : ctx->uc_mcontext.gregs[REG_EIP] = (uintptr_t)fptr;
147 : : #elif defined(_OS_FREEBSD_) && defined(_CPU_X86_)
148 : : ucontext_t *ctx = (ucontext_t*)_ctx;
149 : : rsp -= sizeof(void*);
150 : : ctx->uc_mcontext.mc_esp = rsp;
151 : : ctx->uc_mcontext.mc_eip = (uintptr_t)fptr;
152 : : #elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
153 : : ucontext_t *ctx = (ucontext_t*)_ctx;
154 : : ctx->uc_mcontext.sp = rsp;
155 : : ctx->uc_mcontext.regs[29] = 0; // Clear link register (x29)
156 : : ctx->uc_mcontext.pc = (uintptr_t)fptr;
157 : : #elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
158 : : ucontext_t *ctx = (ucontext_t*)_ctx;
159 : : uintptr_t target = (uintptr_t)fptr;
160 : : // Apparently some glibc's sigreturn target is running in thumb state.
161 : : // Mimic a `bx` instruction by setting the T(5) bit of CPSR
162 : : // depending on the target address.
163 : : uintptr_t cpsr = ctx->uc_mcontext.arm_cpsr;
164 : : // Thumb mode function pointer should have the lowest bit set
165 : : if (target & 1) {
166 : : target = target & ~((uintptr_t)1);
167 : : cpsr = cpsr | (1 << 5);
168 : : }
169 : : else {
170 : : cpsr = cpsr & ~(1 << 5);
171 : : }
172 : : ctx->uc_mcontext.arm_cpsr = cpsr;
173 : : ctx->uc_mcontext.arm_sp = rsp;
174 : : ctx->uc_mcontext.arm_lr = 0; // Clear link register
175 : : ctx->uc_mcontext.arm_pc = target;
176 : : #elif defined(_OS_DARWIN_) && (defined(_CPU_X86_64_) || defined(_CPU_AARCH64_))
177 : : // Only used for SIGFPE.
178 : : // This doesn't seems to be reliable when the SIGFPE is generated
179 : : // from a divide-by-zero exception, which is now handled by
180 : : // `catch_exception_raise`. It works fine when a signal is received
181 : : // due to `kill`/`raise` though.
182 : : ucontext64_t *ctx = (ucontext64_t*)_ctx;
183 : : #if defined(_CPU_X86_64_)
184 : : rsp -= sizeof(void*);
185 : : ctx->uc_mcontext64->__ss.__rsp = rsp;
186 : : ctx->uc_mcontext64->__ss.__rip = (uintptr_t)fptr;
187 : : #else
188 : : ctx->uc_mcontext64->__ss.__sp = rsp;
189 : : ctx->uc_mcontext64->__ss.__pc = (uintptr_t)fptr;
190 : : ctx->uc_mcontext64->__ss.__lr = 0;
191 : : #endif
192 : : #else
193 : : #pragma message("julia: throw-in-context not supported on this platform")
194 : : // TODO Add support for PowerPC(64)?
195 : : sigset_t sset;
196 : : sigemptyset(&sset);
197 : : sigaddset(&sset, sig);
198 : : sigprocmask(SIG_UNBLOCK, &sset, NULL);
199 : : fptr();
200 : : #endif
201 : : }
202 : :
203 : 7 : static void jl_throw_in_ctx(jl_task_t *ct, jl_value_t *e, int sig, void *sigctx)
204 : : {
205 : 7 : jl_ptls_t ptls = ct->ptls;
206 [ + - ]: 7 : if (!jl_get_safe_restore()) {
207 : 7 : ptls->bt_size =
208 : 7 : rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, jl_to_bt_context(sigctx),
209 : : ct->gcstack);
210 : 7 : ptls->sig_exception = e;
211 : : }
212 : 7 : jl_call_in_ctx(ptls, &jl_sig_throw, sig, sigctx);
213 : 7 : }
214 : :
215 : : static pthread_t signals_thread;
216 : :
217 : 9 : static int is_addr_on_stack(jl_task_t *ct, void *addr)
218 : : {
219 [ - + ]: 9 : if (ct->copy_stack) {
220 : 0 : jl_ptls_t ptls = ct->ptls;
221 [ # # ]: 0 : return ((char*)addr > (char*)ptls->stackbase - ptls->stacksize &&
222 [ # # ]: 0 : (char*)addr < (char*)ptls->stackbase);
223 : : }
224 [ + + ]: 16 : return ((char*)addr > (char*)ct->stkbuf &&
225 [ + + ]: 7 : (char*)addr < (char*)ct->stkbuf + ct->bufsz);
226 : : }
227 : :
228 : 7 : static void sigdie_handler(int sig, siginfo_t *info, void *context)
229 : : {
230 : 7 : signal(sig, SIG_DFL);
231 : 7 : uv_tty_reset_mode();
232 [ - + ]: 7 : if (sig == SIGILL)
233 : 0 : jl_show_sigill(context);
234 : 7 : jl_critical_error(sig, jl_to_bt_context(context), jl_get_current_task());
235 [ # # # # ]: 0 : if (sig != SIGSEGV &&
236 [ # # ]: 0 : sig != SIGBUS &&
237 : : sig != SIGILL) {
238 : 0 : raise(sig);
239 : : }
240 : : // fall-through return to re-execute faulting statement (but without the error handler)
241 : 0 : }
242 : :
243 : : #if defined(_CPU_X86_64_) || defined(_CPU_X86_)
244 : : enum x86_trap_flags {
245 : : USER_MODE = 0x4,
246 : : WRITE_FAULT = 0x2,
247 : : PAGE_PRESENT = 0x1
248 : : };
249 : :
250 : 1 : int exc_reg_is_write_fault(uintptr_t err) {
251 : 1 : return err & WRITE_FAULT;
252 : : }
253 : : #elif defined(_CPU_AARCH64_)
254 : : enum aarch64_esr_layout {
255 : : EC_MASK = ((uint32_t)0b111111) << 26,
256 : : EC_DATA_ABORT = ((uint32_t)0b100100) << 26,
257 : : ISR_DA_WnR = ((uint32_t)1) << 6
258 : : };
259 : :
260 : : int exc_reg_is_write_fault(uintptr_t esr) {
261 : : return (esr & EC_MASK) == EC_DATA_ABORT && (esr & ISR_DA_WnR);
262 : : }
263 : : #endif
264 : :
265 : : #if defined(HAVE_MACH)
266 : : #include "signals-mach.c"
267 : : #else
268 : :
269 : :
270 : : #if defined(_OS_LINUX_) && (defined(_CPU_X86_64_) || defined(_CPU_X86_))
271 : 1 : int is_write_fault(void *context) {
272 : 1 : ucontext_t *ctx = (ucontext_t*)context;
273 : 1 : return exc_reg_is_write_fault(ctx->uc_mcontext.gregs[REG_ERR]);
274 : : }
275 : : #elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
276 : : struct linux_aarch64_ctx_header {
277 : : uint32_t magic;
278 : : uint32_t size;
279 : : };
280 : : const uint32_t linux_esr_magic = 0x45535201;
281 : :
282 : : int is_write_fault(void *context) {
283 : : ucontext_t *ctx = (ucontext_t*)context;
284 : : struct linux_aarch64_ctx_header *extra =
285 : : (struct linux_aarch64_ctx_header *)ctx->uc_mcontext.__reserved;
286 : : while (extra->magic != 0) {
287 : : if (extra->magic == linux_esr_magic) {
288 : : return exc_reg_is_write_fault(*(uint64_t*)&extra[1]);
289 : : }
290 : : extra = (struct linux_aarch64_ctx_header *)
291 : : (((uint8_t*)extra) + extra->size);
292 : : }
293 : : return 0;
294 : : }
295 : : #elif defined(_OS_FREEBSD_) && (defined(_CPU_X86_64_) || defined(_CPU_X86_))
296 : : int is_write_fault(void *context) {
297 : : ucontext_t *ctx = (ucontext_t*)context;
298 : : return exc_reg_is_write_fault(ctx->uc_mcontext.mc_err);
299 : : }
300 : : #else
301 : : #pragma message("Implement this query for consistent PROT_NONE handling")
302 : : int is_write_fault(void *context) {
303 : : return 0;
304 : : }
305 : : #endif
306 : :
307 : 7 : static int jl_is_on_sigstack(jl_ptls_t ptls, void *ptr, void *context)
308 : : {
309 [ - + - - ]: 7 : return (is_addr_on_sigstack(ptls, ptr) &&
310 : 0 : is_addr_on_sigstack(ptls, (void*)jl_get_rsp_from_ctx(context)));
311 : : }
312 : :
313 : 38 : static void segv_handler(int sig, siginfo_t *info, void *context)
314 : : {
315 [ - + ]: 38 : if (jl_get_safe_restore()) { // restarting jl_ or profile
316 : 0 : jl_call_in_ctx(NULL, &jl_sig_throw, sig, context);
317 : 0 : return;
318 : : }
319 : 38 : jl_task_t *ct = jl_get_current_task();
320 [ - + ]: 38 : if (ct == NULL) {
321 : 0 : sigdie_handler(sig, info, context);
322 : 0 : return;
323 : : }
324 [ - + - - ]: 38 : assert(sig == SIGSEGV || sig == SIGBUS);
325 [ + + ]: 38 : if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) {
326 : 29 : jl_set_gc_and_wait();
327 : : // Do not raise sigint on worker thread
328 [ + + ]: 29 : if (jl_atomic_load_relaxed(&ct->tid) != 0)
329 : 9 : return;
330 [ + + ]: 20 : if (ct->ptls->defer_signal) {
331 : 18 : jl_safepoint_defer_sigint();
332 : : }
333 [ + + ]: 2 : else if (jl_safepoint_consume_sigint()) {
334 : 1 : jl_clear_force_sigint();
335 : 1 : jl_throw_in_ctx(ct, jl_interrupt_exception, sig, context);
336 : : }
337 : 20 : return;
338 : : }
339 [ + + ]: 9 : if (is_addr_on_stack(ct, info->si_addr)) { // stack overflow
340 : 2 : jl_throw_in_ctx(ct, jl_stackovf_exception, sig, context);
341 : : }
342 [ - + ]: 7 : else if (jl_is_on_sigstack(ct->ptls, info->si_addr, context)) {
343 : : // This mainly happens when one of the finalizers during final cleanup
344 : : // on the signal stack has a deep/infinite recursion.
345 : : // There isn't anything more we can do
346 : : // (we are already corrupting that stack running this function)
347 : : // so just call `_exit` to terminate immediately.
348 : 0 : jl_safe_printf("ERROR: Signal stack overflow, exit\n");
349 : 0 : _exit(sig + 128);
350 : : }
351 [ + - + + : 7 : else if (sig == SIGSEGV && info->si_code == SEGV_ACCERR && is_write_fault(context)) { // writing to read-only memory (e.g., mmap)
+ - ]
352 : 1 : jl_throw_in_ctx(ct, jl_readonlymemory_exception, sig, context);
353 : : }
354 : : else {
355 : : #ifdef SEGV_EXCEPTION
356 : : jl_throw_in_ctx(ct, jl_segv_exception, sig, context);
357 : : #else
358 : 6 : sigdie_handler(sig, info, context);
359 : : #endif
360 : : }
361 : : }
362 : :
363 : : #if !defined(JL_DISABLE_LIBUNWIND)
364 : : static unw_context_t *signal_context;
365 : : pthread_mutex_t in_signal_lock;
366 : : static pthread_cond_t exit_signal_cond;
367 : : static pthread_cond_t signal_caught_cond;
368 : :
369 : 5252 : static void jl_thread_suspend_and_get_state(int tid, unw_context_t **ctx)
370 : : {
371 : : struct timespec ts;
372 : 5252 : clock_gettime(CLOCK_REALTIME, &ts);
373 : 5252 : ts.tv_sec += 1;
374 : 5252 : pthread_mutex_lock(&in_signal_lock);
375 : 5252 : jl_ptls_t ptls2 = jl_all_tls_states[tid];
376 : 5252 : jl_atomic_store_release(&ptls2->signal_request, 1);
377 : 5252 : pthread_kill(ptls2->system_id, SIGUSR2);
378 : : // wait for thread to acknowledge
379 : 5252 : int err = pthread_cond_timedwait(&signal_caught_cond, &in_signal_lock, &ts);
380 [ - + ]: 5252 : if (err == ETIMEDOUT) {
381 : 0 : sig_atomic_t request = 1;
382 [ # # ]: 0 : if (jl_atomic_cmpswap(&ptls2->signal_request, &request, 0)) {
383 : 0 : *ctx = NULL;
384 : 0 : pthread_mutex_unlock(&in_signal_lock);
385 : 0 : return;
386 : : }
387 : : // Request is either now 0 (meaning the other thread is waiting for
388 : : // exit_signal_cond already),
389 : : // Or it is now -1 (meaning the other thread
390 : : // is waiting for in_signal_lock, and we need to release that lock
391 : : // here for a bit, until the other thread has a chance to get to the
392 : : // exit_signal_cond)
393 [ # # ]: 0 : if (request == -1) {
394 : 0 : err = pthread_cond_wait(&signal_caught_cond, &in_signal_lock);
395 [ # # ]: 0 : assert(!err);
396 : : }
397 : : }
398 : : // Now the other thread is waiting on exit_signal_cond (verify that here by
399 : : // checking it is 0, and add an acquire barrier for good measure)
400 : 5252 : int request = jl_atomic_load_acquire(&ptls2->signal_request);
401 [ - + ]: 5252 : assert(request == 0); (void) request;
402 : 5252 : *ctx = signal_context;
403 : : }
404 : :
405 : 5252 : static void jl_thread_resume(int tid, int sig)
406 : : {
407 : 5252 : jl_ptls_t ptls2 = jl_all_tls_states[tid];
408 [ + + ]: 5252 : jl_atomic_store_release(&ptls2->signal_request, sig == -1 ? 3 : 1);
409 : 5252 : pthread_cond_broadcast(&exit_signal_cond);
410 : 5252 : pthread_cond_wait(&signal_caught_cond, &in_signal_lock); // wait for thread to acknowledge
411 : : // The other thread is waiting to leave exit_signal_cond (verify that here by
412 : : // checking it is 0, and add an acquire barrier for good measure)
413 : 5252 : int request = jl_atomic_load_acquire(&ptls2->signal_request);
414 [ - + ]: 5252 : assert(request == 0); (void) request;
415 : 5252 : pthread_mutex_unlock(&in_signal_lock);
416 : 5252 : }
417 : : #endif
418 : :
419 : : // Throw jl_interrupt_exception if the master thread is in a signal async region
420 : : // or if SIGINT happens too often.
421 : 1 : static void jl_try_deliver_sigint(void)
422 : : {
423 : 1 : jl_ptls_t ptls2 = jl_all_tls_states[0];
424 : 1 : jl_safepoint_enable_sigint();
425 : 1 : jl_wake_libuv();
426 : 1 : jl_atomic_store_release(&ptls2->signal_request, 2);
427 : : // This also makes sure `sleep` is aborted.
428 : 1 : pthread_kill(ptls2->system_id, SIGUSR2);
429 : 1 : }
430 : :
431 : : // Write only by signal handling thread, read only by main thread
432 : : // no sync necessary.
433 : : static int thread0_exit_state = 0;
434 : 1 : static void JL_NORETURN jl_exit_thread0_cb(void)
435 : : {
436 : 1 : CFI_NORETURN
437 : : // This can get stuck if it happens at an unfortunate spot
438 : : // (unavoidable due to its async nature).
439 : : // Try harder to exit each time if we get multiple exit requests.
440 [ + - ]: 1 : if (thread0_exit_count <= 1) {
441 : 1 : jl_critical_error(thread0_exit_state - 128, NULL, jl_current_task);
442 : 1 : jl_exit(thread0_exit_state);
443 : : }
444 [ # # ]: 0 : else if (thread0_exit_count == 2) {
445 : 0 : exit(thread0_exit_state);
446 : : }
447 : : else {
448 : 0 : _exit(thread0_exit_state);
449 : : }
450 : : }
451 : :
452 : 1 : static void jl_exit_thread0(int state, jl_bt_element_t *bt_data, size_t bt_size)
453 : : {
454 : 1 : jl_ptls_t ptls2 = jl_all_tls_states[0];
455 [ + - ]: 1 : if (thread0_exit_count <= 1) {
456 : : unw_context_t *signal_context;
457 : 1 : jl_thread_suspend_and_get_state(0, &signal_context);
458 [ + - ]: 1 : if (signal_context != NULL) {
459 : 1 : thread0_exit_state = state;
460 : 1 : ptls2->bt_size = bt_size; // <= JL_MAX_BT_SIZE
461 : 1 : memcpy(ptls2->bt_data, bt_data, ptls2->bt_size * sizeof(bt_data[0]));
462 : 1 : jl_thread_resume(0, -1);
463 : 1 : return;
464 : : }
465 : : }
466 : 0 : thread0_exit_state = state;
467 : 0 : jl_atomic_store_release(&ptls2->signal_request, 3);
468 : : // This also makes sure `sleep` is aborted.
469 : 0 : pthread_kill(ptls2->system_id, SIGUSR2);
470 : : }
471 : :
472 : : // request:
473 : : // -1: beginning processing [invalid outside here]
474 : : // 0: nothing [not from here]
475 : : // 1: get state
476 : : // 2: throw sigint if `!defer_signal && io_wait` or if force throw threshold
477 : : // is reached
478 : : // 3: exit with `thread0_exit_state`
479 : 5253 : void usr2_handler(int sig, siginfo_t *info, void *ctx)
480 : : {
481 : 5253 : jl_task_t *ct = jl_get_current_task();
482 [ - + ]: 5253 : if (ct == NULL)
483 : 0 : return;
484 : 5253 : jl_ptls_t ptls = ct->ptls;
485 [ - + ]: 5253 : if (ptls == NULL)
486 : 0 : return;
487 : 5253 : int errno_save = errno;
488 : : // acknowledge that we saw the signal_request
489 : 5253 : sig_atomic_t request = jl_atomic_exchange(&ptls->signal_request, -1);
490 : : #if !defined(JL_DISABLE_LIBUNWIND)
491 [ + + ]: 5253 : if (request == 1) {
492 : 5252 : pthread_mutex_lock(&in_signal_lock);
493 : 5252 : signal_context = jl_to_bt_context(ctx);
494 : : // acknowledge that we set the signal_caught_cond broadcast
495 : 5252 : request = jl_atomic_exchange(&ptls->signal_request, 0);
496 [ - + ]: 5252 : assert(request == -1); (void) request;
497 : 5252 : pthread_cond_broadcast(&signal_caught_cond);
498 : 5252 : pthread_cond_wait(&exit_signal_cond, &in_signal_lock);
499 : 5252 : request = jl_atomic_exchange(&ptls->signal_request, 0);
500 [ + + - + ]: 5252 : assert(request == 1 || request == 3);
501 : : // acknowledge that we got the resume signal
502 : 5252 : pthread_cond_broadcast(&signal_caught_cond);
503 : 5252 : pthread_mutex_unlock(&in_signal_lock);
504 : : }
505 : : else
506 : : #endif
507 : 1 : jl_atomic_exchange(&ptls->signal_request, 0); // returns -1
508 [ + + ]: 5253 : if (request == 2) {
509 : 1 : int force = jl_check_force_sigint();
510 [ + - + - : 1 : if (force || (!ptls->defer_signal && ptls->io_wait)) {
- + ]
511 : 0 : jl_safepoint_consume_sigint();
512 [ # # ]: 0 : if (force)
513 : 0 : jl_safe_printf("WARNING: Force throwing a SIGINT\n");
514 : : // Force a throw
515 : 0 : jl_clear_force_sigint();
516 : 0 : jl_throw_in_ctx(ct, jl_interrupt_exception, sig, ctx);
517 : : }
518 : : }
519 [ + + ]: 5252 : else if (request == 3) {
520 : 1 : jl_call_in_ctx(ct->ptls, jl_exit_thread0_cb, sig, ctx);
521 : : }
522 : 5253 : errno = errno_save;
523 : : }
524 : :
525 : : // Because SIGUSR1 is dual-purpose, and the timer can have trailing signals after being deleted,
526 : : // a 2-second grace period is imposed to ignore any trailing timer-created signals so they don't get
527 : : // confused for user triggers
528 : : uint64_t last_timer_delete_time = 0;
529 : :
530 : 0 : int timer_graceperiod_elapsed(void)
531 : : {
532 : 0 : return jl_hrtime() > (last_timer_delete_time + 2e9);
533 : : }
534 : :
535 : : #if defined(HAVE_TIMER)
536 : : // Linux-style
537 : : #include <time.h>
538 : : #include <string.h> // for memset
539 : :
540 : : static timer_t timerprof;
541 : : static struct itimerspec itsprof;
542 : :
543 : 5 : JL_DLLEXPORT int jl_profile_start_timer(void)
544 : : {
545 : : struct sigevent sigprof;
546 : :
547 : : // Establish the signal event
548 : 5 : memset(&sigprof, 0, sizeof(struct sigevent));
549 : 5 : sigprof.sigev_notify = SIGEV_SIGNAL;
550 : 5 : sigprof.sigev_signo = SIGUSR1;
551 : 5 : sigprof.sigev_value.sival_ptr = &timerprof;
552 : : // Because SIGUSR1 is multipurpose, set `running` before so that we know that the first SIGUSR1 came from the timer
553 : 5 : running = 1;
554 [ - + ]: 5 : if (timer_create(CLOCK_REALTIME, &sigprof, &timerprof) == -1) {
555 : 0 : running = 0;
556 : 0 : return -2;
557 : : }
558 : :
559 : : // Start the timer
560 : 5 : itsprof.it_interval.tv_sec = 0;
561 : 5 : itsprof.it_interval.tv_nsec = 0;
562 : 5 : itsprof.it_value.tv_sec = nsecprof / GIGA;
563 : 5 : itsprof.it_value.tv_nsec = nsecprof % GIGA;
564 [ - + ]: 5 : if (timer_settime(timerprof, 0, &itsprof, NULL) == -1) {
565 : 0 : running = 0;
566 : 0 : return -3;
567 : : }
568 : 5 : return 0;
569 : : }
570 : :
571 : 5 : JL_DLLEXPORT void jl_profile_stop_timer(void)
572 : : {
573 [ + - ]: 5 : if (running) {
574 : 5 : timer_delete(timerprof);
575 : 5 : last_timer_delete_time = jl_hrtime();
576 : 5 : running = 0;
577 : : }
578 : 5 : }
579 : :
580 : : #elif defined(HAVE_ITIMER)
581 : : // BSD-style timers
582 : : #include <string.h>
583 : : #include <sys/time.h>
584 : : struct itimerval timerprof;
585 : :
586 : : JL_DLLEXPORT int jl_profile_start_timer(void)
587 : : {
588 : : timerprof.it_interval.tv_sec = 0;
589 : : timerprof.it_interval.tv_usec = 0;
590 : : timerprof.it_value.tv_sec = nsecprof / GIGA;
591 : : timerprof.it_value.tv_usec = ((nsecprof % GIGA) + 999) / 1000;
592 : : // Because SIGUSR1 is multipurpose, set `running` before so that we know that the first SIGUSR1 came from the timer
593 : : running = 1;
594 : : if (setitimer(ITIMER_PROF, &timerprof, NULL) == -1) {
595 : : running = 0;
596 : : return -3;
597 : : }
598 : : return 0;
599 : : }
600 : :
601 : : JL_DLLEXPORT void jl_profile_stop_timer(void)
602 : : {
603 : : if (running) {
604 : : memset(&timerprof, 0, sizeof(timerprof));
605 : : setitimer(ITIMER_PROF, &timerprof, NULL);
606 : : last_timer_delete_time = jl_hrtime();
607 : : running = 0;
608 : : }
609 : : }
610 : :
611 : : #else
612 : :
613 : : #error no profile tools available
614 : :
615 : : #endif
616 : : #endif // HAVE_MACH
617 : :
618 : 573 : static void allocate_segv_handler(void)
619 : : {
620 : : struct sigaction act;
621 : 573 : memset(&act, 0, sizeof(struct sigaction));
622 : 573 : sigemptyset(&act.sa_mask);
623 : 573 : act.sa_sigaction = segv_handler;
624 : 573 : act.sa_flags = SA_ONSTACK | SA_SIGINFO;
625 [ - + ]: 573 : if (sigaction(SIGSEGV, &act, NULL) < 0) {
626 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
627 : : }
628 : : // On AArch64, stack overflow triggers a SIGBUS
629 [ - + ]: 573 : if (sigaction(SIGBUS, &act, NULL) < 0) {
630 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
631 : : }
632 : 573 : }
633 : :
634 : 692 : static void *alloc_sigstack(size_t *ssize)
635 : : {
636 : 692 : void *stk = jl_malloc_stack(ssize, NULL);
637 [ - + ]: 692 : if (stk == MAP_FAILED)
638 : 0 : jl_errorf("fatal error allocating signal stack: mmap: %s", strerror(errno));
639 : 692 : return stk;
640 : : }
641 : :
642 : 692 : void jl_install_thread_signal_handler(jl_ptls_t ptls)
643 : : {
644 : 692 : size_t ssize = sig_stack_size;
645 : 692 : void *signal_stack = alloc_sigstack(&ssize);
646 : 692 : ptls->signal_stack = signal_stack;
647 : : stack_t ss;
648 : 692 : ss.ss_flags = 0;
649 : 692 : ss.ss_size = ssize - 16;
650 : 692 : ss.ss_sp = signal_stack;
651 [ - + ]: 692 : if (sigaltstack(&ss, NULL) < 0) {
652 : 0 : jl_errorf("fatal error: sigaltstack: %s", strerror(errno));
653 : : }
654 : :
655 : : #ifdef HAVE_MACH
656 : : attach_exception_port(pthread_mach_thread_np(ptls->system_id), 0);
657 : : #endif
658 : 692 : }
659 : :
660 : 1146 : static void jl_sigsetset(sigset_t *sset)
661 : : {
662 : 1146 : sigemptyset(sset);
663 : 1146 : sigaddset(sset, SIGINT);
664 : 1146 : sigaddset(sset, SIGTERM);
665 : 1146 : sigaddset(sset, SIGABRT);
666 : 1146 : sigaddset(sset, SIGQUIT);
667 : : #ifdef SIGINFO
668 : : sigaddset(sset, SIGINFO);
669 : : #else
670 : 1146 : sigaddset(sset, SIGUSR1);
671 : : #endif
672 : : #if defined(HAVE_TIMER)
673 : 1146 : sigaddset(sset, SIGUSR1);
674 : : #elif defined(HAVE_ITIMER)
675 : : sigaddset(sset, SIGPROF);
676 : : #endif
677 : 1146 : }
678 : :
679 : : #ifdef HAVE_KEVENT
680 : : static void kqueue_signal(int *sigqueue, struct kevent *ev, int sig)
681 : : {
682 : : if (*sigqueue == -1)
683 : : return;
684 : : EV_SET(ev, sig, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
685 : : if (kevent(*sigqueue, ev, 1, NULL, 0, NULL)) {
686 : : perror("signal kevent");
687 : : close(*sigqueue);
688 : : *sigqueue = -1;
689 : : }
690 : : else {
691 : : signal(sig, SIG_IGN);
692 : : }
693 : : }
694 : : #endif
695 : :
696 : 0 : void trigger_profile_peek(void)
697 : : {
698 : 0 : jl_safe_printf("\n======================================================================================\n");
699 : 0 : jl_safe_printf("Information request received. A stacktrace will print followed by a %.1f second profile\n", profile_peek_duration);
700 : 0 : jl_safe_printf("======================================================================================\n");
701 : 0 : bt_size_cur = 0; // clear profile buffer
702 [ # # ]: 0 : if (jl_profile_start_timer() < 0)
703 : 0 : jl_safe_printf("ERROR: Could not start profile timer\n");
704 : : else
705 : 0 : profile_autostop_time = jl_hrtime() + (profile_peek_duration * 1e9);
706 : 0 : }
707 : :
708 : 573 : static void *signal_listener(void *arg)
709 : : {
710 : : static jl_bt_element_t bt_data[JL_MAX_BT_SIZE + 1];
711 : : static size_t bt_size = 0;
712 : : sigset_t sset;
713 : : int sig, critical, profile;
714 : 573 : jl_sigsetset(&sset);
715 : : #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
716 : : siginfo_t info;
717 : : #endif
718 : : #ifdef HAVE_KEVENT
719 : : struct kevent ev;
720 : : int sigqueue = kqueue();
721 : : if (sigqueue == -1) {
722 : : perror("signal kqueue");
723 : : }
724 : : else {
725 : : kqueue_signal(&sigqueue, &ev, SIGINT);
726 : : kqueue_signal(&sigqueue, &ev, SIGTERM);
727 : : kqueue_signal(&sigqueue, &ev, SIGABRT);
728 : : kqueue_signal(&sigqueue, &ev, SIGQUIT);
729 : : #ifdef SIGINFO
730 : : kqueue_signal(&sigqueue, &ev, SIGINFO);
731 : : #else
732 : : kqueue_signal(&sigqueue, &ev, SIGUSR1);
733 : : #endif
734 : : #if defined(HAVE_TIMER)
735 : : kqueue_signal(&sigqueue, &ev, SIGUSR1);
736 : : #elif defined(HAVE_ITIMER)
737 : : kqueue_signal(&sigqueue, &ev, SIGPROF);
738 : : #endif
739 : : }
740 : : #endif
741 : 5303 : while (1) {
742 : 5876 : sig = 0;
743 : 5876 : errno = 0;
744 : : #ifdef HAVE_KEVENT
745 : : if (sigqueue != -1) {
746 : : int nevents = kevent(sigqueue, NULL, 0, &ev, 1, NULL);
747 : : if (nevents == -1) {
748 : : if (errno == EINTR)
749 : : continue;
750 : : perror("signal kevent");
751 : : }
752 : : if (nevents != 1) {
753 : : close(sigqueue);
754 : : sigqueue = -1;
755 : : continue;
756 : : }
757 : : sig = ev.ident;
758 : : }
759 : : else
760 : : #endif
761 : : #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
762 : 5876 : sig = sigwaitinfo(&sset, &info);
763 : : #else
764 : : if (sigwait(&sset, &sig))
765 : : sig = -1;
766 : : #endif
767 [ + + ]: 5303 : if (sig == -1) {
768 [ + - ]: 51 : if (errno == EINTR)
769 : 52 : continue;
770 : 0 : sig = SIGABRT; // this branch can't occur, unless we had stack memory corruption of sset
771 : : }
772 : 5252 : profile = 0;
773 : : #ifndef HAVE_MACH
774 : : #if defined(HAVE_TIMER)
775 : 5252 : profile = (sig == SIGUSR1);
776 : : #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
777 [ + + + - ]: 5252 : if (profile && !(info.si_code == SI_TIMER &&
778 [ - + ]: 5250 : info.si_value.sival_ptr == &timerprof))
779 : 0 : profile = 0;
780 : : #endif
781 : : #elif defined(HAVE_ITIMER)
782 : : profile = (sig == SIGPROF);
783 : : #endif
784 : : #endif
785 : :
786 [ + + ]: 5252 : if (sig == SIGINT) {
787 [ - + ]: 1 : if (jl_ignore_sigint()) {
788 : 0 : continue;
789 : : }
790 [ - + ]: 1 : else if (exit_on_sigint) {
791 : 0 : critical = 1;
792 : : }
793 : : else {
794 : 1 : jl_try_deliver_sigint();
795 : 1 : continue;
796 : : }
797 : : }
798 : : else {
799 : 5251 : critical = 0;
800 : : }
801 : :
802 : 5251 : critical |= (sig == SIGTERM);
803 : 5251 : critical |= (sig == SIGABRT);
804 : 5251 : critical |= (sig == SIGQUIT);
805 : : #ifdef SIGINFO
806 : : critical |= (sig == SIGINFO);
807 : : #else
808 [ + + - + ]: 5251 : critical |= (sig == SIGUSR1 && !profile);
809 : : #endif
810 : :
811 : 5251 : int doexit = critical;
812 : : #ifdef SIGINFO
813 : : if (sig == SIGINFO) {
814 : : if (running != 1)
815 : : trigger_profile_peek();
816 : : doexit = 0;
817 : : }
818 : : #else
819 [ + + ]: 5251 : if (sig == SIGUSR1) {
820 [ - + - - ]: 5250 : if (running != 1 && timer_graceperiod_elapsed())
821 : 0 : trigger_profile_peek();
822 : 5250 : doexit = 0;
823 : : }
824 : : #endif
825 : :
826 : 5251 : bt_size = 0;
827 : : #if !defined(JL_DISABLE_LIBUNWIND)
828 : : unw_context_t *signal_context;
829 : : // sample each thread, round-robin style in reverse order
830 : : // (so that thread zero gets notified last)
831 [ + + + - ]: 5251 : if (critical || profile) {
832 : 5251 : jl_lock_profile();
833 : : int *randperm;
834 [ + + ]: 5251 : if (profile)
835 : 5250 : randperm = profile_get_randperm(jl_n_threads);
836 [ + + ]: 10502 : for (int idx = jl_n_threads; idx-- > 0; ) {
837 : : // Stop the threads in the random or reverse round-robin order.
838 [ + + ]: 5251 : int i = profile ? randperm[idx] : idx;
839 : : // notify thread to stop
840 : 5251 : jl_thread_suspend_and_get_state(i, &signal_context);
841 [ - + ]: 5251 : if (signal_context == NULL)
842 : 0 : continue;
843 : :
844 : : // do backtrace on thread contexts for critical signals
845 : : // this part must be signal-handler safe
846 [ + + ]: 5251 : if (critical) {
847 : 2 : bt_size += rec_backtrace_ctx(bt_data + bt_size,
848 : 1 : JL_MAX_BT_SIZE / jl_n_threads - 1,
849 : : signal_context, NULL);
850 : 1 : bt_data[bt_size++].uintptr = 0;
851 : : }
852 : :
853 : : // do backtrace for profiler
854 [ + + + - ]: 5251 : if (profile && running) {
855 [ - + ]: 5250 : if (jl_profile_is_buffer_full()) {
856 : : // Buffer full: Delete the timer
857 : 0 : jl_profile_stop_timer();
858 : : }
859 : : else {
860 : : // unwinding can fail, so keep track of the current state
861 : : // and restore from the SEGV handler if anything happens.
862 : 5250 : jl_jmp_buf *old_buf = jl_get_safe_restore();
863 : : jl_jmp_buf buf;
864 : :
865 : 5250 : jl_set_safe_restore(&buf);
866 [ - + ]: 5250 : if (jl_setjmp(buf, 0)) {
867 : 0 : jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n");
868 : : } else {
869 : : // Get backtrace data
870 : 5250 : bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur,
871 : 5250 : bt_size_max - bt_size_cur - 1, signal_context, NULL);
872 : : }
873 : 5250 : jl_set_safe_restore(old_buf);
874 : :
875 : 5250 : jl_ptls_t ptls2 = jl_all_tls_states[i];
876 : :
877 : : // store threadid but add 1 as 0 is preserved to indicate end of block
878 : 5250 : bt_data_prof[bt_size_cur++].uintptr = ptls2->tid + 1;
879 : :
880 : : // store task id
881 : 5250 : bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task);
882 : :
883 : : // store cpu cycle clock
884 : 5250 : bt_data_prof[bt_size_cur++].uintptr = cycleclock();
885 : :
886 : : // store whether thread is sleeping but add 1 as 0 is preserved to indicate end of block
887 : 5250 : bt_data_prof[bt_size_cur++].uintptr = jl_atomic_load_relaxed(&ptls2->sleep_check_state) + 1;
888 : :
889 : : // Mark the end of this block with two 0's
890 : 5250 : bt_data_prof[bt_size_cur++].uintptr = 0;
891 : 5250 : bt_data_prof[bt_size_cur++].uintptr = 0;
892 : : }
893 : : }
894 : :
895 : : // notify thread to resume
896 : 5251 : jl_thread_resume(i, sig);
897 : : }
898 : 5251 : jl_unlock_profile();
899 : : }
900 : : #ifndef HAVE_MACH
901 [ + + + - ]: 5251 : if (profile && running) {
902 : 5250 : jl_check_profile_autostop();
903 : : #if defined(HAVE_TIMER)
904 : 5250 : timer_settime(timerprof, 0, &itsprof, NULL);
905 : : #elif defined(HAVE_ITIMER)
906 : : setitimer(ITIMER_PROF, &timerprof, NULL);
907 : : #endif
908 : : }
909 : : #endif
910 : : #endif
911 : :
912 : : // this part is async with the running of the rest of the program
913 : : // and must be thread-safe, but not necessarily signal-handler safe
914 [ + + ]: 5251 : if (critical) {
915 [ + - ]: 1 : if (doexit) {
916 : 1 : thread0_exit_count++;
917 : 1 : jl_exit_thread0(128 + sig, bt_data, bt_size);
918 : : }
919 : : else {
920 : : #ifndef SIGINFO // SIGINFO already prints this automatically
921 : 0 : int nrunning = 0;
922 [ # # ]: 0 : for (int idx = jl_n_threads; idx-- > 0; ) {
923 : 0 : jl_ptls_t ptls2 = jl_all_tls_states[idx];
924 : 0 : nrunning += !jl_atomic_load_relaxed(&ptls2->sleep_check_state);
925 : : }
926 [ # # ]: 0 : jl_safe_printf("\ncmd: %s %d running %d of %d\n", jl_options.julia_bin ? jl_options.julia_bin : "julia", uv_os_getpid(), nrunning, jl_n_threads);
927 : : #endif
928 : :
929 : 0 : jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig));
930 : : size_t i;
931 [ # # ]: 0 : for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
932 : 0 : jl_print_bt_entry_codeloc(bt_data + i);
933 : : }
934 : : }
935 : : }
936 : : }
937 : : return NULL;
938 : : }
939 : :
940 : 573 : void restore_signals(void)
941 : : {
942 : 573 : sigemptyset(&jl_sigint_sset);
943 : 573 : sigaddset(&jl_sigint_sset, SIGINT);
944 : :
945 : : sigset_t sset;
946 : 573 : jl_sigsetset(&sset);
947 : 573 : sigprocmask(SIG_SETMASK, &sset, 0);
948 : :
949 : : #if !defined(HAVE_MACH) && !defined(JL_DISABLE_LIBUNWIND)
950 [ + - + - ]: 1146 : if (pthread_mutex_init(&in_signal_lock, NULL) != 0 ||
951 [ - + ]: 1146 : pthread_cond_init(&exit_signal_cond, NULL) != 0 ||
952 : 573 : pthread_cond_init(&signal_caught_cond, NULL) != 0) {
953 : 0 : jl_error("SIGUSR pthread init failed");
954 : : }
955 : : #endif
956 : :
957 [ - + ]: 573 : if (pthread_create(&signals_thread, NULL, signal_listener, NULL) != 0) {
958 : 0 : jl_error("pthread_create(signal_listener) failed");
959 : : }
960 : 573 : }
961 : :
962 : 3 : static void fpe_handler(int sig, siginfo_t *info, void *context)
963 : : {
964 : : (void)info;
965 [ - + ]: 3 : if (jl_get_safe_restore()) { // restarting jl_ or profile
966 : 0 : jl_call_in_ctx(NULL, &jl_sig_throw, sig, context);
967 : 0 : return;
968 : : }
969 : 3 : jl_task_t *ct = jl_get_current_task();
970 [ - + ]: 3 : if (ct == NULL) // exception on foreign thread is fatal
971 : 0 : sigdie_handler(sig, info, context);
972 : : else
973 : 3 : jl_throw_in_ctx(ct, jl_diverror_exception, sig, context);
974 : : }
975 : :
976 : 1 : static void sigint_handler(int sig)
977 : : {
978 : 1 : jl_sigint_passed = 1;
979 : 1 : }
980 : :
981 : 573 : void jl_install_default_signal_handlers(void)
982 : : {
983 : : struct sigaction actf;
984 : 573 : memset(&actf, 0, sizeof(struct sigaction));
985 : 573 : sigemptyset(&actf.sa_mask);
986 : 573 : actf.sa_sigaction = fpe_handler;
987 : 573 : actf.sa_flags = SA_ONSTACK | SA_SIGINFO;
988 [ - + ]: 573 : if (sigaction(SIGFPE, &actf, NULL) < 0) {
989 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
990 : : }
991 : : struct sigaction actint;
992 : 573 : memset(&actint, 0, sizeof(struct sigaction));
993 : 573 : sigemptyset(&actint.sa_mask);
994 : 573 : actint.sa_handler = sigint_handler;
995 : 573 : actint.sa_flags = 0;
996 [ - + ]: 573 : if (sigaction(SIGINT, &actint, NULL) < 0) {
997 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
998 : : }
999 [ - + ]: 573 : if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
1000 : 0 : jl_error("fatal error: Couldn't set SIGPIPE");
1001 : : }
1002 [ - + ]: 573 : if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
1003 : 0 : jl_error("fatal error: Couldn't set SIGTRAP");
1004 : : }
1005 : :
1006 : : #if defined(HAVE_MACH)
1007 : : allocate_mach_handler();
1008 : : #else
1009 : : struct sigaction act;
1010 : 573 : memset(&act, 0, sizeof(struct sigaction));
1011 : 573 : sigemptyset(&act.sa_mask);
1012 : 573 : act.sa_sigaction = usr2_handler;
1013 : 573 : act.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART;
1014 [ - + ]: 573 : if (sigaction(SIGUSR2, &act, NULL) < 0) {
1015 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1016 : : }
1017 : : #endif
1018 : :
1019 : 573 : allocate_segv_handler();
1020 : :
1021 : : struct sigaction act_die;
1022 : 573 : memset(&act_die, 0, sizeof(struct sigaction));
1023 : 573 : sigemptyset(&act_die.sa_mask);
1024 : 573 : act_die.sa_sigaction = sigdie_handler;
1025 : 573 : act_die.sa_flags = SA_SIGINFO | SA_RESETHAND;
1026 [ - + ]: 573 : if (sigaction(SIGILL, &act_die, NULL) < 0) {
1027 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1028 : : }
1029 [ - + ]: 573 : if (sigaction(SIGABRT, &act_die, NULL) < 0) {
1030 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1031 : : }
1032 [ - + ]: 573 : if (sigaction(SIGSYS, &act_die, NULL) < 0) {
1033 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1034 : : }
1035 : : // need to ensure the following signals are not SIG_IGN, even though they will be blocked
1036 : 573 : act_die.sa_flags = SA_SIGINFO | SA_RESTART | SA_RESETHAND;
1037 : : #if defined(HAVE_ITIMER)
1038 : : if (sigaction(SIGPROF, &act_die, NULL) < 0) {
1039 : : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1040 : : }
1041 : : #endif
1042 : : #ifdef SIGINFO
1043 : : if (sigaction(SIGINFO, &act_die, NULL) < 0) {
1044 : : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1045 : : }
1046 : : #else
1047 [ - + ]: 573 : if (sigaction(SIGUSR1, &act_die, NULL) < 0) {
1048 : 0 : jl_errorf("fatal error: sigaction: %s", strerror(errno));
1049 : : }
1050 : : #endif
1051 : 573 : }
1052 : :
1053 : 566 : JL_DLLEXPORT void jl_install_sigint_handler(void)
1054 : : {
1055 : : // TODO: ?
1056 : 566 : }
1057 : :
1058 : 0 : JL_DLLEXPORT int jl_repl_raise_sigtstp(void)
1059 : : {
1060 : 0 : return raise(SIGTSTP);
1061 : : }
|