LCOV - code coverage report
Current view: top level - src - signal-handling.c (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 67 174 38.5 %
Date: 2022-07-17 01:01:28 Functions: 17 28 60.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 11 68 16.2 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #include <stdlib.h>
       4                 :            : #include <stddef.h>
       5                 :            : #include <stdio.h>
       6                 :            : #include <inttypes.h>
       7                 :            : #include "julia.h"
       8                 :            : #include "julia_internal.h"
       9                 :            : #ifndef _OS_WINDOWS_
      10                 :            : #include <unistd.h>
      11                 :            : #include <sys/mman.h>
      12                 :            : #endif
      13                 :            : 
      14                 :            : #ifdef __cplusplus
      15                 :            : extern "C" {
      16                 :            : #endif
      17                 :            : 
      18                 :            : #include <threading.h>
      19                 :            : 
      20                 :            : // Profiler control variables
      21                 :            : // Note: these "static" variables are also used in "signals-*.c"
      22                 :            : static volatile jl_bt_element_t *bt_data_prof = NULL;
      23                 :            : static volatile size_t bt_size_max = 0;
      24                 :            : static volatile size_t bt_size_cur = 0;
      25                 :            : static volatile uint64_t nsecprof = 0;
      26                 :            : static volatile int running = 0;
      27                 :            : static const    uint64_t GIGA = 1000000000ULL;
      28                 :            : // Timers to take samples at intervals
      29                 :            : JL_DLLEXPORT void jl_profile_stop_timer(void);
      30                 :            : JL_DLLEXPORT int jl_profile_start_timer(void);
      31                 :            : 
      32                 :            : // Any function that acquires this lock must be either a unmanaged thread
      33                 :            : // or in the GC safe region and must NOT allocate anything through the GC
      34                 :            : // while holding this lock.
      35                 :            : // Certain functions in this file might be called from an unmanaged thread
      36                 :            : // and cannot have any interaction with the julia runtime
      37                 :            : // They also may be re-entrant, and operating while threads are paused, so we
      38                 :            : // separately manage the re-entrant count behavior for safety across platforms
      39                 :            : // Note that we cannot safely upgrade read->write
      40                 :            : uv_rwlock_t debuginfo_asyncsafe;
      41                 :            : #ifndef _OS_WINDOWS_
      42                 :            : pthread_key_t debuginfo_asyncsafe_held;
      43                 :            : #else
      44                 :            : DWORD debuginfo_asyncsafe_held;
      45                 :            : #endif
      46                 :            : 
      47                 :         15 : void jl_init_profile_lock(void)
      48                 :            : {
      49                 :         15 :     uv_rwlock_init(&debuginfo_asyncsafe);
      50                 :            : #ifndef _OS_WINDOWS_
      51                 :         15 :     pthread_key_create(&debuginfo_asyncsafe_held, NULL);
      52                 :            : #else
      53                 :            :     debuginfo_asyncsafe_held = TlsAlloc();
      54                 :            : #endif
      55                 :         15 : }
      56                 :            : 
      57                 :        384 : uintptr_t jl_lock_profile_rd_held(void)
      58                 :            : {
      59                 :            : #ifndef _OS_WINDOWS_
      60                 :        384 :     return (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held);
      61                 :            : #else
      62                 :            :     return (uintptr_t)TlsGetValue(debuginfo_asyncsafe_held);
      63                 :            : #endif
      64                 :            : }
      65                 :            : 
      66                 :        192 : void jl_lock_profile(void)
      67                 :            : {
      68                 :        192 :     uintptr_t held = jl_lock_profile_rd_held();
      69         [ +  - ]:        192 :     if (held++ == 0)
      70                 :        192 :         uv_rwlock_rdlock(&debuginfo_asyncsafe);
      71                 :            : #ifndef _OS_WINDOWS_
      72                 :        192 :     pthread_setspecific(debuginfo_asyncsafe_held, (void*)held);
      73                 :            : #else
      74                 :            :     TlsSetValue(debuginfo_asyncsafe_held, (void*)held);
      75                 :            : #endif
      76                 :        192 : }
      77                 :            : 
      78                 :        192 : JL_DLLEXPORT void jl_unlock_profile(void)
      79                 :            : {
      80                 :        192 :     uintptr_t held = jl_lock_profile_rd_held();
      81         [ -  + ]:        192 :     assert(held);
      82         [ +  - ]:        192 :     if (--held == 0)
      83                 :        192 :         uv_rwlock_rdunlock(&debuginfo_asyncsafe);
      84                 :            : #ifndef _OS_WINDOWS_
      85                 :        192 :     pthread_setspecific(debuginfo_asyncsafe_held, (void*)held);
      86                 :            : #else
      87                 :            :     TlsSetValue(debuginfo_asyncsafe_held, (void*)held);
      88                 :            : #endif
      89                 :        192 : }
      90                 :            : 
      91                 :     161252 : void jl_lock_profile_wr(void)
      92                 :            : {
      93                 :     161252 :     uv_rwlock_wrlock(&debuginfo_asyncsafe);
      94                 :     161252 : }
      95                 :            : 
      96                 :     161252 : void jl_unlock_profile_wr(void)
      97                 :            : {
      98                 :     161252 :     uv_rwlock_wrunlock(&debuginfo_asyncsafe);
      99                 :     161252 : }
     100                 :            : 
     101                 :            : 
     102                 :            : #ifndef _OS_WINDOWS_
     103                 :            : static uint64_t profile_cong_rng_seed = 0;
     104                 :            : static int *profile_round_robin_thread_order = NULL;
     105                 :            : static int profile_round_robin_thread_order_size = 0;
     106                 :            : 
     107                 :         90 : static void jl_shuffle_int_array_inplace(int *carray, int size, uint64_t *seed)
     108                 :            : {
     109                 :            :     // The "modern Fisher–Yates shuffle" - O(n) algorithm
     110                 :            :     // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
     111         [ -  + ]:         90 :     for (int i = size; i-- > 1; ) {
     112                 :          0 :         uint64_t unbias = UINT64_MAX; // slightly biased, but i is very small
     113                 :          0 :         size_t j = cong(i, unbias, seed);
     114                 :          0 :         uint64_t tmp = carray[j];
     115                 :          0 :         carray[j] = carray[i];
     116                 :          0 :         carray[i] = tmp;
     117                 :            :     }
     118                 :         90 : }
     119                 :            : 
     120                 :            : 
     121                 :         90 : static int *profile_get_randperm(int size)
     122                 :            : {
     123         [ +  + ]:         90 :     if (profile_round_robin_thread_order_size < size) {
     124                 :          2 :         free(profile_round_robin_thread_order);
     125                 :          2 :         profile_round_robin_thread_order = (int*)malloc_s(size * sizeof(int));
     126         [ +  + ]:          4 :         for (int i = 0; i < size; i++)
     127                 :          2 :             profile_round_robin_thread_order[i] = i;
     128                 :          2 :         profile_round_robin_thread_order_size = size;
     129                 :          2 :         profile_cong_rng_seed = jl_rand();
     130                 :            :     }
     131                 :         90 :     jl_shuffle_int_array_inplace(profile_round_robin_thread_order, size, &profile_cong_rng_seed);
     132                 :         90 :     return profile_round_robin_thread_order;
     133                 :            : }
     134                 :            : #endif
     135                 :            : 
     136                 :            : 
     137                 :         92 : JL_DLLEXPORT int jl_profile_is_buffer_full(void)
     138                 :            : {
     139                 :            :     // declare buffer full if there isn't enough room to take samples across all threads
     140                 :            :     #if defined(_OS_WINDOWS_)
     141                 :            :         uint64_t nthreads = 1; // windows only profiles the main thread
     142                 :            :     #else
     143                 :         92 :         uint64_t nthreads = jl_n_threads;
     144                 :            :     #endif
     145                 :            :     // the `+ 6` is for the two block terminators `0` plus 4 metadata entries
     146                 :         92 :     return bt_size_cur + (((JL_BT_MAX_ENTRY_SIZE + 1) + 6) * nthreads) > bt_size_max;
     147                 :            : }
     148                 :            : 
     149                 :            : static uint64_t jl_last_sigint_trigger = 0;
     150                 :            : static uint64_t jl_disable_sigint_time = 0;
     151                 :          0 : static void jl_clear_force_sigint(void)
     152                 :            : {
     153                 :          0 :     jl_last_sigint_trigger = 0;
     154                 :          0 : }
     155                 :            : 
     156                 :          0 : static int jl_check_force_sigint(void)
     157                 :            : {
     158                 :            :     static double accum_weight = 0;
     159                 :          0 :     uint64_t cur_time = uv_hrtime();
     160                 :          0 :     uint64_t dt = cur_time - jl_last_sigint_trigger;
     161                 :          0 :     uint64_t last_t = jl_last_sigint_trigger;
     162                 :          0 :     jl_last_sigint_trigger = cur_time;
     163         [ #  # ]:          0 :     if (last_t == 0) {
     164                 :          0 :         accum_weight = 0;
     165                 :          0 :         return 0;
     166                 :            :     }
     167                 :          0 :     double new_weight = accum_weight * exp(-(dt / 1e9)) + 0.3;
     168         [ #  # ]:          0 :     if (!isnormal(new_weight))
     169                 :          0 :         new_weight = 0;
     170                 :          0 :     accum_weight = new_weight;
     171         [ #  # ]:          0 :     if (new_weight > 1) {
     172                 :          0 :         jl_disable_sigint_time = cur_time + (uint64_t)0.5e9;
     173                 :          0 :         return 1;
     174                 :            :     }
     175                 :          0 :     jl_disable_sigint_time = 0;
     176                 :          0 :     return 0;
     177                 :            : }
     178                 :            : 
     179                 :            : #ifndef _OS_WINDOWS_
     180                 :            : // Not thread local, should only be accessed by the signal handler thread.
     181                 :            : static volatile int jl_sigint_passed = 0;
     182                 :            : static sigset_t jl_sigint_sset;
     183                 :            : #endif
     184                 :            : 
     185                 :          0 : static int jl_ignore_sigint(void)
     186                 :            : {
     187                 :            :     // On Unix, we get the SIGINT before the debugger which makes it very
     188                 :            :     // hard to interrupt a running process in the debugger with `Ctrl-C`.
     189                 :            :     // Manually raise a `SIGINT` on current thread with the signal temporarily
     190                 :            :     // unblocked and use it's behavior to decide if we need to handle the signal.
     191                 :            : #ifndef _OS_WINDOWS_
     192                 :          0 :     jl_sigint_passed = 0;
     193                 :          0 :     pthread_sigmask(SIG_UNBLOCK, &jl_sigint_sset, NULL);
     194                 :            :     // This can swallow an external `SIGINT` but it's not an issue
     195                 :            :     // since we don't deliver the same number of signals anyway.
     196                 :          0 :     pthread_kill(pthread_self(), SIGINT);
     197                 :          0 :     pthread_sigmask(SIG_BLOCK, &jl_sigint_sset, NULL);
     198         [ #  # ]:          0 :     if (!jl_sigint_passed)
     199                 :          0 :         return 1;
     200                 :            : #endif
     201                 :            :     // Force sigint requires pressing `Ctrl-C` repeatedly.
     202                 :            :     // Ignore sigint for a short time after that to avoid rethrowing sigint too
     203                 :            :     // quickly again. (Code that has this issue is inherently racy but this is
     204                 :            :     // an interactive feature anyway.)
     205   [ #  #  #  # ]:          0 :     return jl_disable_sigint_time && jl_disable_sigint_time > uv_hrtime();
     206                 :            : }
     207                 :            : 
     208                 :            : static int exit_on_sigint = 0;
     209                 :          8 : JL_DLLEXPORT void jl_exit_on_sigint(int on)
     210                 :            : {
     211                 :          8 :     exit_on_sigint = on;
     212                 :          8 : }
     213                 :            : 
     214                 :            : static uintptr_t jl_get_pc_from_ctx(const void *_ctx);
     215                 :            : void jl_show_sigill(void *_ctx);
     216                 :            : #if defined(_CPU_X86_64_) || defined(_CPU_X86_) \
     217                 :            :     || (defined(_OS_LINUX_) && defined(_CPU_AARCH64_)) \
     218                 :            :     || (defined(_OS_LINUX_) && defined(_CPU_ARM_))
     219                 :          0 : static size_t jl_safe_read_mem(const volatile char *ptr, char *out, size_t len)
     220                 :            : {
     221                 :          0 :     jl_jmp_buf *old_buf = jl_get_safe_restore();
     222                 :            :     jl_jmp_buf buf;
     223                 :          0 :     jl_set_safe_restore(&buf);
     224                 :          0 :     volatile size_t i = 0;
     225         [ #  # ]:          0 :     if (!jl_setjmp(buf, 0)) {
     226         [ #  # ]:          0 :         for (; i < len; i++) {
     227                 :          0 :             out[i] = ptr[i];
     228                 :            :         }
     229                 :            :     }
     230                 :          0 :     jl_set_safe_restore(old_buf);
     231                 :          0 :     return i;
     232                 :            : }
     233                 :            : #endif
     234                 :            : 
     235                 :            : static double profile_autostop_time = -1.0;
     236                 :            : static double profile_peek_duration = 1.0; // seconds
     237                 :            : 
     238                 :          0 : double jl_get_profile_peek_duration(void)
     239                 :            : {
     240                 :          0 :     return profile_peek_duration;
     241                 :            : }
     242                 :          0 : void jl_set_profile_peek_duration(double t)
     243                 :            : {
     244                 :          0 :     profile_peek_duration = t;
     245                 :          0 : }
     246                 :            : 
     247                 :            : uintptr_t profile_show_peek_cond_loc;
     248                 :         10 : JL_DLLEXPORT void jl_set_peek_cond(uintptr_t cond)
     249                 :            : {
     250                 :         10 :     profile_show_peek_cond_loc = cond;
     251                 :         10 : }
     252                 :            : 
     253                 :         90 : static void jl_check_profile_autostop(void)
     254                 :            : {
     255   [ -  +  -  - ]:         90 :     if ((profile_autostop_time != -1.0) && (jl_hrtime() > profile_autostop_time)) {
     256                 :          0 :         profile_autostop_time = -1.0;
     257                 :          0 :         jl_profile_stop_timer();
     258                 :          0 :         jl_safe_printf("\n==============================================================\n");
     259                 :          0 :         jl_safe_printf("Profile collected. A report will print at the next yield point\n");
     260                 :          0 :         jl_safe_printf("==============================================================\n\n");
     261                 :          0 :         uv_async_send((uv_async_t*)profile_show_peek_cond_loc);
     262                 :            :     }
     263                 :         90 : }
     264                 :            : 
     265                 :            : #if defined(_WIN32)
     266                 :            : #include "signals-win.c"
     267                 :            : #else
     268                 :            : #include "signals-unix.c"
     269                 :            : #endif
     270                 :            : 
     271                 :          0 : static uintptr_t jl_get_pc_from_ctx(const void *_ctx)
     272                 :            : {
     273                 :            : #if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
     274                 :          0 :     return ((ucontext_t*)_ctx)->uc_mcontext.gregs[REG_RIP];
     275                 :            : #elif defined(_OS_FREEBSD_) && defined(_CPU_X86_64_)
     276                 :            :     return ((ucontext_t*)_ctx)->uc_mcontext.mc_rip;
     277                 :            : #elif defined(_OS_LINUX_) && defined(_CPU_X86_)
     278                 :            :     return ((ucontext_t*)_ctx)->uc_mcontext.gregs[REG_EIP];
     279                 :            : #elif defined(_OS_FREEBSD_) && defined(_CPU_X86_)
     280                 :            :     return ((ucontext_t*)_ctx)->uc_mcontext.mc_eip;
     281                 :            : #elif defined(_OS_DARWIN_) && defined(_CPU_x86_64_)
     282                 :            :     return ((ucontext64_t*)_ctx)->uc_mcontext64->__ss.__rip;
     283                 :            : #elif defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
     284                 :            :     return ((ucontext64_t*)_ctx)->uc_mcontext64->__ss.__pc;
     285                 :            : #elif defined(_OS_WINDOWS_) && defined(_CPU_X86_)
     286                 :            :     return ((CONTEXT*)_ctx)->Eip;
     287                 :            : #elif defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
     288                 :            :     return ((CONTEXT*)_ctx)->Rip;
     289                 :            : #elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
     290                 :            :     return ((ucontext_t*)_ctx)->uc_mcontext.pc;
     291                 :            : #elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
     292                 :            :     return ((ucontext_t*)_ctx)->uc_mcontext.arm_pc;
     293                 :            : #else
     294                 :            :     // TODO for PPC
     295                 :            :     return 0;
     296                 :            : #endif
     297                 :            : }
     298                 :            : 
     299                 :          0 : void jl_show_sigill(void *_ctx)
     300                 :            : {
     301                 :          0 :     char *pc = (char*)jl_get_pc_from_ctx(_ctx);
     302                 :            :     // unsupported platform
     303         [ #  # ]:          0 :     if (!pc)
     304                 :          0 :         return;
     305                 :            : #if defined(_CPU_X86_64_) || defined(_CPU_X86_)
     306                 :            :     uint8_t inst[15]; // max length of x86 instruction
     307                 :          0 :     size_t len = jl_safe_read_mem(pc, (char*)inst, sizeof(inst));
     308                 :            :     // ud2
     309   [ #  #  #  #  :          0 :     if (len >= 2 && inst[0] == 0x0f && inst[1] == 0x0b) {
                   #  # ]
     310                 :          0 :         jl_safe_printf("Unreachable reached at %p\n", (void*)pc);
     311                 :            :     }
     312                 :            :     else {
     313                 :          0 :         jl_safe_printf("Invalid instruction at %p: ", (void*)pc);
     314         [ #  # ]:          0 :         for (int i = 0;i < len;i++) {
     315         [ #  # ]:          0 :             if (i == 0) {
     316                 :          0 :                 jl_safe_printf("0x%02" PRIx8, inst[i]);
     317                 :            :             }
     318                 :            :             else {
     319                 :          0 :                 jl_safe_printf(", 0x%02" PRIx8, inst[i]);
     320                 :            :             }
     321                 :            :         }
     322                 :          0 :         jl_safe_printf("\n");
     323                 :            :     }
     324                 :            : #elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
     325                 :            :     uint32_t inst = 0;
     326                 :            :     size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
     327                 :            :     if (len < 4)
     328                 :            :         jl_safe_printf("Fault when reading instruction: %d bytes read\n", (int)len);
     329                 :            :     if (inst == 0xd4200020) { // brk #0x1
     330                 :            :         // The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
     331                 :            :         jl_safe_printf("Unreachable reached at %p\n", pc);
     332                 :            :     }
     333                 :            :     else {
     334                 :            :         jl_safe_printf("Invalid instruction at %p: 0x%08" PRIx32 "\n", pc, inst);
     335                 :            :     }
     336                 :            : #elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
     337                 :            :     ucontext_t *ctx = (ucontext_t*)_ctx;
     338                 :            :     if (ctx->uc_mcontext.arm_cpsr & (1 << 5)) {
     339                 :            :         // Thumb
     340                 :            :         uint16_t inst[2] = {0, 0};
     341                 :            :         size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
     342                 :            :         if (len < 2)
     343                 :            :             jl_safe_printf("Fault when reading Thumb instruction: %d bytes read\n", (int)len);
     344                 :            :         // LLVM and GCC uses different code for the trap...
     345                 :            :         if (inst[0] == 0xdefe || inst[0] == 0xdeff) {
     346                 :            :             // The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
     347                 :            :             jl_safe_printf("Unreachable reached in Thumb mode at %p: 0x%04" PRIx16 "\n",
     348                 :            :                            (void*)pc, inst[0]);
     349                 :            :         }
     350                 :            :         else {
     351                 :            :             jl_safe_printf("Invalid Thumb instruction at %p: 0x%04" PRIx16 ", 0x%04" PRIx16 "\n",
     352                 :            :                            (void*)pc, inst[0], inst[1]);
     353                 :            :         }
     354                 :            :     }
     355                 :            :     else {
     356                 :            :         uint32_t inst = 0;
     357                 :            :         size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
     358                 :            :         if (len < 4)
     359                 :            :             jl_safe_printf("Fault when reading instruction: %d bytes read\n", (int)len);
     360                 :            :         // LLVM and GCC uses different code for the trap...
     361                 :            :         if (inst == 0xe7ffdefe || inst == 0xe7f000f0) {
     362                 :            :             // The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
     363                 :            :             jl_safe_printf("Unreachable reached in ARM mode at %p: 0x%08" PRIx32 "\n",
     364                 :            :                            (void*)pc, inst);
     365                 :            :         }
     366                 :            :         else {
     367                 :            :             jl_safe_printf("Invalid ARM instruction at %p: 0x%08" PRIx32 "\n", (void*)pc, inst);
     368                 :            :         }
     369                 :            :     }
     370                 :            : #else
     371                 :            :     // TODO for PPC
     372                 :            :     (void)_ctx;
     373                 :            : #endif
     374                 :            : }
     375                 :            : 
     376                 :            : // what to do on a critical error on a thread
     377                 :          0 : void jl_critical_error(int sig, bt_context_t *context, jl_task_t *ct)
     378                 :            : {
     379         [ #  # ]:          0 :     jl_bt_element_t *bt_data = ct ? ct->ptls->bt_data : NULL;
     380         [ #  # ]:          0 :     size_t *bt_size = ct ? &ct->ptls->bt_size : NULL;
     381         [ #  # ]:          0 :     size_t i, n = ct ? *bt_size : 0;
     382         [ #  # ]:          0 :     if (sig) {
     383                 :            :         // kill this task, so that we cannot get back to it accidentally (via an untimely ^C or jlbacktrace in jl_exit)
     384                 :          0 :         jl_set_safe_restore(NULL);
     385         [ #  # ]:          0 :         if (ct) {
     386                 :          0 :             ct->gcstack = NULL;
     387                 :          0 :             ct->eh = NULL;
     388                 :          0 :             ct->excstack = NULL;
     389                 :          0 :             ct->ptls->locks.len = 0;
     390                 :          0 :             ct->ptls->in_pure_callback = 0;
     391                 :          0 :             ct->ptls->in_finalizer = 1;
     392                 :          0 :             ct->world_age = 1;
     393                 :            :         }
     394                 :            : #ifndef _OS_WINDOWS_
     395                 :            :         sigset_t sset;
     396                 :          0 :         sigemptyset(&sset);
     397                 :            :         // n.b. In `abort()`, Apple's libSystem "helpfully" blocks all signals
     398                 :            :         // on all threads but SIGABRT. But we also don't know what the thread
     399                 :            :         // was doing, so unblock all critical signals so that they will crash
     400                 :            :         // hard, and not just get stuck.
     401                 :          0 :         sigaddset(&sset, SIGSEGV);
     402                 :          0 :         sigaddset(&sset, SIGBUS);
     403                 :          0 :         sigaddset(&sset, SIGILL);
     404                 :            :         // also unblock fatal signals now, so we won't get back here twice
     405                 :          0 :         sigaddset(&sset, SIGTERM);
     406                 :          0 :         sigaddset(&sset, SIGABRT);
     407                 :          0 :         sigaddset(&sset, SIGQUIT);
     408                 :            :         // and the original signal is now fatal too, in case it wasn't
     409                 :            :         // something already listed (?)
     410         [ #  # ]:          0 :         if (sig != SIGINT)
     411                 :          0 :             sigaddset(&sset, sig);
     412                 :          0 :         pthread_sigmask(SIG_UNBLOCK, &sset, NULL);
     413                 :            : #endif
     414                 :          0 :         jl_safe_printf("\n[%d] signal (%d): %s\n", getpid(), sig, strsignal(sig));
     415                 :            :     }
     416                 :          0 :     jl_safe_printf("in expression starting at %s:%d\n", jl_filename, jl_lineno);
     417   [ #  #  #  # ]:          0 :     if (context && ct) {
     418                 :            :         // Must avoid extended backtrace frames here unless we're sure bt_data
     419                 :            :         // is properly rooted.
     420                 :          0 :         *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL);
     421                 :            :     }
     422         [ #  # ]:          0 :     for (i = 0; i < n; i += jl_bt_entry_size(bt_data + i)) {
     423                 :          0 :         jl_print_bt_entry_codeloc(bt_data + i);
     424                 :            :     }
     425                 :          0 :     jl_gc_debug_print_status();
     426                 :          0 :     jl_gc_debug_critical_error();
     427                 :          0 : }
     428                 :            : 
     429                 :            : ///////////////////////
     430                 :            : // Utility functions //
     431                 :            : ///////////////////////
     432                 :         10 : JL_DLLEXPORT int jl_profile_init(size_t maxsize, uint64_t delay_nsec)
     433                 :            : {
     434                 :         10 :     bt_size_max = maxsize;
     435                 :         10 :     nsecprof = delay_nsec;
     436         [ -  + ]:         10 :     if (bt_data_prof != NULL)
     437                 :          0 :         free((void*)bt_data_prof);
     438                 :         10 :     bt_data_prof = (jl_bt_element_t*) calloc(maxsize, sizeof(jl_bt_element_t));
     439   [ -  +  -  - ]:         10 :     if (bt_data_prof == NULL && maxsize > 0)
     440                 :          0 :         return -1;
     441                 :         10 :     bt_size_cur = 0;
     442                 :         10 :     return 0;
     443                 :            : }
     444                 :            : 
     445                 :          2 : JL_DLLEXPORT uint8_t *jl_profile_get_data(void)
     446                 :            : {
     447                 :          2 :     return (uint8_t*) bt_data_prof;
     448                 :            : }
     449                 :            : 
     450                 :      17472 : JL_DLLEXPORT size_t jl_profile_len_data(void)
     451                 :            : {
     452                 :      17472 :     return bt_size_cur;
     453                 :            : }
     454                 :            : 
     455                 :          2 : JL_DLLEXPORT size_t jl_profile_maxlen_data(void)
     456                 :            : {
     457                 :          2 :     return bt_size_max;
     458                 :            : }
     459                 :            : 
     460                 :          0 : JL_DLLEXPORT uint64_t jl_profile_delay_nsec(void)
     461                 :            : {
     462                 :          0 :     return nsecprof;
     463                 :            : }
     464                 :            : 
     465                 :          2 : JL_DLLEXPORT void jl_profile_clear_data(void)
     466                 :            : {
     467                 :          2 :     bt_size_cur = 0;
     468                 :          2 : }
     469                 :            : 
     470                 :          0 : JL_DLLEXPORT int jl_profile_is_running(void)
     471                 :            : {
     472                 :          0 :     return running;
     473                 :            : }
     474                 :            : 
     475                 :            : #ifdef __cplusplus
     476                 :            : }
     477                 :            : #endif

Generated by: LCOV version 1.14