Skip to content

Commit 357fff4

Browse files
authored
New computation for signal stack sizes (oxcaml#3986)
1 parent e06264f commit 357fff4

File tree

4 files changed

+52
-15
lines changed

4 files changed

+52
-15
lines changed

otherlibs/systhreads/st_stubs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct caml_thread_struct {
134134
char * async_exn_handler; /* saved value of Caml_state->async_exn_handler */
135135
memprof_thread_t memprof; /* memprof's internal thread data structure */
136136
void * signal_stack; /* this thread's signal stack */
137+
size_t signal_stack_size; /* size of this thread's signal stack in bytes */
137138
int is_main; /* whether this is the main thread of its domain */
138139

139140
#ifndef NATIVE_CODE
@@ -782,7 +783,7 @@ static void thread_detach_from_runtime(void)
782783
caml_threadstatus_terminate(Terminated(th->descr));
783784
/* Remove signal stack */
784785
CAMLassert(th->signal_stack != NULL);
785-
caml_free_signal_stack(th->signal_stack);
786+
caml_free_signal_stack(th->signal_stack, th->signal_stack_size);
786787
/* The following also sets Active_thread to a sane value in case the
787788
backup thread does a GC before the domain lock is acquired
788789
again. It also removes the thread from memprof. */
@@ -798,7 +799,7 @@ static void thread_init_current(caml_thread_t th)
798799
{
799800
st_tls_set(caml_thread_key, th);
800801
restore_runtime_state(th);
801-
th->signal_stack = caml_init_signal_stack();
802+
th->signal_stack = caml_init_signal_stack(&th->signal_stack_size);
802803
}
803804

804805
/* Create a thread */

runtime/caml/signals.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ value caml_process_pending_actions_with_root_exn (value extra_root);
7878
void caml_init_signal_handling(void);
7979
void caml_init_signals(void);
8080
void caml_terminate_signals(void);
81-
CAMLextern void * caml_init_signal_stack(void);
82-
CAMLextern void caml_free_signal_stack(void *);
81+
CAMLextern void * caml_init_signal_stack(size_t* returned_signal_stack_size);
82+
CAMLextern void caml_free_signal_stack(void *, size_t signal_stack_size);
8383

8484
/* These hooks are not modified after other threads are spawned. */
8585
CAMLextern void (*caml_enter_blocking_section_hook)(void);

runtime/domain.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,9 +1241,11 @@ static void* domain_thread_func(void* v)
12411241
struct domain_ml_values *ml_values = p->ml_values;
12421242

12431243
#ifndef _WIN32
1244-
void * signal_stack = caml_init_signal_stack();
1244+
errno = 0;
1245+
size_t signal_stack_size = 0;
1246+
void * signal_stack = caml_init_signal_stack(&signal_stack_size);
12451247
if (signal_stack == NULL) {
1246-
caml_fatal_error("Failed to create domain: signal stack");
1248+
caml_fatal_error("Failed to create domain: signal stack (errno %d)", errno);
12471249
}
12481250
#endif
12491251

@@ -1303,7 +1305,7 @@ static void* domain_thread_func(void* v)
13031305
free_domain_ml_values(ml_values);
13041306
}
13051307
#ifndef _WIN32
1306-
caml_free_signal_stack(signal_stack);
1308+
caml_free_signal_stack(signal_stack, signal_stack_size);
13071309
#endif
13081310
return 0;
13091311
}

runtime/signals.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
#include "caml/memprof.h"
3838
#include "caml/finalise.h"
3939
#include "caml/printexc.h"
40+
#ifdef __linux__
41+
#include <sys/auxv.h>
42+
#include <linux/auxvec.h>
43+
#endif
4044

