mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-28 05:50:30 +02:00
Add platform abstraction
This will allow us to iterate conservative roots from stacks and static data segments.
This commit is contained in:
parent
05d2c95950
commit
a5b1a66d21
3 changed files with 126 additions and 1 deletions
6
Makefile
6
Makefile
|
@ -6,11 +6,15 @@ CFLAGS=-Wall -O2 -g -flto -fno-strict-aliasing -fvisibility=hidden -Wno-unused -
|
||||||
INCLUDES=-I.
|
INCLUDES=-I.
|
||||||
LDFLAGS=-lpthread -flto
|
LDFLAGS=-lpthread -flto
|
||||||
COMPILE=$(CC) $(CFLAGS) $(INCLUDES)
|
COMPILE=$(CC) $(CFLAGS) $(INCLUDES)
|
||||||
|
PLATFORM=gnu-linux
|
||||||
|
|
||||||
ALL_TESTS=$(foreach COLLECTOR,$(COLLECTORS),$(addprefix $(COLLECTOR)-,$(TESTS)))
|
ALL_TESTS=$(foreach COLLECTOR,$(COLLECTORS),$(addprefix $(COLLECTOR)-,$(TESTS)))
|
||||||
|
|
||||||
all: $(ALL_TESTS)
|
all: $(ALL_TESTS)
|
||||||
|
|
||||||
|
gc-platform.o: gc-platform.h gc-platform-$(PLATFORM).c gc-visibility.h
|
||||||
|
$(COMPILE) -o $@ -c gc-platform-$(PLATFORM).c
|
||||||
|
|
||||||
bdw-%-gc.o: semi.c %-embedder.h %.c
|
bdw-%-gc.o: semi.c %-embedder.h %.c
|
||||||
$(COMPILE) `pkg-config --cflags bdw-gc` -include $*-embedder.h -o $@ -c bdw.c
|
$(COMPILE) `pkg-config --cflags bdw-gc` -include $*-embedder.h -o $@ -c bdw.c
|
||||||
bdw-%.o: semi.c %.c
|
bdw-%.o: semi.c %.c
|
||||||
|
@ -43,7 +47,7 @@ parallel-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.
|
||||||
parallel-generational-whippet-%.o: whippet.c %.c
|
parallel-generational-whippet-%.o: whippet.c %.c
|
||||||
$(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c
|
$(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE=1 -include whippet-attrs.h -o $@ -c $*.c
|
||||||
|
|
||||||
%: %.o %-gc.o
|
%: %.o %-gc.o gc-platform.o
|
||||||
$(CC) $(LDFLAGS) $($*_LDFLAGS) -o $@ $^
|
$(CC) $(LDFLAGS) $($*_LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
check: $(addprefix test-$(TARGET),$(TARGETS))
|
check: $(addprefix test-$(TARGET),$(TARGETS))
|
||||||
|
|
101
gc-platform-gnu-linux.c
Normal file
101
gc-platform-gnu-linux.c
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// For pthread_getattr_np.
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <errno.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define GC_IMPL 1
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "gc-assert.h"
|
||||||
|
#include "gc-inline.h"
|
||||||
|
//#include "gc-stack.h"
|
||||||
|
|
||||||
|
void gc_platform_init(void) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintptr_t fallback_current_thread_stack_base(void) GC_NEVER_INLINE;
|
||||||
|
static uintptr_t fallback_current_thread_stack_base(void) {
|
||||||
|
// Sloppily assume that there are very few frames between us and the
|
||||||
|
// thread entry or main function, and that therefore we haven't
|
||||||
|
// consumed more than a page of stack; we can then just round up the
|
||||||
|
// stack pointer to the page boundary.
|
||||||
|
fprintf(stderr,
|
||||||
|
"Using fallback strategy to capture stack base for thread %p.\n",
|
||||||
|
(void*)pthread_self());
|
||||||
|
int local;
|
||||||
|
uintptr_t hot = (uintptr_t)&local;
|
||||||
|
size_t page_size = getpagesize();
|
||||||
|
return (hot + page_size) & ~(page_size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t gc_platform_current_thread_stack_base(void) {
|
||||||
|
pthread_t me = pthread_self();
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int err = pthread_getattr_np(me, &attr);
|
||||||
|
if (err) {
|
||||||
|
errno = err;
|
||||||
|
// This case can occur for the main thread when running in a
|
||||||
|
// filesystem without /proc/stat.
|
||||||
|
perror("Failed to capture stack base via pthread_getattr_np");
|
||||||
|
return fallback_current_thread_stack_base();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *stack_low_addr;
|
||||||
|
size_t stack_size;
|
||||||
|
err = pthread_attr_getstack(&attr, &stack_low_addr, &stack_size);
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
if (err) {
|
||||||
|
// Should never occur.
|
||||||
|
errno = err;
|
||||||
|
perror("pthread_attr_getstack");
|
||||||
|
return fallback_current_thread_stack_base();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uintptr_t)stack_low_addr + stack_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct visit_data {
|
||||||
|
void (*f)(uintptr_t start, uintptr_t end, void *data);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int visit_roots(struct dl_phdr_info *info, size_t size, void *data) {
|
||||||
|
struct visit_data *visit_data = data;
|
||||||
|
uintptr_t object_addr = info->dlpi_addr;
|
||||||
|
const char *object_name = info->dlpi_name;
|
||||||
|
const ElfW(Phdr) *program_headers = info->dlpi_phdr;
|
||||||
|
size_t program_headers_count = info->dlpi_phnum;
|
||||||
|
|
||||||
|
// From the loader's perspective, an ELF image is broken up into
|
||||||
|
// "segments", each of which is described by a "program header".
|
||||||
|
// Treat all writable data segments as potential edges into the
|
||||||
|
// GC-managed heap.
|
||||||
|
//
|
||||||
|
// Note that there are some RELRO segments which are initially
|
||||||
|
// writable but then remapped read-only. BDW-GC will exclude these,
|
||||||
|
// but we just punt for the time being and treat them as roots
|
||||||
|
for (size_t i = 0; i < program_headers_count; i++) {
|
||||||
|
const ElfW(Phdr) *p = &program_headers[i];
|
||||||
|
if (p->p_type == PT_LOAD && (p->p_flags & PF_W)) {
|
||||||
|
uintptr_t start = p->p_vaddr + object_addr;
|
||||||
|
uintptr_t end = start + p->p_memsz;
|
||||||
|
DEBUG("found roots for '%s': [%p,%p)\n", object_name,
|
||||||
|
(void*)start, (void*)end);
|
||||||
|
visit_data->f(start, end, visit_data->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gc_platform_visit_global_conservative_roots(void (*f)(uintptr_t start,
|
||||||
|
uintptr_t end,
|
||||||
|
void *data),
|
||||||
|
void *data) {
|
||||||
|
struct visit_data visit_data = { f, data };
|
||||||
|
dl_iterate_phdr(visit_roots, &visit_data);
|
||||||
|
}
|
20
gc-platform.h
Normal file
20
gc-platform.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef GC_PLATFORM_H
|
||||||
|
#define GC_PLATFORM_H
|
||||||
|
|
||||||
|
#ifndef GC_IMPL
|
||||||
|
#error internal header file, not part of API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "gc-visibility.h"
|
||||||
|
|
||||||
|
GC_INTERNAL void gc_platform_init(void);
|
||||||
|
GC_INTERNAL uintptr_t gc_platform_current_thread_stack_base(void);
|
||||||
|
GC_INTERNAL
|
||||||
|
void gc_platform_visit_global_conservative_roots(void (*f)(uintptr_t start,
|
||||||
|
uintptr_t end,
|
||||||
|
void *data),
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
#endif // GC_PLATFORM_H
|
Loading…
Add table
Add a link
Reference in a new issue