Skip to content

Commit

Permalink
coroutines: fix segfaults with GC (part 1) (#20549)
Browse files Browse the repository at this point in the history
  • Loading branch information
joe-conigliaro committed Jan 27, 2024
1 parent 5f7e6ff commit f79dd79
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 25 deletions.
23 changes: 19 additions & 4 deletions thirdparty/photon/photonwrapper.h
Expand Up @@ -19,24 +19,39 @@
#include <iostream>

extern "C" {
// using namespace photon;

// WorkPool* work_pool;
// WorkPool* new_photon_work_pool();
photon::WorkPool* work_pool;

// using namespace photon;
// typedef WorkPool PhotonWorkPool;
// typedef photon::WorkPool PhotonWorkPool1;
#else
#endif

// using namespace photon;
// typedef WorkPool PhotonWorkPool;
// typedef photon::WorkPool PhotonWorkPool;
// typedef WorkPool PhotonWorkPool;
// typedef PhotonWorkPool1 PhotonWorkPool;
// PhotonWorkPool* new_photon_work_pool();
void* new_photon_work_pool(size_t);
// void delete_photon_work_pool(void*);
void delete_photon_work_pool();
// custom v functions
void init_photon_work_pool(size_t);
// void photon_thread_migrate();
// void photon_thread_migrate(void*);
void photon_thread_create_and_migrate_to_work_pool(void* (* f)(void*), void* arg);
// void photon_thread_create_and_migrate_to_work_pool(void*, void* (* f)(void*), void* arg);
// direct wrappers to photon functions
int photon_init_default();
void photon_thread_create(void* (* f)(void*), void* arg);
void photon_sleep_s(int n);
void photon_sleep_ms(int n);

// void* default_photon_thread_stack_alloc(void*, size_t size);
// void default_photon_thread_stack_dealloc(void*, void* ptr, size_t size);
void* default_photon_thread_stack_alloc(void*, size_t size);
void default_photon_thread_stack_dealloc(void*, void* ptr, size_t size);
void set_photon_thread_stack_allocator(
void* (*alloc_func)(void*, size_t),
void (*dealloc_func)(void*, void*, size_t)
Expand Down
11 changes: 11 additions & 0 deletions vlib/builtin/builtin_d_gcboehm.c.v
Expand Up @@ -143,5 +143,16 @@ pub fn gc_check_leaks() {
fn C.GC_get_heap_usage_safe(pheap_size &usize, pfree_bytes &usize, punmapped_bytes &usize, pbytes_since_gc &usize, ptotal_bytes &usize)
fn C.GC_get_memory_use() usize

pub struct C.GC_stack_base {
mem_base voidptr
// reg_base voidptr
}

// pub struct C.GC_stack_base{}

fn C.GC_get_stack_base(voidptr)
fn C.GC_register_my_thread(voidptr) int
fn C.GC_unregister_my_thread() int

fn C.GC_add_roots(voidptr, voidptr)
fn C.GC_remove_roots(voidptr, voidptr)
72 changes: 52 additions & 20 deletions vlib/coroutines/coroutines.c.v
Expand Up @@ -11,45 +11,77 @@ import time

#include "photonwrapper.h"

// struct C.WorkPool {}
// fn C.new_photon_work_pool) C.WorkPool
fn C.set_photon_thread_stack_allocator(fn (voidptr, int) voidptr, fn (voidptr, voidptr, int))
fn C.default_photon_thread_stack_alloc(voidptr, int) voidptr
fn C.default_photon_thread_stack_dealloc(voidptr, voidptr, int)
fn C.new_photon_work_pool(int) voidptr
fn C.delete_photon_work_pool()
fn C.init_photon_work_pool(int)

// fn C.photon_thread_create_and_migrate_to_work_pool(f voidptr, arg voidptr)
fn C.init_photon_manual(int, fn ())
fn C.init_photon_manual2(fn (), fn ())
fn C.photon_thread_create_and_migrate_to_work_pool(f voidptr, arg voidptr)
fn C.photon_thread_create(f voidptr, arg voidptr)
fn C.photon_thread_migrate()

// fn C.photon_thread_migrate(work_pool voidptr)
fn C.photon_init_default() int

fn C.photon_sleep_s(n int)
fn C.photon_sleep_ms(n int)
fn C.set_photon_thread_stack_allocator(fn (voidptr, int) voidptr, fn (voidptr, voidptr, int))

// sleep is coroutine-safe version of time.sleep()
pub fn sleep(duration time.Duration) {
C.photon_sleep_ms(duration.milliseconds())
}

fn init() {
alloc := fn (_ voidptr, stack_size int) voidptr {
unsafe {
stack_ptr := malloc(stack_size)
$if gcboehm ? {
C.GC_add_roots(stack_ptr, charptr(stack_ptr) + stack_size)
}
return stack_ptr
fn alloc(_ voidptr, stack_size int) voidptr {
// println('## alloc called')
unsafe {
// thread_id := C.pthread_self()
// println('## Thread ID: $thread_id')

// $if gcboehm ? {
// mut sb := C.GC_stack_base{}
// C.GC_get_stack_base(&sb)
// C.GC_register_my_thread(&sb)
// // res = C.GC_register_my_thread(&sb)
// // println('## RES: $res')
// }

// NOTE: when using malloc (GC_MALLOC) we get a segfault
// when migrating from a new thread to a work pool thread
// stack_ptr := malloc(stack_size)
// stack_ptr := C.malloc(stack_size)
stack_ptr := C.default_photon_thread_stack_alloc(nil, stack_size)

$if gcboehm ? {
C.GC_add_roots(stack_ptr, charptr(stack_ptr) + stack_size)
}

return stack_ptr
}
dealloc := fn (_ voidptr, stack_ptr voidptr, stack_size int) {
unsafe {
$if gcboehm ? {
C.GC_remove_roots(stack_ptr, charptr(stack_ptr) + stack_size)
}
free(stack_ptr)
}

fn dealloc(_ voidptr, stack_ptr voidptr, stack_size int) {
// println('## dealloc called')
unsafe {
$if gcboehm ? {
// C.GC_unregister_my_thread()
C.GC_remove_roots(stack_ptr, charptr(stack_ptr) + stack_size)
}
// free(stack_ptr)
C.default_photon_thread_stack_dealloc(nil, stack_ptr, stack_size)
}
}

fn init() {
C.set_photon_thread_stack_allocator(alloc, dealloc)
ret := C.photon_init_default()
if util.nr_jobs > 0 {

if util.nr_jobs >= 1 {
C.init_photon_work_pool(util.nr_jobs)
}

if ret < 0 {
panic('failed to initialize coroutines via photon (ret=${ret})')
}
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/c/cgen.v
Expand Up @@ -6173,6 +6173,9 @@ fn (mut g Gen) write_init_function() {
for x in cleaning_up_array.reverse() {
g.writeln(x)
}
if g.pref.use_coroutines {
g.writeln('\tdelete_photon_work_pool();')
}
g.writeln('}')
if g.pref.printfn_list.len > 0 && '_vcleanup' in g.pref.printfn_list {
println(g.out.after(fn_vcleanup_start_pos))
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/gen/c/cmain.v
Expand Up @@ -110,7 +110,10 @@ fn (mut g Gen) gen_c_main_header() {
g.writeln('\tGC_set_find_leak(1);')
}
g.writeln('\tGC_set_pages_executable(0);')
// NOTE: required when using GC_MALLOC & GC_register_my_thread
// g.writeln('\tGC_allow_register_threads();')
g.writeln('\tGC_INIT();')

if g.pref.gc_mode in [.boehm_incr, .boehm_incr_opt] {
g.writeln('\tGC_enable_incremental();')
}
Expand Down Expand Up @@ -242,6 +245,8 @@ pub fn (mut g Gen) gen_c_main_for_tests() {
g.writeln('\tGC_set_find_leak(1);')
}
g.writeln('\tGC_set_pages_executable(0);')
// NOTE: required when using GC_MALLOC & GC_register_my_thread
// g.writeln('\tGC_allow_register_threads();')
g.writeln('\tGC_INIT();')
if g.pref.gc_mode in [.boehm_incr, .boehm_incr_opt] {
g.writeln('\tGC_enable_incremental();')
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/spawn_and_go.v
Expand Up @@ -162,7 +162,7 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
}
}
} else if is_go {
if util.nr_jobs > 0 {
if util.nr_jobs > 1 {
g.writeln('photon_thread_create_and_migrate_to_work_pool((void*)${wrapper_fn_name}, &${arg_tmp_var});')
} else {
g.writeln('photon_thread_create((void*)${wrapper_fn_name}, &${arg_tmp_var});')
Expand Down

0 comments on commit f79dd79

Please sign in to comment.