8000 [WASM] wasm export func block until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue · Issue #4874 · tinygo-org/tinygo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[WASM] wasm export func block until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue #4874

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

Open
labulakalia opened this issue Apr 26, 2025 · 5 comments
Labels
bug Something isn't working next-release Will be part of next release wasm WebAssembly

Comments

@labulakalia
Copy link

env

go version go1.24.0 linux/amd64
tinygo version 0.37.0 linux/amd64 (using go version go1.24.0 and LLVM version 19.1.2)

example code

greet_wasm.go

package main

import (
	"fmt"
	"runtime"
	"time"
)

// main is required for TinyGo to compile to Wasm.
func main() {}

//go:wasmexport greet
func _greet() {
	go func() {
		fmt.Println(time.Now(), "wasm call host func log")
		for i := 0; i < 10; i++ {
			runtime.Gosched()
			fmt.Println(time.Now(), "sleep", i)
			time.Sleep(time.Second)
			runtime.Gosched()
		}
		fmt.Println(time.Now(), "wasm end call host func log")
	}()
	fmt.Println(time.Now(), "start go sched")
	runtime.Gosched()
	time.Sleep(time.Second * 3)
	fmt.Println(time.Now(), "wasm greet exit")

}

greet.go

package main

import (
	"context"
	"crypto/rand"
	_ "embed"
	"fmt"
	"log"
	"os"

	"github.com/tetratelabs/wazero"
	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

func main() {
	greetWasm, _ := os.ReadFile(os.Args[1])
	// Choose the context to use for function calls.
	ctx := context.Background()

	// Create a new WebAssembly Runtime.
	r := wazero.NewRuntime(ctx)
	defer r.Close(ctx) // This closes everything this Runtime created.

	// Instantiate a Go-defined module named "env" that exports a function to
	// log to the console.
	_, err := r.NewHostModuleBuilder("env").
		Instantiate(ctx)
	if err != nil {
		log.Panicln(err)
	}
	wasi_snapshot_preview1.MustInstantiate(ctx, r)
	conf := wazero.NewModuleConfig().WithStartFunctions("_initialize").
		WithStdout(os.Stdout).
		WithStderr(os.Stderr).
		WithStdin(os.Stdin).
		WithRandSource(rand.Reader).
		WithSysNanosleep().
		WithSysNanotime().
		WithSysWalltime()
	mod, err := r.InstantiateWithConfig(ctx, greetWasm, conf)
	if err != nil {
		log.Panicln(err)
	}
	greet := mod.ExportedFunction("greet")
	_, err = greet.Call(ctx)
	if err != nil {
		log.Panicln(err)
	}
	fmt.Println("call exit")
}

build wasm

GOOS=wasip1 GOARCH=wasm go build -x -buildmode=c-shared  -o greet_go.wasm greet_wasm.go
tinygo build -x -target=wasip1 -buildmode=c-shared  -o greet_tinygo.wasm greet_wasm.go

run code

✗ go run ./greet.go greet_go.wasm
2025-04-26 09:26:46.872942035 +0000 UTC m=+0.000078673 start go sched
2025-04-26 09:26:46.873053476 +0000 UTC m=+0.000189942 wasm call host func log
2025-04-26 09:26:46.873128772 +0000 UTC m=+0.000265139 sleep 0
2025-04-26 09:26:47.873372779 +0000 UTC m=+1.000509331 sleep 1
2025-04-26 09:26:48.873640519 +0000 UTC m=+2.000777271 sleep 2
2025-04-26 09:26:49.873695106 +0000 UTC m=+3.000832630 wasm greet exit
call exit
go run ./greet.go greet_tinygo.wasm
2025-04-26 09:26:56.587587118 +0000 UTC m=+1745659616.587587119 start go sched
2025-04-26 09:26:56.587619849 +0000 UTC m=+1745659616.587619850 wasm call host func log
2025-04-26 09:26:56.587631859 +0000 UTC m=+1745659616.587631860 sleep 0
2025-04-26 09:26:57.588717987 +0000 UTC m=+1745659617.588717988 sleep 1
2025-04-26 09:26:58.588576017 +0000 UTC m=+1745659618.588576018 sleep 2
2025-04-26 09:26:59.588550816 +0000 UTC m=+1745659619.588550817 wasm greet exit
2025-04-26 09:26:59.588612372 +0000 UTC m=+1745659619.588612373 sleep 3
2025-04-26 09:27:00.589590637 +0000 UTC m=+1745659620.589590638 sleep 4
2025-04-26 09:27:01.590820044 +0000 UTC m=+1745659621.590820045 sleep 5
2025-04-26 09:27:02.591662457 +0000 UTC m=+1745659622.591662458 sleep 6
2025-04-26 09:27:03.592701553 +0000 UTC m=+1745659623.592701554 sleep 7
2025-04-26 09:27:04.592851337 +0000 UTC m=+1745659624.592851338 sleep 8
2025-04-26 09:27:05.593621511 +0000 UTC m=+1745659625.593621512 sleep 9
2025-04-26 09:27:06.594576024 +0000 UTC m=+1745659626.594576025 wasm end call host func log
call exit

hope

i need wasm exit not block other goroutinue by tinygo build

@labulakalia labulakalia changed the title [WASM] call wasm export func block when until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue [WASM] call wasm export func block until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue Apr 26, 2025
@labulakalia
Copy link
Author

if move code to func main not use //go:wasmexport greet , this behavior same with go,
example code
greet_wasm.go

package main

import (
	"fmt"
	"runtime"
	"time"
)

// main is required for TinyGo to compile to Wasm.
func main() {
	go func() {
		fmt.Println(time.Now(), "wasm call host func log")
		for i := 0; i < 10; i++ {
			runtime.Gosched()
			fmt.Println(time.Now(), "sleep", i)
			time.Sleep(time.Second)
			runtime.Gosched()
		}
		fmt.Println(time.Now(), "wasm end call host func log")
	}()
	fmt.Println(time.Now(), "start go sched")
	runtime.Gosched()
	time.Sleep(time.Second * 3)
	fmt.Println(time.Now(), "wasm greet exit")

}

//go:wasmexport greet
func _greet() {

}

build it not use c-shared

tinygo build -x -target=wasip1 -o greet_tinygo.wasm greet_wasm.go

greet.go

package main

import (
	"context"
	"crypto/rand"
	_ "embed"
	"fmt"
	"log"
	"os"

	"github.com/tetratelabs/wazero"
	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

func main() {
	greetWasm, _ := os.ReadFile(os.Args[1])
	// Choose the context to use for function calls.
	ctx := context.Background()

	// Create a new WebAssembly Runtime.
	r := wazero.NewRuntime(ctx)
	defer r.Close(ctx) // This closes everything this Runtime created.

	// Instantiate a Go-defined module named "env" that exports a function to
	// log to the console.
	_, err := r.NewHostModuleBuilder("env").
		Instantiate(ctx)
	if err != nil {
		log.Panicln(err)
	}
	wasi_snapshot_preview1.MustInstantiate(ctx, r)
	conf := wazero.NewModuleConfig().WithStartFunctions("_start").
		WithStdout(os.Stdout).
		WithStderr(os.Stderr).
		WithStdin(os.Stdin).
		WithRandSource(rand.Reader).
		WithSysNanosleep().
		WithSysNanotime().
		WithSysWalltime()
	mod, err := r.InstantiateWithConfig(ctx, greetWasm, conf)
	if err != nil {
		log.Panicln(err)
	}
	mod = mod
	// greet := mod.ExportedFunction("greet")
	// _, err = greet.Call(ctx)
	// if err != nil {
	// 	log.Panicln(err)
	// }
	fmt.Println("call exit")

}

run this code

go run ./greet.go greet_tinygo.wasm
2025-04-26 09:42:19.47828821 +0000 UTC m=+1745660539.478288211 start go sched
2025-04-26 09:42:19.478316019 +0000 UTC m=+1745660539.478316020 wasm call host func log
2025-04-26 09:42:19.478347789 +0000 UTC m=+1745660539.478347790 sleep 0
2025-04-26 09:42:20.478735262 +0000 UTC m=+1745660540.478735263 sleep 1
2025-04-26 09:42:21.478565463 +0000 UTC m=+1745660541.478565464 sleep 2
2025-04-26 09:42:22.478581989 +0000 UTC m=+1745660542.478581990 wasm greet exit
call exit

@labulakalia
Copy link
Author

@aykevl could you look this problem about wasm,thanks

@labulakalia labulakalia changed the title [WASM] call wasm export func block until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue [WASM] wasm export func block until other goroutinue exit, this behavior not same go,go will exit right now and not block other goroutinue Apr 26, 2025
@deadprogram deadprogram added the wasm WebAssembly label Apr 27, 2025
@aykevl
Copy link
Member
aykevl commented Apr 28, 2025

I can confirm this bug.

Simplified code:

package main

import (
        "runtime"
        "time"
)

// main is required for Go to compile to Wasm.
func main() {}

//go:wasmexport greet
func _greet() {
        go func() {
                println("inside goroutine")
                time.Sleep(time.Second*2)
                println("exiting goroutine")
        }()
        runtime.Gosched()
        println("exiting greet function")
}

Go command:

 GOOS=wasip1 GOARCH=wasm go build -o test.wasm -buildmode=c-shared tmp/issue4874.go && time wasmtime --invoke greet test.wasm
inside goroutine
exiting greet function

________________________________________________________
Executed in   30.13 millis    fish           external
   usr time   18.16 millis    1.72 millis   16.44 millis
   sys time    4.15 millis    0.05 millis    4.10 millis

TinyGo:

$ GOOS=wasip1 GOARCH=wasm tinygo build -o test.wasm -buildmode=c-shared tmp/issue4874.go && time wasmtime --invoke greet test.wasm
inside goroutine
exiting greet function
exiting goroutine

________________________________________________________
Executed in    2.02 secs      fish           external
   usr time   28.76 millis    1.03 millis   27.73 millis
   sys time    9.38 millis    0.99 millis    8.38 millis

The proposal (golang/go#65199) says the following:

The proposal considers scenarios where the go:wasmexport call spawns new goroutines. In the absence of threading or stack switching capability in Wasm, the simplest option is to document that all goroutines still running when the invocation of the go:wasmexport function returns will be paused until the control flow re-enters the Go application.

So greet should return when it's done, it should not wait for other goroutines to complete.

@aykevl
Copy link
Member
aykevl commented Apr 28, 2025

See: #4875

@deadprogram
Copy link
Member

Tagging to close this issue after next release.

@deadprogram deadprogram added next-release Will be part of next release bug Something isn't working labels Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working next-release Will be part of next release wasm WebAssembly
Projects
None yet
Development

No branches or pull requests

3 participants
0