v / vlib / coroutines / coroutines.c.v
118 lines · 101 sloc · 3.33 KB · a87a4d73b9ab25cfff0822f4e94cf2a2d9e64323
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module coroutines
5
6import v.util
7import time
8
9#flag -I @VEXEROOT/thirdparty/photon
10#flag @VEXEROOT/thirdparty/photon/photonwrapper.so
11#include "photonwrapper.h"
12
13$if windows {
14 #include "processthreadsapi.h"
15} $else {
16 #include <pthread.h>
17}
18#flag -I @VEXEROOT/vlib/coroutines
19#include "sp_corrector.c"
20
21fn C.set_photon_thread_stack_allocator(fn (voidptr, int) voidptr, fn (voidptr, voidptr, int))
22
23// fn C.default_photon_thread_stack_alloc(voidptr, int) voidptr
24// fn C.default_photon_thread_stack_dealloc(voidptr, voidptr, int)
25fn C.new_photon_work_pool(i32) voidptr
26fn C.delete_photon_work_pool()
27fn C.init_photon_work_pool(i32)
28fn C.photon_set_log_output_stdout()
29fn C.photon_set_log_output_stderr()
30fn C.photon_set_log_output_null()
31fn C.photon_join_current_thread_into_workpool() i32
32fn C.photon_thread_create_and_migrate_to_work_pool(f voidptr, arg voidptr)
33fn C.photon_thread_create(f voidptr, arg voidptr, stack_size u64)
34fn C.photon_thread_migrate()
35
36// fn C.photon_thread_migrate(work_pool voidptr)
37fn C.photon_init_default() i32
38fn C.photon_sleep_s(n i32)
39fn C.photon_sleep_ms(n i32)
40
41fn C.sp_corrector(voidptr, voidptr)
42
43// sleep is coroutine-safe version of time.sleep()
44pub fn sleep(duration time.Duration) {
45 C.photon_sleep_ms(duration.milliseconds())
46}
47
48fn alloc(_ voidptr, stack_size int) voidptr {
49 unsafe {
50 stack_ptr := malloc(stack_size)
51
52 $if gcboehm ? {
53 // TODO: this wont work if a coroutine gets moved to a different
54 // thread, so we are using `C.GC_set_sp_corrector` with our own
55 // corrector function which seems to be the best solution for now.
56 // It would probably be more performant if we could hook into photon's context
57 // switching code (currently not possible) or we write our own implementation.
58 // TODO: update - I'm not sure if what I wrote above is correct. test
59 // C.GC_set_stackbottom(0, stack_ptr)
60
61 C.GC_add_roots(stack_ptr, charptr(stack_ptr) + stack_size)
62 }
63
64 return stack_ptr
65 }
66}
67
68fn dealloc(_ voidptr, stack_ptr voidptr, stack_size int) {
69 unsafe {
70 $if gcboehm ? {
71 C.GC_remove_roots(stack_ptr, charptr(stack_ptr) + stack_size)
72 }
73 free(stack_ptr)
74 }
75}
76
77fn init_photon_vcpu() {
78 C.photon_init_default()
79 $if gcboehm ? {
80 mut sb := C.GC_stack_base{}
81 C.GC_get_stack_base(&sb)
82 C.GC_register_my_thread(&sb)
83 }
84 C.photon_join_current_thread_into_workpool()
85 $if gcboehm ? {
86 C.GC_unregister_my_thread()
87 }
88}
89
90fn init() {
91 $if gcboehm ? {
92 // NOTE `sp_corrector` only works for platforms with the stack growing down
93 // MacOs, Win32 and Linux always have stack growing down.
94 // A proper solution is planned (hopefully) for boehm v8.4.0.
95 C.GC_set_sp_corrector(C.sp_corrector)
96 if C.GC_get_sp_corrector() == unsafe { nil } {
97 panic('stack pointer correction unsupported')
98 }
99 }
100 C.photon_set_log_output_null()
101 C.set_photon_thread_stack_allocator(alloc, dealloc)
102 ret := C.photon_init_default()
103
104 if util.nr_jobs >= 1 {
105 // automatic
106 // C.init_photon_work_pool(util.nr_jobs)
107 // manual - pass 0 because we will start our own
108 C.init_photon_work_pool(0)
109 // start our own vcpu's manually
110 for _ in 1 .. util.nr_jobs {
111 spawn init_photon_vcpu()
112 }
113 }
114
115 if ret < 0 {
116 panic_n('failed to initialize coroutines via photon ret:', ret)
117 }
118}
119