Alright, this is something that provided me trouble for some time now, so I would like to ask for help here, so here is the situation:
For my project NewCaw (A rewrite of Cawbird for GTK4) I need to implement the option to download media and display them in the UI. For downloading I am using libsoup.
Recently I rewrote the code for media download to use GLib.Task to move the download and converting of images to a thread. While this works most time without problems, I do encounter more often than enough that libsoup segfaults or has an error which is not caught by my error handling (mostly an assertion error).
Since it worked fine with an previous approach using async I expect that while creating the new downloader I have made some error with using Task and Soup, but I am not sure where it could be, which is why I want to ask here if someone else can spot the error.
The relevant classes to look at would be MediaLoader (base class implementing the download), ImageLoader (managing the task and creating a Gdk.Texture) and MediaDisplayItem as an example for a UI class initiating a download.
I checked quickly just to make sure you’re creating a new SoupSession for each thread that you use – not passing the same SoupSession between multiple threads – and it looks like you are. You’ll probably need to report a libsoup bug and post backtraces. As long as you’re confident that you’re not reusing objects across threads, the library itself should be threadsafe.
In libsoup 2 there was an attempt at making various APIs of the library thread-safe. However this was never well tested, maintained, or documented.
In libsoup 3 it now behaves in line with other GObject libraries. Once you create a SoupSession all usage of that session must happen on the same thread. You may create seperate sessions per thread but in most use-cases you should be using the async APIs which handle non-blocking IO for you.
You should be using libsoup 3 in new projects anyway, but if you are still using libsoup 2, better follow the rules for libsoup 3 anyway.
Also I know this isn’t the point of this post but the usage of session.send_and_read() followed by MemoryInputStream.from_bytes (streambytes); is really odd… libsoup returns an InputStream for you to read from directly.