LCOV - code coverage report
Current view: top level - src - signals-unix.c (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 186 386 48.2 %
Date: 2022-07-17 01:01:28 Functions: 14 32 43.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 216 25.5 %

           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                 :         90 : 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                 :         90 :     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                 :          0 : 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                 :          0 :     const ucontext_t *ctx = (const ucontext_t*)_ctx;
      71                 :          0 :     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                 :          0 : static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr)
      97                 :            : {
      98                 :            :     // One guard page for signal_stack.
      99         [ #  # ]:          0 :     return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size ||
     100         [ #  # ]:          0 :              (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                 :          0 : 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   [ #  #  #  # ]:          0 :     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                 :          0 :     uintptr_t rsp = jl_get_rsp_from_ctx(_ctx);
     125         [ #  # ]:          0 :     if (is_addr_on_sigstack(ptls, (void*)rsp)) {
     126                 :          0 :         rsp = (rsp - 256) & ~(uintptr_t)15; // redzone and re-alignment
     127                 :            :     }
     128                 :            :     else {
     129                 :          0 :         rsp = (uintptr_t)ptls->signal_stack + sig_stack_size;
     130                 :            :     }
     131         [ #  # ]:          0 :     assert(rsp % 16 == 0);
     132                 :            : #if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
     133                 :          0 :     ucontext_t *ctx = (ucontext_t*)_ctx;
     134                 :          0 :     rsp -= sizeof(void*);
     135                 :          0 :     ctx->uc_mcontext.gregs[REG_RSP] = rsp;
     136                 :          0 :     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                 :          0 : static void jl_throw_in_ctx(jl_task_t *ct, jl_value_t *e, int sig, void *sigctx)
     204                 :            : {
     205                 :          0 :     jl_ptls_t ptls = ct->ptls;
     206         [ #  # ]:          0 :     if (!jl_get_safe_restore()) {
     207                 :          0 :         ptls->bt_size =
     208                 :          0 :             rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, jl_to_bt_context(sigctx),
     209                 :            :                               ct->gcstack);
     210                 :          0 :         ptls->sig_exception = e;
     211                 :            :     }
     212                 :          0 :     jl_call_in_ctx(ptls, &jl_sig_throw, sig, sigctx);
     213                 :          0 : }
     214                 :            : 
     215                 :            : static pthread_t signals_thread;
     216                 :            : 
     217                 :          0 : static int is_addr_on_stack(jl_task_t *ct, void *addr)
     218                 :            : {
     219         [ #  # ]:          0 :     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         [ #  # ]:          0 :     return ((char*)addr > (char*)ct->stkbuf &&
     225         [ #  # ]:          0 :             (char*)addr < (char*)ct->stkbuf + ct->bufsz);
     226                 :            : }
     227                 :            : 
     228                 :          0 : static void sigdie_handler(int sig, siginfo_t *info, void *context)
     229                 :            : {
     230                 :          0 :     signal(sig, SIG_DFL);
     231                 :          0 :     uv_tty_reset_mode();
     232         [ #  # ]:          0 :     if (sig == SIGILL)
     233                 :          0 :         jl_show_sigill(context);
     234                 :          0 :     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                 :          0 : int exc_reg_is_write_fault(uintptr_t err) {
     251                 :          0 :     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                 :          0 : int is_write_fault(void *context) {
     272                 :          0 :     ucontext_t *ctx = (ucontext_t*)context;
     273                 :          0 :     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                 :          0 : static int jl_is_on_sigstack(jl_ptls_t ptls, void *ptr, void *context)
     308                 :            : {
     309   [ #  #  #  # ]:          0 :     return (is_addr_on_sigstack(ptls, ptr) &&
     310                 :          0 :             is_addr_on_sigstack(ptls, (void*)jl_get_rsp_from_ctx(context)));
     311                 :            : }
     312                 :            : 
     313                 :          0 : static void segv_handler(int sig, siginfo_t *info, void *context)
     314                 :            : {
     315         [ #  # ]:          0 :     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                 :          0 :     jl_task_t *ct = jl_get_current_task();
     320         [ #  # ]:          0 :     if (ct == NULL) {
     321                 :          0 :         sigdie_handler(sig, info, context);
     322                 :          0 :         return;
     323                 :            :     }
     324   [ #  #  #  # ]:          0 :     assert(sig == SIGSEGV || sig == SIGBUS);
     325         [ #  # ]:          0 :     if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) {
     326                 :          0 :         jl_set_gc_and_wait();
     327                 :            :         // Do not raise sigint on worker thread
     328         [ #  # ]:          0 :         if (jl_atomic_load_relaxed(&ct->tid) != 0)
     329                 :          0 :             return;
     330         [ #  # ]:          0 :         if (ct->ptls->defer_signal) {
     331                 :          0 :             jl_safepoint_defer_sigint();
     332                 :            :         }
     333         [ #  # ]:          0 :         else if (jl_safepoint_consume_sigint()) {
     334                 :          0 :             jl_clear_force_sigint();
     335                 :          0 :             jl_throw_in_ctx(ct, jl_interrupt_exception, sig, context);
     336                 :            :         }
     337                 :          0 :         return;
     338                 :            :     }
     339         [ #  # ]:          0 :     if (is_addr_on_stack(ct, info->si_addr)) { // stack overflow
     340                 :          0 :         jl_throw_in_ctx(ct, jl_stackovf_exception, sig, context);
     341                 :            :     }
     342         [ #  # ]:          0 :     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   [ #  #  #  #  :          0 :     else if (sig == SIGSEGV && info->si_code == SEGV_ACCERR && is_write_fault(context)) {  // writing to read-only memory (e.g., mmap)
                   #  # ]
     352                 :          0 :         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                 :          0 :         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                 :         90 : static void jl_thread_suspend_and_get_state(int tid, unw_context_t **ctx)
     370                 :            : {
     371                 :            :     struct timespec ts;
     372                 :         90 :     clock_gettime(CLOCK_REALTIME, &ts);
     373                 :         90 :     ts.tv_sec += 1;
     374                 :         90 :     pthread_mutex_lock(&in_signal_lock);
     375                 :         90 :     jl_ptls_t ptls2 = jl_all_tls_states[tid];
     376                 :         90 :     jl_atomic_store_release(&ptls2->signal_request, 1);
     377                 :         90 :     pthread_kill(ptls2->system_id, SIGUSR2);
     378                 :            :     // wait for thread to acknowledge
     379                 :         90 :     int err = pthread_cond_timedwait(&signal_caught_cond, &in_signal_lock, &ts);
     380         [ -  + ]:         90 :     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                 :         90 :     int request = jl_atomic_load_acquire(&ptls2->signal_request);
     401         [ -  + ]:         90 :     assert(request == 0); (void) request;
     402                 :         90 :     *ctx = signal_context;
     403                 :            : }
     404                 :            : 
     405                 :         90 : static void jl_thread_resume(int tid, int sig)
     406                 :            : {
     407                 :         90 :     jl_ptls_t ptls2 = jl_all_tls_states[tid];
     408         [ -  + ]:         90 :     jl_atomic_store_release(&ptls2->signal_request, sig == -1 ? 3 : 1);
     409                 :         90 :     pthread_cond_broadcast(&exit_signal_cond);
     410                 :         90 :     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                 :         90 :     int request = jl_atomic_load_acquire(&ptls2->signal_request);
     414         [ -  + ]:         90 :     assert(request == 0); (void) request;
     415                 :         90 :     pthread_mutex_unlock(&in_signal_lock);
     416                 :         90 : }
     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                 :          0 : static void jl_try_deliver_sigint(void)
     422                 :            : {
     423                 :          0 :     jl_ptls_t ptls2 = jl_all_tls_states[0];
     424                 :          0 :     jl_safepoint_enable_sigint();
     425                 :          0 :     jl_wake_libuv();
     426                 :          0 :     jl_atomic_store_release(&ptls2->signal_request, 2);
     427                 :            :     // This also makes sure `sleep` is aborted.
     428                 :          0 :     pthread_kill(ptls2->system_id, SIGUSR2);
     429                 :          0 : }
     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                 :          0 : static void JL_NORETURN jl_exit_thread0_cb(void)
     435                 :            : {
     436                 :          0 : 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         [ #  # ]:          0 :     if (thread0_exit_count <= 1) {
     441                 :          0 :         jl_critical_error(thread0_exit_state - 128, NULL, jl_current_task);
     442                 :          0 :         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                 :          0 : static void jl_exit_thread0(int state, jl_bt_element_t *bt_data, size_t bt_size)
     453                 :            : {
     454                 :          0 :     jl_ptls_t ptls2 = jl_all_tls_states[0];
     455         [ #  # ]:          0 :     if (thread0_exit_count <= 1) {
     456                 :            :         unw_context_t *signal_context;
     457                 :          0 :         jl_thread_suspend_and_get_state(0, &signal_context);
     458         [ #  # ]:          0 :         if (signal_context != NULL) {
     459                 :          0 :             thread0_exit_state = state;
     460                 :          0 :             ptls2->bt_size = bt_size; // <= JL_MAX_BT_SIZE
     461                 :          0 :             memcpy(ptls2->bt_data, bt_data, ptls2->bt_size * sizeof(bt_data[0]));
     462                 :          0 :             jl_thread_resume(0, -1);
     463                 :          0 :             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                 :         90 : void usr2_handler(int sig, siginfo_t *info, void *ctx)
     480                 :            : {
     481                 :         90 :     jl_task_t *ct = jl_get_current_task();
     482         [ -  + ]:         90 :     if (ct == NULL)
     483                 :          0 :         return;
     484                 :         90 :     jl_ptls_t ptls = ct->ptls;
     485         [ -  + ]:         90 :     if (ptls == NULL)
     486                 :          0 :         return;
     487                 :         90 :     int errno_save = errno;
     488                 :            :     // acknowledge that we saw the signal_request
     489                 :         90 :     sig_atomic_t request = jl_atomic_exchange(&ptls->signal_request, -1);
     490                 :            : #if !defined(JL_DISABLE_LIBUNWIND)
     491         [ +  - ]:         90 :     if (request == 1) {
     492                 :         90 :         pthread_mutex_lock(&in_signal_lock);
     493                 :         90 :         signal_context = jl_to_bt_context(ctx);
     494                 :            :         // acknowledge that we set the signal_caught_cond broadcast
     495                 :         90 :         request = jl_atomic_exchange(&ptls->signal_request, 0);
     496         [ -  + ]:         90 :         assert(request == -1); (void) request;
     497                 :         90 :         pthread_cond_broadcast(&signal_caught_cond);
     498                 :         90 :         pthread_cond_wait(&exit_signal_cond, &in_signal_lock);
     499                 :         90 :         request = jl_atomic_exchange(&ptls->signal_request, 0);
     500   [ -  +  -  - ]:         90 :         assert(request == 1 || request == 3);
     501                 :            :         // acknowledge that we got the resume signal
     502                 :         90 :         pthread_cond_broadcast(&signal_caught_cond);
     503                 :         90 :         pthread_mutex_unlock(&in_signal_lock);
     504                 :            :     }
     505                 :            :     else
     506                 :            : #endif
     507                 :          0 :     jl_atomic_exchange(&ptls->signal_request, 0); // returns -1
     508         [ -  + ]:         90 :     if (request == 2) {
     509                 :          0 :         int force = jl_check_force_sigint();
     510   [ #  #  #  #  :          0 :         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         [ -  + ]:         90 :     else if (request == 3) {
     520                 :          0 :         jl_call_in_ctx(ct->ptls, jl_exit_thread0_cb, sig, ctx);
     521                 :            :     }
     522                 :         90 :     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                 :          2 : JL_DLLEXPORT int jl_profile_start_timer(void)
     544                 :            : {
     545                 :            :     struct sigevent sigprof;
     546                 :            : 
     547                 :            :     // Establish the signal event
     548                 :          2 :     memset(&sigprof, 0, sizeof(struct sigevent));
     549                 :          2 :     sigprof.sigev_notify = SIGEV_SIGNAL;
     550                 :          2 :     sigprof.sigev_signo = SIGUSR1;
     551                 :          2 :     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                 :          2 :     running = 1;
     554         [ -  + ]:          2 :     if (timer_create(CLOCK_REALTIME, &sigprof, &timerprof) == -1) {
     555                 :          0 :         running = 0;
     556                 :          0 :         return -2;
     557                 :            :     }
     558                 :            : 
     559                 :            :     // Start the timer
     560                 :          2 :     itsprof.it_interval.tv_sec = 0;
     561                 :          2 :     itsprof.it_interval.tv_nsec = 0;
     562                 :          2 :     itsprof.it_value.tv_sec = nsecprof / GIGA;
     563                 :          2 :     itsprof.it_value.tv_nsec = nsecprof % GIGA;
     564         [ -  + ]:          2 :     if (timer_settime(timerprof, 0, &itsprof, NULL) == -1) {
     565                 :          0 :         running = 0;
     566                 :          0 :         return -3;
     567                 :            :     }
     568                 :          2 :     return 0;
     569                 :            : }
     570                 :            : 
     571                 :          2 : JL_DLLEXPORT void jl_profile_stop_timer(void)
     572                 :            : {
     573         [ +  - ]:          2 :     if (running) {
     574                 :          2 :         timer_delete(timerprof);
     575                 :          2 :         last_timer_delete_time = jl_hrtime();
     576                 :          2 :         running = 0;
     577                 :            :     }
     578                 :          2 : }
     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                 :         15 : static void allocate_segv_handler(void)
     619                 :            : {
     620                 :            :     struct sigaction act;
     621                 :         15 :     memset(&act, 0, sizeof(struct sigaction));
     622                 :         15 :     sigemptyset(&act.sa_mask);
     623                 :         15 :     act.sa_sigaction = segv_handler;
     624                 :         15 :     act.sa_flags = SA_ONSTACK | SA_SIGINFO;
     625         [ -  + ]:         15 :     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         [ -  + ]:         15 :     if (sigaction(SIGBUS, &act, NULL) < 0) {
     630                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
     631                 :            :     }
     632                 :         15 : }
     633                 :            : 
     634                 :         15 : static void *alloc_sigstack(size_t *ssize)
     635                 :            : {
     636                 :         15 :     void *stk = jl_malloc_stack(ssize, NULL);
     637         [ -  + ]:         15 :     if (stk == MAP_FAILED)
     638                 :          0 :         jl_errorf("fatal error allocating signal stack: mmap: %s", strerror(errno));
     639                 :         15 :     return stk;
     640                 :            : }
     641                 :            : 
     642                 :         15 : void jl_install_thread_signal_handler(jl_ptls_t ptls)
     643                 :            : {
     644                 :         15 :     size_t ssize = sig_stack_size;
     645                 :         15 :     void *signal_stack = alloc_sigstack(&ssize);
     646                 :         15 :     ptls->signal_stack = signal_stack;
     647                 :            :     stack_t ss;
     648                 :         15 :     ss.ss_flags = 0;
     649                 :         15 :     ss.ss_size = ssize - 16;
     650                 :         15 :     ss.ss_sp = signal_stack;
     651         [ -  + ]:         15 :     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                 :         15 : }
     659                 :            : 
     660                 :         30 : static void jl_sigsetset(sigset_t *sset)
     661                 :            : {
     662                 :         30 :     sigemptyset(sset);
     663                 :         30 :     sigaddset(sset, SIGINT);
     664                 :         30 :     sigaddset(sset, SIGTERM);
     665                 :         30 :     sigaddset(sset, SIGABRT);
     666                 :         30 :     sigaddset(sset, SIGQUIT);
     667                 :            : #ifdef SIGINFO
     668                 :            :     sigaddset(sset, SIGINFO);
     669                 :            : #else
     670                 :         30 :     sigaddset(sset, SIGUSR1);
     671                 :            : #endif
     672                 :            : #if defined(HAVE_TIMER)
     673                 :         30 :     sigaddset(sset, SIGUSR1);
     674                 :            : #elif defined(HAVE_ITIMER)
     675                 :            :     sigaddset(sset, SIGPROF);
     676                 :            : #endif
     677                 :         30 : }
     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                 :         15 : 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                 :         15 :     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                 :         90 :     while (1) {
     742                 :        105 :         sig = 0;
     743                 :        105 :         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                 :        105 :         sig = sigwaitinfo(&sset, &info);
     763                 :            : #else
     764                 :            :         if (sigwait(&sset, &sig))
     765                 :            :             sig = -1;
     766                 :            : #endif
     767         [ -  + ]:         90 :         if (sig == -1) {
     768         [ #  # ]:          0 :             if (errno == EINTR)
     769                 :          0 :                 continue;
     770                 :          0 :             sig = SIGABRT; // this branch can't occur, unless we had stack memory corruption of sset
     771                 :            :         }
     772                 :         90 :         profile = 0;
     773                 :            : #ifndef HAVE_MACH
     774                 :            : #if defined(HAVE_TIMER)
     775                 :         90 :         profile = (sig == SIGUSR1);
     776                 :            : #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
     777   [ +  -  +  - ]:         90 :         if (profile && !(info.si_code == SI_TIMER &&
     778         [ -  + ]:         90 :                     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         [ -  + ]:         90 :         if (sig == SIGINT) {
     787         [ #  # ]:          0 :             if (jl_ignore_sigint()) {
     788                 :          0 :                 continue;
     789                 :            :             }
     790         [ #  # ]:          0 :             else if (exit_on_sigint) {
     791                 :          0 :                 critical = 1;
     792                 :            :             }
     793                 :            :             else {
     794                 :          0 :                 jl_try_deliver_sigint();
     795                 :          0 :                 continue;
     796                 :            :             }
     797                 :            :         }
     798                 :            :         else {
     799                 :         90 :             critical = 0;
     800                 :            :         }
     801                 :            : 
     802                 :         90 :         critical |= (sig == SIGTERM);
     803                 :         90 :         critical |= (sig == SIGABRT);
     804                 :         90 :         critical |= (sig == SIGQUIT);
     805                 :            : #ifdef SIGINFO
     806                 :            :         critical |= (sig == SIGINFO);
     807                 :            : #else
     808   [ +  -  -  + ]:         90 :         critical |= (sig == SIGUSR1 && !profile);
     809                 :            : #endif
     810                 :            : 
     811                 :         90 :         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         [ +  - ]:         90 :         if (sig == SIGUSR1) {
     820   [ -  +  -  - ]:         90 :             if (running != 1 && timer_graceperiod_elapsed())
     821                 :          0 :                 trigger_profile_peek();
     822                 :         90 :             doexit = 0;
     823                 :            :         }
     824                 :            : #endif
     825                 :            : 
     826                 :         90 :         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   [ +  -  +  - ]:         90 :         if (critical || profile) {
     832                 :         90 :             jl_lock_profile();
     833                 :            :             int *randperm;
     834         [ +  - ]:         90 :             if (profile)
     835                 :         90 :                  randperm = profile_get_randperm(jl_n_threads);
     836         [ +  + ]:        180 :             for (int idx = jl_n_threads; idx-- > 0; ) {
     837                 :            :                 // Stop the threads in the random or reverse round-robin order.
     838         [ +  - ]:         90 :                 int i = profile ? randperm[idx] : idx;
     839                 :            :                 // notify thread to stop
     840                 :         90 :                 jl_thread_suspend_and_get_state(i, &signal_context);
     841         [ -  + ]:         90 :                 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         [ -  + ]:         90 :                 if (critical) {
     847                 :          0 :                     bt_size += rec_backtrace_ctx(bt_data + bt_size,
     848                 :          0 :                             JL_MAX_BT_SIZE / jl_n_threads - 1,
     849                 :            :                             signal_context, NULL);
     850                 :          0 :                     bt_data[bt_size++].uintptr = 0;
     851                 :            :                 }
     852                 :            : 
     853                 :            :                 // do backtrace for profiler
     854   [ +  -  +  - ]:         90 :                 if (profile && running) {
     855         [ -  + ]:         90 :                     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                 :         90 :                         jl_jmp_buf *old_buf = jl_get_safe_restore();
     863                 :            :                         jl_jmp_buf buf;
     864                 :            : 
     865                 :         90 :                         jl_set_safe_restore(&buf);
     866         [ -  + ]:         90 :                         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                 :         90 :                             bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur,
     871                 :         90 :                                     bt_size_max - bt_size_cur - 1, signal_context, NULL);
     872                 :            :                         }
     873                 :         90 :                         jl_set_safe_restore(old_buf);
     874                 :            : 
     875                 :         90 :                         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                 :         90 :                         bt_data_prof[bt_size_cur++].uintptr = ptls2->tid + 1;
     879                 :            : 
     880                 :            :                         // store task id
     881                 :         90 :                         bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task);
     882                 :            : 
     883                 :            :                         // store cpu cycle clock
     884                 :         90 :                         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                 :         90 :                         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                 :         90 :                         bt_data_prof[bt_size_cur++].uintptr = 0;
     891                 :         90 :                         bt_data_prof[bt_size_cur++].uintptr = 0;
     892                 :            :                     }
     893                 :            :                 }
     894                 :            : 
     895                 :            :                 // notify thread to resume
     896                 :         90 :                 jl_thread_resume(i, sig);
     897                 :            :             }
     898                 :         90 :             jl_unlock_profile();
     899                 :            :         }
     900                 :            : #ifndef HAVE_MACH
     901   [ +  -  +  - ]:         90 :         if (profile && running) {
     902                 :         90 :             jl_check_profile_autostop();
     903                 :            : #if defined(HAVE_TIMER)
     904                 :         90 :             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         [ -  + ]:         90 :         if (critical) {
     915         [ #  # ]:          0 :             if (doexit) {
     916                 :          0 :                 thread0_exit_count++;
     917                 :          0 :                 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                 :         15 : void restore_signals(void)
     941                 :            : {
     942                 :         15 :     sigemptyset(&jl_sigint_sset);
     943                 :         15 :     sigaddset(&jl_sigint_sset, SIGINT);
     944                 :            : 
     945                 :            :     sigset_t sset;
     946                 :         15 :     jl_sigsetset(&sset);
     947                 :         15 :     sigprocmask(SIG_SETMASK, &sset, 0);
     948                 :            : 
     949                 :            : #if !defined(HAVE_MACH) && !defined(JL_DISABLE_LIBUNWIND)
     950   [ +  -  +  - ]:         30 :     if (pthread_mutex_init(&in_signal_lock, NULL) != 0 ||
     951         [ -  + ]:         30 :         pthread_cond_init(&exit_signal_cond, NULL) != 0 ||
     952                 :         15 :         pthread_cond_init(&signal_caught_cond, NULL) != 0) {
     953                 :          0 :         jl_error("SIGUSR pthread init failed");
     954                 :            :     }
     955                 :            : #endif
     956                 :            : 
     957         [ -  + ]:         15 :     if (pthread_create(&signals_thread, NULL, signal_listener, NULL) != 0) {
     958                 :          0 :         jl_error("pthread_create(signal_listener) failed");
     959                 :            :     }
     960                 :         15 : }
     961                 :            : 
     962                 :          0 : static void fpe_handler(int sig, siginfo_t *info, void *context)
     963                 :            : {
     964                 :            :     (void)info;
     965         [ #  # ]:          0 :     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                 :          0 :     jl_task_t *ct = jl_get_current_task();
     970         [ #  # ]:          0 :     if (ct == NULL) // exception on foreign thread is fatal
     971                 :          0 :         sigdie_handler(sig, info, context);
     972                 :            :     else
     973                 :          0 :         jl_throw_in_ctx(ct, jl_diverror_exception, sig, context);
     974                 :            : }
     975                 :            : 
     976                 :          0 : static void sigint_handler(int sig)
     977                 :            : {
     978                 :          0 :     jl_sigint_passed = 1;
     979                 :          0 : }
     980                 :            : 
     981                 :         15 : void jl_install_default_signal_handlers(void)
     982                 :            : {
     983                 :            :     struct sigaction actf;
     984                 :         15 :     memset(&actf, 0, sizeof(struct sigaction));
     985                 :         15 :     sigemptyset(&actf.sa_mask);
     986                 :         15 :     actf.sa_sigaction = fpe_handler;
     987                 :         15 :     actf.sa_flags = SA_ONSTACK | SA_SIGINFO;
     988         [ -  + ]:         15 :     if (sigaction(SIGFPE, &actf, NULL) < 0) {
     989                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
     990                 :            :     }
     991                 :            :     struct sigaction actint;
     992                 :         15 :     memset(&actint, 0, sizeof(struct sigaction));
     993                 :         15 :     sigemptyset(&actint.sa_mask);
     994                 :         15 :     actint.sa_handler = sigint_handler;
     995                 :         15 :     actint.sa_flags = 0;
     996         [ -  + ]:         15 :     if (sigaction(SIGINT, &actint, NULL) < 0) {
     997                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
     998                 :            :     }
     999         [ -  + ]:         15 :     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
    1000                 :          0 :         jl_error("fatal error: Couldn't set SIGPIPE");
    1001                 :            :     }
    1002         [ -  + ]:         15 :     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                 :         15 :     memset(&act, 0, sizeof(struct sigaction));
    1011                 :         15 :     sigemptyset(&act.sa_mask);
    1012                 :         15 :     act.sa_sigaction = usr2_handler;
    1013                 :         15 :     act.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART;
    1014         [ -  + ]:         15 :     if (sigaction(SIGUSR2, &act, NULL) < 0) {
    1015                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
    1016                 :            :     }
    1017                 :            : #endif
    1018                 :            : 
    1019                 :         15 :     allocate_segv_handler();
    1020                 :            : 
    1021                 :            :     struct sigaction act_die;
    1022                 :         15 :     memset(&act_die, 0, sizeof(struct sigaction));
    1023                 :         15 :     sigemptyset(&act_die.sa_mask);
    1024                 :         15 :     act_die.sa_sigaction = sigdie_handler;
    1025                 :         15 :     act_die.sa_flags = SA_SIGINFO | SA_RESETHAND;
    1026         [ -  + ]:         15 :     if (sigaction(SIGILL, &act_die, NULL) < 0) {
    1027                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
    1028                 :            :     }
    1029         [ -  + ]:         15 :     if (sigaction(SIGABRT, &act_die, NULL) < 0) {
    1030                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
    1031                 :            :     }
    1032         [ -  + ]:         15 :     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                 :         15 :     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         [ -  + ]:         15 :     if (sigaction(SIGUSR1, &act_die, NULL) < 0) {
    1048                 :          0 :         jl_errorf("fatal error: sigaction: %s", strerror(errno));
    1049                 :            :     }
    1050                 :            : #endif
    1051                 :         15 : }
    1052                 :            : 
    1053                 :         15 : JL_DLLEXPORT void jl_install_sigint_handler(void)
    1054                 :            : {
    1055                 :            :     // TODO: ?
    1056                 :         15 : }
    1057                 :            : 
    1058                 :          0 : JL_DLLEXPORT int jl_repl_raise_sigtstp(void)
    1059                 :            : {
    1060                 :          0 :     return raise(SIGTSTP);
    1061                 :            : }

Generated by: LCOV version 1.14