1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

all: coroutines (part 2)

This commit is contained in:
Alexander Medvednikov 2023-05-28 05:30:23 +02:00
parent 2162230086
commit 9db10c8f61
6 changed files with 99 additions and 48 deletions

View File

@ -21,7 +21,7 @@ extern "C" {
#endif #endif
int photon_init_default(); int photon_init_default();
void photon_thread_create11(void* (* f)(void*)); void photon_thread_create(void* (* f)(void*), void* arg);
void photon_sleep_s(int n); void photon_sleep_s(int n);
void photon_sleep_ms(int n); void photon_sleep_ms(int n);

View File

@ -11,7 +11,7 @@ import time
#include "photonwrapper.h" #include "photonwrapper.h"
fn C.photon_init_default() int fn C.photon_init_default() int
fn C.photon_thread_create11(f voidptr) fn C.photon_thread_create(f voidptr)
fn C.photon_sleep_s(n int) fn C.photon_sleep_s(n int)
fn C.photon_sleep_ms(n int) fn C.photon_sleep_ms(n int)
@ -19,3 +19,8 @@ fn C.photon_sleep_ms(n int)
pub fn sleep(duration time.Duration) { pub fn sleep(duration time.Duration) {
C.photon_sleep_ms(duration.milliseconds()) C.photon_sleep_ms(duration.milliseconds())
} }
// init needs to be run
pub fn initialize() int {
return C.photon_init_default()
}

View File

@ -4199,7 +4199,13 @@ fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type {
fsym := c.table.final_sym(typ) fsym := c.table.final_sym(typ)
if fsym.kind != .enum_ && !c.pref.translated && !c.file.is_translated { if fsym.kind != .enum_ && !c.pref.translated && !c.file.is_translated {
// TODO in C int fields can be compared to enums, need to handle that in C2V // TODO in C int fields can be compared to enums, need to handle that in C2V
c.error('expected type is not an enum (`${typ_sym.name}`)', node.pos) if typ_sym.kind == .placeholder {
// If it's a placeholder, the type doesn't exist, print
// an error that makes sense here.
c.error('unknown type `${typ_sym.name}`', node.pos)
} else {
c.error('expected type is not an enum (`${typ_sym.name}`)', node.pos)
}
return ast.void_type return ast.void_type
} }
if fsym.info !is ast.Enum { if fsym.info !is ast.Enum {

View File

@ -3161,10 +3161,16 @@ fn (mut g Gen) expr(node_ ast.Expr) {
} }
} }
ast.SpawnExpr { ast.SpawnExpr {
g.spawn_expr(node) g.spawn_and_go_expr(node, .spawn_)
} }
ast.GoExpr { ast.GoExpr {
g.go_expr(node) // XTODO this results in a cgen bug, order of fields is broken
// g.spawn_and_go_expr(ast.SpawnExpr{node.pos, node.call_expr, node.is_expr},
g.spawn_and_go_expr(ast.SpawnExpr{
pos: node.pos
call_expr: node.call_expr
is_expr: node.is_expr
}, .go_)
} }
ast.Ident { ast.Ident {
g.ident(node) g.ident(node)

View File

@ -6,8 +6,19 @@ module c
import v.ast import v.ast
import v.util import v.util
fn (mut g Gen) spawn_expr(node ast.SpawnExpr) { enum SpawnGoMode {
g.writeln('/*spawn (thread) */') spawn_
go_
}
fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
is_spawn := mode == .spawn_
is_go := mode == .go_
if is_spawn {
g.writeln('/*spawn (thread) */')
} else {
g.writeln('/*go (coroutine) */')
}
line := g.go_before_stmt(0) line := g.go_before_stmt(0)
mut handle := '' mut handle := ''
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
@ -67,7 +78,12 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
wrapper_struct_name := 'thread_arg_' + name wrapper_struct_name := 'thread_arg_' + name
wrapper_fn_name := name + '_thread_wrapper' wrapper_fn_name := name + '_thread_wrapper'
arg_tmp_var := 'arg_' + tmp arg_tmp_var := 'arg_' + tmp
g.writeln('${wrapper_struct_name} *${arg_tmp_var} = malloc(sizeof(thread_arg_${name}));') if is_spawn {
g.writeln('${wrapper_struct_name} *${arg_tmp_var} = malloc(sizeof(thread_arg_${name}));')
} else if is_go {
g.writeln('${wrapper_struct_name} ${arg_tmp_var};')
}
dot := if is_spawn { '->' } else { '.' }
fn_name := if use_tmp_fn_var { fn_name := if use_tmp_fn_var {
tmp_fn tmp_fn
} else if expr.is_fn_var { } else if expr.is_fn_var {
@ -76,15 +92,15 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
name name
} }
if !(expr.is_method && g.table.sym(expr.receiver_type).kind == .interface_) { if !(expr.is_method && g.table.sym(expr.receiver_type).kind == .interface_) {
g.writeln('${arg_tmp_var}->fn = ${fn_name};') g.writeln('${arg_tmp_var}${dot}fn = ${fn_name};')
} }
if expr.is_method { if expr.is_method {
g.write('${arg_tmp_var}->arg0 = ') g.write('${arg_tmp_var}${dot}arg0 = ')
g.expr(expr.left) g.expr(expr.left)
g.writeln(';') g.writeln(';')
} }
for i, arg in expr.args { for i, arg in expr.args {
g.write('${arg_tmp_var}->arg${i + 1} = ') g.write('${arg_tmp_var}${dot}arg${i + 1} = ')
g.expr(arg.expr) g.expr(arg.expr)
g.writeln(';') g.writeln(';')
} }
@ -108,39 +124,43 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
res := if is_res { '${result_name}_' } else { '' } res := if is_res { '${result_name}_' } else { '' }
gohandle_name = '__v_thread_${opt}${res}${g.table.sym(g.unwrap_generic(node.call_expr.return_type)).cname}' gohandle_name = '__v_thread_${opt}${res}${g.table.sym(g.unwrap_generic(node.call_expr.return_type)).cname}'
} }
if g.pref.os == .windows { if is_spawn {
simple_handle := if node.is_expr && node.call_expr.return_type != ast.void_type { if g.pref.os == .windows {
'thread_handle_${tmp}' simple_handle := if node.is_expr && node.call_expr.return_type != ast.void_type {
'thread_handle_${tmp}'
} else {
'thread_${tmp}'
}
stack_size := g.get_cur_thread_stack_size(expr.name)
g.writeln('HANDLE ${simple_handle} = CreateThread(0, ${stack_size}, (LPTHREAD_START_ROUTINE)${wrapper_fn_name}, ${arg_tmp_var}, 0, 0); // fn: ${expr.name}')
g.writeln('if (!${simple_handle}) panic_lasterr(tos3("`go ${name}()`: "));')
if node.is_expr && node.call_expr.return_type != ast.void_type {
g.writeln('${gohandle_name} thread_${tmp} = {')
g.writeln('\t.ret_ptr = ${arg_tmp_var}->ret_ptr,')
g.writeln('\t.handle = thread_handle_${tmp}')
g.writeln('};')
}
if !node.is_expr {
g.writeln('CloseHandle(thread_${tmp});')
}
} else { } else {
'thread_${tmp}' g.writeln('pthread_t thread_${tmp};')
} mut sthread_attributes := 'NULL'
stack_size := g.get_cur_thread_stack_size(expr.name) if g.pref.os != .vinix {
g.writeln('HANDLE ${simple_handle} = CreateThread(0, ${stack_size}, (LPTHREAD_START_ROUTINE)${wrapper_fn_name}, ${arg_tmp_var}, 0, 0); // fn: ${expr.name}') g.writeln('pthread_attr_t thread_${tmp}_attributes;')
g.writeln('if (!${simple_handle}) panic_lasterr(tos3("`go ${name}()`: "));') g.writeln('pthread_attr_init(&thread_${tmp}_attributes);')
if node.is_expr && node.call_expr.return_type != ast.void_type { size := g.get_cur_thread_stack_size(expr.name)
g.writeln('${gohandle_name} thread_${tmp} = {') g.writeln('pthread_attr_setstacksize(&thread_${tmp}_attributes, ${size}); // fn: ${expr.name}')
g.writeln('\t.ret_ptr = ${arg_tmp_var}->ret_ptr,') sthread_attributes = '&thread_${tmp}_attributes'
g.writeln('\t.handle = thread_handle_${tmp}') }
g.writeln('};') g.writeln('int ${tmp}_thr_res = pthread_create(&thread_${tmp}, ${sthread_attributes}, (void*)${wrapper_fn_name}, ${arg_tmp_var});')
} g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
if !node.is_expr { if !node.is_expr {
g.writeln('CloseHandle(thread_${tmp});') g.writeln('pthread_detach(thread_${tmp});')
} }
} else {
g.writeln('pthread_t thread_${tmp};')
mut sthread_attributes := 'NULL'
if g.pref.os != .vinix {
g.writeln('pthread_attr_t thread_${tmp}_attributes;')
g.writeln('pthread_attr_init(&thread_${tmp}_attributes);')
size := g.get_cur_thread_stack_size(expr.name)
g.writeln('pthread_attr_setstacksize(&thread_${tmp}_attributes, ${size}); // fn: ${expr.name}')
sthread_attributes = '&thread_${tmp}_attributes'
}
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_${tmp}, ${sthread_attributes}, (void*)${wrapper_fn_name}, ${arg_tmp_var});')
g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
if !node.is_expr {
g.writeln('pthread_detach(thread_${tmp});')
} }
} else if is_go {
g.writeln('photon_thread_create((void*)${wrapper_fn_name}, &${arg_tmp_var});')
} }
g.writeln('// end go') g.writeln('// end go')
if node.is_expr { if node.is_expr {
@ -273,11 +293,11 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
receiver_type_name := util.no_dots(rec_cc_type) receiver_type_name := util.no_dots(rec_cc_type)
g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[') g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[')
g.gowrappers.write_string('arg->arg0') g.gowrappers.write_string('arg->arg0')
dot := if expr.left_type.is_ptr() { '->' } else { '.' } idot := if expr.left_type.is_ptr() { '->' } else { '.' }
mname := c_name(expr.name) mname := c_name(expr.name)
g.gowrappers.write_string('${dot}_typ]._method_${mname}(') g.gowrappers.write_string('${idot}_typ]._method_${mname}(')
g.gowrappers.write_string('arg->arg0') g.gowrappers.write_string('arg->arg0')
g.gowrappers.write_string('${dot}_object') g.gowrappers.write_string('${idot}_object')
} else { } else {
g.gowrappers.write_string('arg->fn(') g.gowrappers.write_string('arg->fn(')
g.gowrappers.write_string('arg->arg0') g.gowrappers.write_string('arg->arg0')
@ -354,9 +374,8 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
} }
} }
fn (mut g Gen) go_expr(node ast.GoExpr) { // fn (mut g Gen) go_expr(node ast.GoExpr) {
g.writeln('/*go (coroutine) */') //}
}
// get current thread size, if fn hasn't defined return default // get current thread size, if fn hasn't defined return default
[inline] [inline]

View File

@ -8,6 +8,7 @@ import os.cmdline
import os import os
import v.vcache import v.vcache
import rand import rand
// import net.http // TODO can't use net.http on arm maccs: bignum.c arm asm error
pub enum BuildMode { pub enum BuildMode {
// `v program.v' // `v program.v'
@ -801,6 +802,20 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
} }
'-use-coroutines' { '-use-coroutines' {
res.use_coroutines = true res.use_coroutines = true
$if macos && arm64 {
vexe := vexe_path()
vroot := os.dir(vexe)
so_path := os.join_path(vroot, 'thirdparty', 'photon', 'photonwrapper.so')
so_url := 'https://github.com/vlang/photonbin/raw/master/photonwrapper_macos_arm64.so'
if !os.exists(so_path) {
println('coroutines .so not found, downloading...')
// http.download_file(so_url, so_path) or { panic(err) }
os.system('wget -O "${so_path}" "${so_url}"')
println('done!')
}
} $else {
println('coroutines only work on arm64 macos for now')
}
} }
else { else {
if command == 'build' && is_source_file(arg) { if command == 'build' && is_source_file(arg) {