Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow goroutines from exported wasm functions #3095

Open
codefromthecrypt opened this issue Aug 25, 2022 · 7 comments
Open

Allow goroutines from exported wasm functions #3095

codefromthecrypt opened this issue Aug 25, 2022 · 7 comments
Labels
enhancement New feature or request wasm WebAssembly

Comments

@codefromthecrypt
Copy link
Contributor

Currently, the following will work as expected:

package main

import "fmt"

func main() {
	msg := make(chan int)
	finished := make(chan int)
	go func() {
		<-msg
		fmt.Println("consumer")
		finished <- 1
	}()
	go func() {
		fmt.Println("producer")
		msg <- 1
	}()
	<-finished
}

However, doing the same from an exported function besides main panics at the line the goroutine is created.

package main

import "fmt"

func main() {}

//export notMain
func notMain() {
	msg := make(chan int)
	finished := make(chan int)
	go func() { // <- panic
		<-msg
		fmt.Println("consumer")
		finished <- 1
	}()
	go func() {
		fmt.Println("producer")
		msg <- 1
	}()
	<-finished
}

Since Wasm isn't parallel-safe, we rely on keeping main alive and calling the exported function at the same time.
It would seem helpful to have a compiler flag or an annotation like //enable-scheduler

Note: jimmysl lee noticed that if you manipulate the %.wasm and insert a call opcode to call the _start function prior to actually invoking the desired export, it doesn't crash. This hint might help narrow down a path to a solution.

@deadprogram deadprogram added enhancement New feature or request wasm WebAssembly labels Aug 25, 2022
@aykevl
Copy link
Member

aykevl commented Aug 25, 2022

If you want to call an exported function without calling _start first: that is not possible. _start must be called first to initialize various things (the runtime, global variables, etc).

Or do you mean something else?

It might be possible to allow calling exported functions after main has returned, if that is what you want.

@codefromthecrypt
Copy link
Contributor Author

_start is already called first (at least in the test I was doing as wazero calls it by default, so before you can call any exports). Perhaps it is due to _start completing?

@aykevl
Copy link
Member

aykevl commented Sep 8, 2022

I don't think this can work, at least not in a JS environment. The issue is that JavaScript can't block, and you are doing a blocking operation with <-finished.

Apart from that, running goroutines after main has returned isn't specified in the Go specification:

Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

In other words, goroutines that were running when main exits will be terminated. That doesn't necessarily imply that you can't start new goroutines, but it would be odd if that were possible.

@codefromthecrypt
Copy link
Contributor Author

ok I should rephrase this as non-js. ex wasi and freestanding cc @hunjixin

The nature of entry points in wasm are different than go, and the impedance mismatch is a reality. what we do about it however is our choice. IOTW saying something about how main works in normal go, is historical context, but in the context of wasm (non js.. remember wasm core spec has no JS in it), it isn't necessarily painting a clear decision of what to do.

@dgryski
Copy link
Member

dgryski commented Feb 2, 2023

Does this boil down to #2735 ?

@codefromthecrypt
Copy link
Contributor Author

I'm not really sure the future of the reactor thing in WASI, even normal command is being completely redone. It feels uncomfortable to move it to blocked on something we don't implement, and might be dead by the time we do..

@twharmon
Copy link
Contributor

twharmon commented Jan 22, 2024

I encountered a very similar problem with wasm ran in the browser. Rather than panic, the goroutine would just not execute. I was able to "fix" it by wrapping it in a js func:

var work = js.FuncOf(somethingThatUsesGoroutines)

//export notMain
func notMain() {
	work.Invoke()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request wasm WebAssembly
Projects
None yet
Development

No branches or pull requests

5 participants