4145
/* The set of pending signals (received but not yet processed).
4246
It is represented as a bit vector.
@@ -584,12 +588,37 @@ CAMLexport int caml_rev_convert_signal_number(int signo)
584588
return signo;
585589
}
586590

587-
void * caml_init_signal_stack(void)
591+
static size_t max_size_t(size_t a, size_t b)
592+
{
593+
return (a > b) ? a : b;
594+
}
595+
596+
void * caml_init_signal_stack(size_t* signal_stack_size)
588597
{
589598
#ifdef POSIX_SIGNALS
590599
stack_t stk;
591600
stk.ss_flags = 0;
601+
602+
#ifdef __linux__
603+
/* On some systems, e.g. when AMX has been enabled on certain glibc versions,
604+
the dynamic value of MINSIGSTKSZ might be larger than SIGSTKSZ and/or any
605+
compile-time MINSIGSTKSZ. As such we compute our own SIGSTKSZ. The
606+
"4 * " scaling factor matches current glibc behaviour.
607+
608+
If the values the system has provided look sensible, however, we
609+
trust SIGSTKSZ. */
610+
size_t at_minsigstksz = getauxval(AT_MINSIGSTKSZ);
611+
612+
if (at_minsigstksz <= MINSIGSTKSZ && MINSIGSTKSZ <= SIGSTKSZ)
613+
stk.ss_size = SIGSTKSZ;
614+
else
615+
stk.ss_size = max_size_t(
616+
SIGSTKSZ, 4 * max_size_t(MINSIGSTKSZ, at_minsigstksz));
617+
#else
618+
/* Preserve existing runtime5 behaviour for now. */
592619
stk.ss_size = SIGSTKSZ;
620+
#endif
621+
593622
/* The memory used for the alternate signal stack must not free'd before
594623
calling sigaltstack with SS_DISABLE. malloc/mmap is therefore used rather
595624
than caml_stat_alloc_noexc so that if a shutdown path erroneously fails
@@ -602,7 +631,7 @@ void * caml_init_signal_stack(void)
602631
if (stk.ss_sp == MAP_FAILED)
603632
return NULL;
604633
if (sigaltstack(&stk, NULL) < 0) {
605-
munmap(stk.ss_sp, SIGSTKSZ);
634+
munmap(stk.ss_sp, stk.ss_size);
606635
return NULL;
607636
}
608637
#else
@@ -614,19 +643,21 @@ void * caml_init_signal_stack(void)
614643
return NULL;
615644
}
616645
#endif /* USE_MMAP_MAP_STACK */
646+
*signal_stack_size = stk.ss_size;
617647
return stk.ss_sp;
618648
#else
649+
*signal_stack_size = 0;
619650
return NULL;
620651
#endif /* POSIX_SIGNALS */
621652
}
622653

623-
void caml_free_signal_stack(void * signal_stack)
654+
void caml_free_signal_stack(void * signal_stack, size_t signal_stack_size)
624655
{
625656
#ifdef POSIX_SIGNALS
626657
stack_t stk, disable;
627658
disable.ss_flags = SS_DISABLE;
628659
disable.ss_sp = NULL; /* not required but avoids a valgrind false alarm */
629-
disable.ss_size = SIGSTKSZ; /* macOS wants a valid size here */
660+
disable.ss_size = signal_stack_size; /* macOS wants a valid size here */
630661
if (sigaltstack(&disable, &stk) < 0) {
631662
caml_fatal_error("Failed to reset signal stack (err %d)", errno);
632663
}
@@ -638,7 +669,7 @@ void caml_free_signal_stack(void * signal_stack)
638669
/* Memory was allocated with malloc/mmap directly (see
639670
caml_init_signal_stack) */
640671
#ifdef USE_MMAP_MAP_STACK
641-
munmap(signal_stack, SIGSTKSZ);
672+
munmap(signal_stack, signal_stack_size);
642673
#else
643674
free(signal_stack);
644675
#endif /* USE_MMAP_MAP_STACK */
@@ -648,15 +679,18 @@ void caml_free_signal_stack(void * signal_stack)
648679
#ifdef POSIX_SIGNALS
649680
/* This is the alternate signal stack block for domain 0 */
650681
static void * caml_signal_stack_0 = NULL;
682+
static size_t caml_signal_stack_0_size = 0;
651683
#endif
652684

653685
void caml_init_signals(void)
654686
{
655687
/* Set up alternate signal stack for domain 0 */
656688
#ifdef POSIX_SIGNALS
657-
caml_signal_stack_0 = caml_init_signal_stack();
689+
errno = 0;
690+
caml_signal_stack_0 = caml_init_signal_stack(&caml_signal_stack_0_size);
658691
if (caml_signal_stack_0 == NULL) {
659-
caml_fatal_error("Failed to allocate signal stack for domain 0");
692+
caml_fatal_error("Failed to allocate signal stack for domain 0 (errno %d)",
693+
errno);
660694
}
661695

662696
/* gprof installs a signal handler for SIGPROF.
@@ -679,7 +713,7 @@ void caml_init_signals(void)
679713
void caml_terminate_signals(void)
680714
{
681715
#ifdef POSIX_SIGNALS
682-
caml_free_signal_stack(caml_signal_stack_0);
716+
caml_free_signal_stack(caml_signal_stack_0, caml_signal_stack_0_size);
683717
caml_signal_stack_0 = NULL;
684718
#endif
685719
}

0 commit comments

Comments
 (0)