diff --git a/thirdparty/photon/photonwrapper.h b/thirdparty/photon/photonwrapper.h index cef9d9ddf3..76123c6aa5 100644 --- a/thirdparty/photon/photonwrapper.h +++ b/thirdparty/photon/photonwrapper.h @@ -21,7 +21,7 @@ extern "C" { #endif 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_ms(int n); diff --git a/vlib/coroutines/coroutines.v b/vlib/coroutines/coroutines.v index a217b2b29c..22c1d9d95d 100644 --- a/vlib/coroutines/coroutines.v +++ b/vlib/coroutines/coroutines.v @@ -11,7 +11,7 @@ import time #include "photonwrapper.h" 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_ms(n int) @@ -19,3 +19,8 @@ fn C.photon_sleep_ms(n int) pub fn sleep(duration time.Duration) { C.photon_sleep_ms(duration.milliseconds()) } + +// init needs to be run +pub fn initialize() int { + return C.photon_init_default() +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 41261e5156..1383243b1b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4199,7 +4199,13 @@ fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type { fsym := c.table.final_sym(typ) 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 - 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 } if fsym.info !is ast.Enum { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 441872904c..fc2044edbc 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3161,10 +3161,16 @@ fn (mut g Gen) expr(node_ ast.Expr) { } } ast.SpawnExpr { - g.spawn_expr(node) + g.spawn_and_go_expr(node, .spawn_) } 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 { g.ident(node) diff --git a/vlib/v/gen/c/spawn_and_go.v b/vlib/v/gen/c/spawn_and_go.v index 66b166935c..f860c0ba57 100644 --- a/vlib/v/gen/c/spawn_and_go.v +++ b/vlib/v/gen/c/spawn_and_go.v @@ -6,8 +6,19 @@ module c import v.ast import v.util -fn (mut g Gen) spawn_expr(node ast.SpawnExpr) { - g.writeln('/*spawn (thread) */') +enum SpawnGoMode { + 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) mut handle := '' 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_fn_name := name + '_thread_wrapper' 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 { tmp_fn } else if expr.is_fn_var { @@ -76,15 +92,15 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) { name } 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 { - g.write('${arg_tmp_var}->arg0 = ') + g.write('${arg_tmp_var}${dot}arg0 = ') g.expr(expr.left) g.writeln(';') } 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.writeln(';') } @@ -108,39 +124,43 @@ fn (mut g Gen) spawn_expr(node ast.SpawnExpr) { 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}' } - if g.pref.os == .windows { - simple_handle := if node.is_expr && node.call_expr.return_type != ast.void_type { - 'thread_handle_${tmp}' + if is_spawn { + if g.pref.os == .windows { + 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 { - '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 { - 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});') + 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') 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) g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[') 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) - 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('${dot}_object') + g.gowrappers.write_string('${idot}_object') } else { g.gowrappers.write_string('arg->fn(') 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) { - g.writeln('/*go (coroutine) */') -} +// fn (mut g Gen) go_expr(node ast.GoExpr) { +//} // get current thread size, if fn hasn't defined return default [inline] diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 45de296f33..f594a61d28 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -8,6 +8,7 @@ import os.cmdline import os import v.vcache import rand +// import net.http // TODO can't use net.http on arm maccs: bignum.c arm asm error pub enum BuildMode { // `v program.v' @@ -801,6 +802,20 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin } '-use-coroutines' { 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 { if command == 'build' && is_source_file(arg) {