diff --git a/cmd/v/help/build-c.txt b/cmd/v/help/build-c.txt index 8627eb48d7..11844b6555 100644 --- a/cmd/v/help/build-c.txt +++ b/cmd/v/help/build-c.txt @@ -257,7 +257,7 @@ see also `v help build`. Passing -no-std will remove that flag, and you can then use -cflags '' to pass the other options for your specific C compiler. --assert aborts + -assert aborts Call abort() after an assertion failure. Debuggers usually install signal handlers for SIGABRT, so your program will stop and you will get a backtrace. If you are running your program outside of a @@ -267,3 +267,14 @@ see also `v help build`. Call print_backtrace() after an assertion failure. Note that backtraces are not implemented yet on all combinations of platform/compiler. + + -thread-stack-size 4194304 + Set the thread stack size to 4MB. Use multiples of 4096. + The default is 8MB, which is enough for compiling V programs, with deeply + nested expressions (~40 levels). + It may need to be increased, if you are getting stack overflow errors for + deeply recursive programs like some of the stages of the V compiler itself, + that use relatively few threads. + It may be decreased, to reduce the memory footprint of programs that launch + hundreds/thousands of threads, but where each of the threads does not need + a big stack. diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 24a3babcbe..5bd571cc8b 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1777,7 +1777,14 @@ fn (mut g Gen) go_expr(node ast.GoExpr) { } } else { g.writeln('pthread_t thread_$tmp;') - g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);') + 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);') + g.writeln('pthread_attr_setstacksize(&thread_${tmp}_attributes, $g.pref.thread_stack_size);') + 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);') diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index c0e9736c66..b93e18a542 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -199,6 +199,7 @@ pub mut: nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64 // checker settings: checker_match_exhaustive_cutoff_limit int = 12 + thread_stack_size int = 8388608 // Change with `-thread-stack-size 4194304`. Note: on macos it was 524288, which is too small for more complex programs with many nested callexprs. } pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) { @@ -571,6 +572,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin res.message_limit = cmdline.option(current_args, arg, '5').int() i++ } + '-thread-stack-size' { + res.thread_stack_size = cmdline.option(current_args, arg, res.thread_stack_size.str()).int() + i++ + } '-cc' { res.ccompiler = cmdline.option(current_args, '-cc', 'cc') res.build_options << '$arg "$res.ccompiler"' diff --git a/vlib/v/tests/default_thread_stack_size_test.v b/vlib/v/tests/default_thread_stack_size_test.v new file mode 100644 index 0000000000..0cc46b41c2 --- /dev/null +++ b/vlib/v/tests/default_thread_stack_size_test.v @@ -0,0 +1,26 @@ +fn f(x u8) u8 { + eprintln('> f: $x') + if x == 0 { + return 0 + } + mut local := [131072]u8{} + local[local.len - 1] = x + f(x - 1) + return local[0] + local[local.len - 1] +} + +fn abc(depth u8) u8 { + return f(depth) +} + +fn test_default_stack_depth() { + $if tinyc && windows { + exit(0) // skip for now testing on windows-tcc + } + // Note: 10 levels of recursing f, requires a little over 1.4MB, + // and would have failed on macos, where the default thread size + // is just 512KB, if V was not changed to have a default for + // `-thread-stack-size` of 8MB. + t := go abc(10) + res := t.wait() + assert res == 55 +}