syscall/js (wasm): Wrapped func, goroutines, GOMAXPROCS, mutex necessity?

220 views
Skip to first unread message

atd...@gmail.com

unread,
Jul 2, 2022, 9:40:10 AM7/2/22
to golang-nuts
Hi,

I just have a quick question.
I am using callbacks that run Go code to modify a Go-wasm datastructure.
These callbacks are essentially Wrapped Go Funcs called from js.

Reading the docs, I've realized that each callback runs in its own goroutine.
Now, I'm wondering if I should protect access to the datastructure with mutexes.

It's a bit unclear here as I think the current implementation guarantees that each callback fully returns before another one gets processed (because the event loop is prempted each time a wrapped function gets called until it returns). Seems to me that callbacks into Go code can only be sequentially processed(?)

Also, if I launch a goroutine in one of these wrapped funcs, when would it be scheduled to run? Before the wrapped func it was launched from returns?

Many thanks,


atd...@gmail.com

unread,
Jul 2, 2022, 9:57:11 AM7/2/22
to golang-nuts
Addendum: for the bottom question, I would expect the goroutines launched to be scheduled right after the initial callback/wrapped func returns unless there is a blocking operation in which case the scheduler might run them earlier.
I also do not know if the goroutines would run in a given order, I would think it to be potentially random. (in the case multiple goroutines were launched within a callback)

All this before any other callback can be called from js.

Is that right? (still unsure of what it entails in terms of synchronization requirements)

atd...@gmail.com

unread,
Jul 3, 2022, 10:27:04 PM7/3/22
to golang-nuts
Ok so I am still trying to figure out what this paragraph entails:
> Invoking the wrapped Go function from JavaScript will pause the event loop and spawn a new goroutine. Other wrapped functions which are triggered during a call from Go to JavaScript get executed on the same goroutine.

> As a consequence, if one wrapped function blocks, JavaScript's event loop is blocked until that function returns. Hence, calling any async JavaScript API, which requires the event loop, like fetch (http.Client), will cause an immediate deadlock. Therefore > a blocking function should explicitly start a new goroutine.

As far as I understand, it means that only one wasm callback function can be run at a time and it will be run in a new goroutine. So there should be a happens-before edge here. Sequential ordering of synchronous callbacks should be kept. That does not require synchronization.

However, within that goroutine, other goroutines may be spawned. Naively, I would be tempted to say that it then may require synchronization.
But what makes me hesitate is that preempting the main goroutine and running a spawned goroutine that calls a wrapped function that requires the use of the event loop would block?
So how are goroutines scheduled here?
Can goroutines be interleaved? How does it not block then if several goroutines have to interact with the event loop?

Am I misunderstanding something?

atd...@gmail.com

unread,
Jul 4, 2022, 9:24:01 AM7/4/22
to golang-nuts
ok so, thinking about it again, I guess that here, there is no preemption point within functions. So when a wrapped function returns, the event loop resumes and it is then ok to call another wrapped function which may use the event loop.
However, there could be an issue if the wasm code were able to multiplex goroutines on different threads (I don't think that is the case yet) since there is  potentially simultaneous access by different goroutines.
So concurrent access needs to be serialized in my case, I think.




Reply all
Reply to author
Forward
Message has been deleted
0 new messages