mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 20:16:03 +01:00
Restore fixupBoehmStackPointer
This was removed in https://github.com/NixOS/nix/pull/11152. However, we need it for the multi-threaded evaluator, because otherwise Boehm GC will crash while scanning the thread stack: #0 GC_push_all_eager (bottom=<optimized out>, top=<optimized out>) at extra/../mark.c:1488 #1 0x00007ffff74691d5 in GC_push_all_stack_sections (lo=<optimized out>, hi=<optimized out>, traced_stack_sect=0x0) at extra/../mark_rts.c:704 #2 GC_push_all_stacks () at extra/../pthread_stop_world.c:876 #3 GC_default_push_other_roots () at extra/../os_dep.c:2893 #4 0x00007ffff746235c in GC_mark_some (cold_gc_frame=0x7ffee8ecaa50 "`\304G\367\377\177") at extra/../mark.c:374 #5 0x00007ffff7465a8d in GC_stopped_mark (stop_func=stop_func@entry=0x7ffff7453c80 <GC_never_stop_func>) at extra/../alloc.c:875 #6 0x00007ffff7466724 in GC_try_to_collect_inner (stop_func=0x7ffff7453c80 <GC_never_stop_func>) at extra/../alloc.c:624 #7 0x00007ffff7466a22 in GC_collect_or_expand (needed_blocks=needed_blocks@entry=1, ignore_off_page=ignore_off_page@entry=0, retry=retry@entry=0) at extra/../alloc.c:1688 #8 0x00007ffff746878f in GC_allocobj (gran=<optimized out>, kind=<optimized out>) at extra/../alloc.c:1798 #9 GC_generic_malloc_inner (lb=<optimized out>, k=k@entry=1) at extra/../malloc.c:193 #10 0x00007ffff746cd40 in GC_generic_malloc_many (lb=<optimized out>, k=<optimized out>, result=<optimized out>) at extra/../mallocx.c:477 #11 0x00007ffff746cf35 in GC_malloc_kind (bytes=120, kind=1) at extra/../thread_local_alloc.c:187 #12 0x00007ffff796ede5 in nix::allocBytes (n=<optimized out>, n=<optimized out>) at ../src/libexpr/include/nix/expr/eval-inline.hh:19 This is because it will use the stack pointer of the coroutine, so it will scan a region of memory that doesn't exist, e.g. Stack for thread 0x7ffea4ff96c0 is [0x7ffe80197af0w,0x7ffea4ffa000) (where 0x7ffe80197af0w is the sp of the coroutine and 0x7ffea4ffa000 is the base of the thread stack). We don't scan coroutine stacks, because currently they don't have GC roots (there is no evaluation happening in coroutines). So there is currently no need to restore the other parts of the original patch, such as BoehmGCStackAllocator.
This commit is contained in:
parent
c4c3203b7b
commit
3ba103865d
1 changed files with 64 additions and 0 deletions
|
|
@ -35,6 +35,67 @@ static void * oomHandler(size_t requested)
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a thread goes into a coroutine, we lose its original sp until
|
||||||
|
* control flow returns to the thread. This causes Boehm GC to crash
|
||||||
|
* since it will scan memory between the coroutine's sp and the
|
||||||
|
* original stack base of the thread. Therefore, we detect when the
|
||||||
|
* current sp is outside of the original thread stack and push the
|
||||||
|
* entire thread stack instead, as an approximation.
|
||||||
|
*
|
||||||
|
* This is not optimal, because it causes the stack below sp to be
|
||||||
|
* scanned. However, we usually we don't have active coroutines during
|
||||||
|
* evaluation, so this is acceptable.
|
||||||
|
*
|
||||||
|
* Note that we don't scan coroutine stacks. It's currently assumed
|
||||||
|
* that we don't have GC roots in coroutines.
|
||||||
|
*/
|
||||||
|
void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
|
||||||
|
{
|
||||||
|
void *& sp = *sp_ptr;
|
||||||
|
auto pthread_id = reinterpret_cast<pthread_t>(_pthread_id);
|
||||||
|
size_t osStackSize;
|
||||||
|
// The low address of the stack, which grows down.
|
||||||
|
void * osStackLimit;
|
||||||
|
|
||||||
|
# ifdef __APPLE__
|
||||||
|
osStackSize = pthread_get_stacksize_np(pthread_id);
|
||||||
|
osStackLimit = pthread_get_stackaddr_np(pthread_id);
|
||||||
|
# else
|
||||||
|
pthread_attr_t pattr;
|
||||||
|
if (pthread_attr_init(&pattr)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
|
||||||
|
}
|
||||||
|
# ifdef HAVE_PTHREAD_GETATTR_NP
|
||||||
|
if (pthread_getattr_np(pthread_id, &pattr)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
|
||||||
|
}
|
||||||
|
# elif HAVE_PTHREAD_ATTR_GET_NP
|
||||||
|
if (!pthread_attr_init(&pattr)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
|
||||||
|
}
|
||||||
|
if (!pthread_attr_get_np(pthread_id, &pattr)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_attr_get_np failed");
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
# error "Need one of `pthread_attr_get_np` or `pthread_getattr_np`"
|
||||||
|
# endif
|
||||||
|
if (pthread_attr_getstack(&pattr, &osStackLimit, &osStackSize)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
|
||||||
|
}
|
||||||
|
if (pthread_attr_destroy(&pattr)) {
|
||||||
|
throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
void * osStackBase = (char *) osStackLimit + osStackSize;
|
||||||
|
// NOTE: We assume the stack grows down, as it does on all architectures we support.
|
||||||
|
// Architectures that grow the stack up are rare.
|
||||||
|
if (sp >= osStackBase || sp < osStackLimit) { // sp is outside the os stack
|
||||||
|
sp = osStackLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void initGCReal()
|
static inline void initGCReal()
|
||||||
{
|
{
|
||||||
/* Initialise the Boehm garbage collector. */
|
/* Initialise the Boehm garbage collector. */
|
||||||
|
|
@ -62,6 +123,9 @@ static inline void initGCReal()
|
||||||
|
|
||||||
GC_set_oom_fn(oomHandler);
|
GC_set_oom_fn(oomHandler);
|
||||||
|
|
||||||
|
GC_set_sp_corrector(&fixupBoehmStackPointer);
|
||||||
|
assert(GC_get_sp_corrector());
|
||||||
|
|
||||||
/* Set the initial heap size to something fairly big (25% of
|
/* Set the initial heap size to something fairly big (25% of
|
||||||
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
||||||
we don't need to garbage collect at all. (Collection has a
|
we don't need to garbage collect at all. (Collection has a
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue