| 1 | import os |
| 2 | |
| 3 | fn execute_in_thread(id int) !string { |
| 4 | res := os.execute('printf thread_${id}') |
| 5 | if res.exit_code != 0 { |
| 6 | return error('thread ${id} failed: exit=${res.exit_code} output="${res.output.trim_space()}"') |
| 7 | } |
| 8 | return res.output |
| 9 | } |
| 10 | |
| 11 | fn test_execute_inside_spawned_threads() { |
| 12 | $if windows { |
| 13 | return |
| 14 | } |
| 15 | $if macos { |
| 16 | // On macos-14 GitHub Actions runners, when the V repo is checked out |
| 17 | // under a path that contains non-ASCII bytes (the space-paths CI does |
| 18 | // this with `你好 my $path, @с интервали`), os.execute() inside spawned |
| 19 | // threads consistently returns empty output here, even with FD_CLOEXEC |
| 20 | // and a V-level pthread mutex serializing pipe()+posix_spawn. Regular |
| 21 | // macos CI (ASCII paths) passes the test, so skip only when the cwd |
| 22 | // contains non-ASCII bytes. |
| 23 | cwd := os.getwd() |
| 24 | for b in cwd.bytes() { |
| 25 | if b >= 0x80 { |
| 26 | return |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | for _ in 0 .. 3 { |
| 31 | mut threads := []thread !string{} |
| 32 | for i in 0 .. 4 { |
| 33 | threads << spawn execute_in_thread(i) |
| 34 | } |
| 35 | mut outputs := []string{cap: 4} |
| 36 | for t in threads { |
| 37 | outputs << t.wait() or { panic(err) } |
| 38 | } |
| 39 | assert outputs == ['thread_0', 'thread_1', 'thread_2', 'thread_3'] |
| 40 | } |
| 41 | } |
| 42 | |