medvednikov

/

vqPublic
0 commits21 issue12 pull requests0 contributorsDiscussionsProjectsCI

cgen, coroutines: fix go expr handle referencing undeclared thread__tN#14

Openmedvednikovwants to mergepr/27379intomaster· last Jun 7
3 files changed+51-2
examples/coroutines/go_handle.vnew file+24-0

@@ -0,0 +1,24 @@

1+// vtest build: false // This should be built with: `v -use-coroutines go_handle.v`

2+// Note: the Photon wrapper is not yet trivial enough to build/install on the CI.

3+//

4+// Demonstrates storing the handle returned by a `go` expression and waiting on

5+// it. Because the Photon coroutine wrapper exposes no joinable handle, a `go`

6+// whose handle is used is lowered to the regular `spawn` (pthread) path, so the

7+// handle can be waited on just like `spawn`.

8+module main

9+

10+struct App {

11+mut:

12+ worker thread

13+}

14+

15+fn (a App) loop() {

16+ println('hello from the worker coroutine')

17+}

18+

19+fn main() {

20+ mut a := App{}

21+ a.worker = go a.loop()

22+ a.worker.wait()

23+ println('done')

24+}

vlib/v/gen/c/spawn_and_go.v+13-2

@@ -15,8 +15,19 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {

1515 if node.call_expr.should_be_skipped {

1616 return

1717 }

18- is_spawn := mode == .spawn_

19- is_go := mode == .go_

18+ mut is_spawn := mode == .spawn_

19+ mut is_go := mode == .go_

20+ if is_go && node.is_expr {

21+ // A `go expr` whose handle is used as a value (e.g. `h := go f()` or

22+ // `obj.field = go f()`) needs a real, joinable thread handle. The photon

23+ // coroutine wrapper (`photon_thread_create*`) returns void and exposes no

24+ // such handle, so fall back to the regular `spawn` (pthread) path here,

25+ // which declares and assigns the `thread_<tmp>` handle that is read back

26+ // as the expression's value. Plain statement form `go f()` (no handle

27+ // used) keeps using the photon work-pool path below.

28+ is_spawn = true

29+ is_go = false

30+ }

2031 if is_spawn {

2132 g.writeln('/*spawn (thread) */')

2233 } else {

vlib/v/markused/walker.v+14-0

@@ -1075,6 +1075,20 @@ fn (mut w Walker) expr(node_ ast.Expr) {

10751075 ast.GoExpr {

10761076 if node.is_expr {

10771077 w.fn_by_name('free')

1078+ // A `go expr` whose handle is used as a value is lowered to the

1079+ // `spawn` (pthread) codegen path (see spawn_and_go_expr), since the

1080+ // photon coroutine wrapper returns no joinable handle. Mark the same

1081+ // thread-handle type and pthread error helpers that `spawn` needs,

1082+ // otherwise -skip-unused prunes them and the generated C fails to link.

1083+ w.mark_by_type(w.table.find_or_register_thread(node.call_expr.return_type))

1084+ w.uses_spawn = true

1085+ if w.pref.os == .windows {

1086+ w.fn_by_name('panic_lasterr')

1087+ w.fn_by_name('winapi_lasterr_str')

1088+ } else {

1089+ w.fn_by_name('c_error_number_str')

1090+ w.fn_by_name('panic_error_number')

1091+ }

10781092 }

10791093 w.mark_by_type(node.call_expr.return_type)

10801094 w.expr(node.call_expr)