Deadlock

123 views
Skip to first unread message

Luis Furquim

unread,
Jun 16, 2022, 4:41:43 PM6/16/22
to golang-nuts

Hi Gophers!

I am trying to work with web assembly and got stuck with a deadlock problem,
The main function has nothing more than simple steps, but if someone wants to check, it is at https://go.dev/play/p/y_0aiIzFA0j .
It imports an internal package so it is not compilable outside my computer, it is at the Go Playground just to show the source if someone wants to see it.

So, it sets a javascript callable function exported as img2data. The purpose of the function is to receive an HTML string and check each image reference (IMG tags and alse elements with "background-image: url(...)" style), download the image, generate a data URL, and finally replacing the reference in the HTML with the data URL.

But when it starts the process it deadlocks at the very first image it finds. The panic message is as follows:

2022/06/16 17:19:01 {main}[Img2data-wasm.go]<main.func1>(26): Calling Img2data
wasm_exec.js:51 2022/06/16 17:19:01 {Img2data}[Img2data.go]<Img2data>(21): START
8wasm_exec.js:51 2022/06/16 17:19:02 {Img2data}[Img2data.go]<Img2data.func1>(30): NOSCRIPT
wasm_exec.js:51 2022/06/16 17:19:02 {Img2data}[Img2data.go]<Img2data.func2>(41): IMG
wasm_exec.js:51 2022/06/16 17:19:02 {Img2data}[Img2data.go]<Img2data.func2>(44): img: src=https://<censored image url>.png
wasm_exec.js:51 2022/06/16 17:19:02 {Img2data}[Img2data.go]<Img2data.func2>(46): img: src=https://<censored image url>.png
wasm_exec.js:51 fatal error: all goroutines are asleep - deadlock!
wasm_exec.js:51
wasm_exec.js:51 goroutine 1 [chan receive]:
wasm_exec.js:51 main.main()
wasm_exec.js:51 /home/vuco/repos/mpf/Img2data/cmd/Img2data-wasm.go:35 +0xa
wasm_exec.js:51
wasm_exec.js:51 goroutine 6 [select]:
wasm_exec.js:51 net/http.(*Transport).RoundTrip(0x36c640, 0x1a0a200, 0x36c640, 0x0, 0x0)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/roundtrip_js.go:169 +0x4f
wasm_exec.js:51 net/http.send(0x1a0a200, 0xe14d8, 0x36c640, 0x0, 0x0, 0x0, 0x0, 0x40c0b8, 0x718ed0, 0x1)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:251 +0x5b
wasm_exec.js:51 net/http.(*Client).send(0x379940, 0x1a0a200, 0x0, 0x0, 0x0, 0x40c0b8, 0x0, 0x1, 0x1a0a200)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:175 +0x13
wasm_exec.js:51 net/http.(*Client).do(0x379940, 0x1a0a200, 0x0, 0x0, 0x0)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:717 +0x36
wasm_exec.js:51 net/http.(*Client).Do(...)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:585
wasm_exec.js:51 net/http.(*Client).Get(0x379940, 0x4c4320, 0x4e, 0xb, 0x1a05d50, 0x1)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:474 +0xe
wasm_exec.js:51 net/http.Get(...)
wasm_exec.js:51 /home/vuco/repos/go/src/net/http/client.go:446
wasm_exec.js:51 mpf/Img2data.Img2data.func2(0x0, 0x718de0)
wasm_exec.js:51 /home/vuco/repos/mpf/Img2data/Img2data.go:48 +0x19
wasm_exec.js:51 github.com/PuerkitoBio/goquery.(*Selection).Each(0x718db0, 0xa8378, 0x3)
wasm_exec.js:51 /home/vuco/repos/gopkg/pkg/mod/github.com/!puerkito!bio/goq...@v1.8.0/iteration.go:10 +0x16
wasm_exec.js:51 mpf/Img2data.Img2data(0x2000000, 0x9ef7fd, 0x2000000, 0x9ef7fd, 0x0, 0x0)
wasm_exec.js:51 /home/vuco/repos/mpf/Img2data/Img2data.go:34 +0x14
wasm_exec.js:51 main.main.func1(0x0, 0x0, 0x40ec60, 0x1, 0x1, 0x4102b8, 0x3a0108)
wasm_exec.js:51 /home/vuco/repos/mpf/Img2data/cmd/Img2data-wasm.go:28 +0x10
wasm_exec.js:51 syscall/js.handleEvent()
wasm_exec.js:51 /home/vuco/repos/go/src/syscall/js/func.go:96 +0x24

I shared the point of the code where it panics at https://go.dev/play/p/3chb2eQo8sD . Again, it is not runnable, it's just there to check the code. It panics at line 15. 

The point is: there is only 2 goroutines (done by me, I don't know about other go routines started by the libraries) 
1) the main function running, but, as learnt from golang wasm tutorial, it is doing nothing, just waiting forever for a channel read that will never read anything, 
2) the img2data function that tries to download the images ang, when I call the http.Get it goes to sleep waiting for the server to answer the request and at this very moment all my goroutines are sleeping ang the runtime detects this condition and panics!

I also tried to make the main function do something while it waits forever by using a "for{}", it did not panicked, but I got stuck anyway and I suspect that it is because in the web assembly runtime only one goroutine can execute until it sleeps and leave place for other goroutines and doing a "for{}" makes the main function run forever but it never allows the img2data function to be run.

So, someone could help me on how to solve this problem?

Thank you in advance!
Best regards,

--
Luis Otavio de Colla Furquim

Luis Furquim

unread,
Jun 17, 2022, 1:36:05 AM6/17/22
to golang-nuts
So, finally I solved the problem!

The trick is to add a new parameter to the exported function. This parameter will be a javascript callback. Then we call the exported function as a goroutine passing the callback to it. The exported function had also to be changed: no more values to be returned, now they are passed to the callback function. Doing so, when the function is called the execution flow immediately returns to javascript and no panic occurs. The exported function (called asynchronously) keeps running (sleeping from time to time when it calls http.Get) until all the work is done, then it calls the javascript callback!

If someone wants to see the code, the main function can be seen (although can't be executed thanks to the private package it imports) here: https://go.dev/play/p/Iyy-pgCZCHI


The javascript code invoking the wasm function:

window.addEventListener('message', function(event) {
   console.log("STARTING WASM");
   img2data(event.data.body, {
      success: function(htmldoc) {
         event.source.postMessage({doc: htmldoc, err: null}, event.origin);
         console.log("ENDING success WASM");
      },
      fail: function(err) {
         event.source.postMessage({doc: "", err: err}, event.origin);
         console.log("ENDING failed WASM");
      },
   });
   console.log("WASM pending");
});


So, I ended up answering my own question, but I think that the question should be "closed" to prevent anyone of wasting time and also it could help someone else with the same problem in the future.

Best regards!
Reply all
Reply to author
Forward
0 new messages