After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 693911 - souphttpsrc: rewrite using new session/request API
souphttpsrc: rewrite using new session/request API
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gst-plugins-good
git master
Other Linux
: Normal enhancement
: 1.9.1
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2013-02-15 17:31 UTC by Rico Tzschichholz
Modified: 2016-06-17 22:08 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Port soup to use sync API (34.49 KB, patch)
2016-05-14 10:34 UTC, Thiago Sousa Santos
none Details | Review
Backtrace when souphttpsrc hangs (8.67 KB, text/plain)
2016-05-30 09:22 UTC, Carlos Rafael Giani
  Details
updated backtrace (9.23 KB, text/plain)
2016-06-01 10:03 UTC, Carlos Rafael Giani
  Details

Description Rico Tzschichholz 2013-02-15 17:31:26 UTC
Building against libsoup 2.41.5 triggers the following deprecation warnings.

make -C soup
make[3]: Betrete Verzeichnis 'gstreamer/gst-plugins-good/ext/soup'
  CC       libgstsouphttpsrc_la-gstsouphttpsrc.lo
gstsouphttpsrc.c: In function 'gst_soup_http_src_build_message':
gstsouphttpsrc.c:1108:3: error: 'soup_message_set_chunk_allocator' is deprecated (declared at /usr/include/libsoup-2.4/libsoup/soup-message.h:176): Use 'SoupRequest' instead [-Werror=deprecated-declarations]
gstsouphttpsrc.c: In function 'gst_soup_http_src_start':
gstsouphttpsrc.c:1218:9: error: 'soup_proxy_resolver_gnome_get_type' is deprecated (declared at /usr/include/libsoup-gnome-2.4/libsoup/soup-gnome-features.h:15): Use '(soup_proxy_resolver_default_get_type ())' instead [-Werror=deprecated-declarations]
cc1: all warnings being treated as errors
make[3]: *** [libgstsouphttpsrc_la-gstsouphttpsrc.lo] Fehler 1
Comment 1 Tim-Philipp Müller 2013-02-16 15:49:31 UTC
commit a3e1db12929ed26a6d589e796e38ac8627471fb6
Author: Tim-Philipp Müller <tim@centricular.net>
Date:   Sat Feb 16 15:47:02 2013 +0000

    soup: use default proxy resolver instead of deprecated GNOME proxy resolver
    
    Apparently there's no reason to use it any longer. Drop libsoup-gnome
    dependency while at it, now that we don't need anything from it any
    more (it only consists entirely of deprecated API now anyways).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693911
Comment 2 Tim-Philipp Müller 2013-02-16 16:52:01 UTC
I hope this fixes the deprecation warning for the allocator stuff:

 commit 048d256041a68d0f4e64ddbb73a6bcf325e6ff17
 Author: Tim-Philipp Müller <tim@centricular.net>
 Date:   Sat Feb 16 16:49:22 2013 +0000

    souphttpsrc: set SOUP_VERSION_{MIN_REQUIRED,MAX_ALLOWED} to suppress deprecations with newer versions
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693911


As I understand it, we should really rewrite the plugin based on the newer API which might also simplify things.
Comment 3 Dan Winship 2013-09-29 22:33:00 UTC
(In reply to comment #2)
> As I understand it, we should really rewrite the plugin based on the newer API
> which might also simplify things.

I suspect "might also simplify things" is a huge understatement. souphttpsrc has to jump through a lot of hoops to turn the old push-based libsoup API into a pull-based API for gstreamer.

In particular, you could completely get rid of all the callbacks and signal handlers and GMainContext/GMainLoop fiddling, and just use synchronous I/O instead. And you don't need to do the chunk allocator stuff, because you can just g_input_stream_read() directly into your buffers, and (assuming you aren't using SSL or compression), that operation shouldn't involve any additional copying of the data (beyond the eventual read(2) call itself).


gst-plugins-good currently requires libsoup >= 2.38 (which was released in March 2012). You would want to require at least 2.40 (from September 2012; the request API existed in 2.38, but it was doing the same hacks souphttpsrc does).

With 2.40, you can #define SOUP_USE_UNSTABLE_REQUEST_API, and use SoupRequester and SoupRequest.

Alternatively, you could bump the requirement to 2.42 (March 2013), and then you don't need a #define, and you can bypass SoupRequest and use soup_session_send() (which takes a SoupMessage and returns a GInputStream).
Comment 4 Thiago Sousa Santos 2016-05-14 10:34:18 UTC
Created attachment 327866 [details] [review]
Port soup to use sync API

Still needs some more testing but the code flow looks much simpler
Comment 5 Thiago Sousa Santos 2016-05-14 11:45:09 UTC
gst-validate and unit tests still happy after this. Decided to merge as unlikely to get wider testing without landing in master.

souphttpsrc: refactor to use Soup's sync API
    
    Replace the async API with the sync API to remove all the extra mainloop
    and context handling. Currently it blocks reading until 'blocksize'
    bytes are available but that can be improved by using:
    
    https://developer.gnome.org/gio/unstable/GPollableInputStream.html#g-pollable-input-stream-read-nonblocking
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693911
Comment 6 Dan Winship 2016-05-14 14:58:36 UTC
Awesome... skimming the diff I see a few possible problems:

>-          soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
>+          soup_session_new_with_options (SOUP_SESSION_USER_AGENT,

Be sure to read https://developer.gnome.org/libsoup/stable/libsoup-session-porting.html. In particular, you don't need to add a SOUP_TYPE_PROXY_RESOLVER_DEFAULT feature any more, since that's the default behavior (if you don't set SOUP_SESSION_PROXY_URI), and you don't need to add a SOUP_TYPE_CONTENT_DECODER (though you still want to remove the automatically-added one if !src->compress)

(OK, neither of those are actually *problems*, they're just places where the code is doing stuff it doesn't have to do any more.)

>+  src->input_stream =
>+      soup_session_send (src->session, src->msg, src->cancellable, NULL);
>+  gst_soup_http_src_got_headers (src, src->msg);

That won't do the right thing if the message fails or is cancelled before reading the headers. Note that in the old code, "got-headers" wouldn't be emitted in that case and it would go right to "finished". So some of the error checking code that used to be in gst_soup_http_src_finished_cb() needs to happen before you call gst_soup_http_src_got_headers().
Comment 7 Thiago Sousa Santos 2016-05-14 15:00:34 UTC
Thanks for the pointers, will address those till the end of the hackfest (tomorrow).
Comment 8 Thiago Sousa Santos 2016-05-14 15:50:22 UTC
(In reply to Dan Winship from comment #6)
> Awesome... skimming the diff I see a few possible problems:
> 
> >-          soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
> >+          soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
> 
> Be sure to read
> https://developer.gnome.org/libsoup/stable/libsoup-session-porting.html. In
> particular, you don't need to add a SOUP_TYPE_PROXY_RESOLVER_DEFAULT feature
> any more, since that's the default behavior (if you don't set
> SOUP_SESSION_PROXY_URI), and you don't need to add a
> SOUP_TYPE_CONTENT_DECODER (though you still want to remove the
> automatically-added one if !src->compress)

Removed the proxy entry but kept the compress as it was already being explicit about the choice, even though !compress was the default before.

> 
> (OK, neither of those are actually *problems*, they're just places where the
> code is doing stuff it doesn't have to do any more.)
> 
> >+  src->input_stream =
> >+      soup_session_send (src->session, src->msg, src->cancellable, NULL);
> >+  gst_soup_http_src_got_headers (src, src->msg);
> 
> That won't do the right thing if the message fails or is cancelled before
> reading the headers. Note that in the old code, "got-headers" wouldn't be
> emitted in that case and it would go right to "finished". So some of the
> error checking code that used to be in gst_soup_http_src_finished_cb() needs
> to happen before you call gst_soup_http_src_got_headers().

Added some code to handle the cancellation, but what exactly happens when the message fails before the headers? I'm guessing no GInputStream is created there. So we should only parse the headers if we got a GInputStream?

Will also look at the other changes in that porting document.
Comment 9 Dan Winship 2016-05-16 12:45:21 UTC
(In reply to Thiago Sousa Santos from comment #8)
> Added some code to handle the cancellation, but what exactly happens when
> the message fails before the headers? I'm guessing no GInputStream is
> created there. So we should only parse the headers if we got a GInputStream?

right
Comment 10 Carlos Rafael Giani 2016-05-30 09:21:24 UTC
This is introducing a race condition. This command line freezes when it tries to reach the PAUSED state:

  gst-launch-1.0 souphttpsrc location=http://<some-stream> ! fakesink

With 1.8.0 this always works. Reverting the commits above also fixes it (thanks slomo :) ).

I'll attach a backtrace.
Comment 11 Carlos Rafael Giani 2016-05-30 09:22:03 UTC
Created attachment 328713 [details]
Backtrace when souphttpsrc hangs
Comment 12 Thiago Sousa Santos 2016-05-30 14:39:01 UTC
(In reply to Carlos Rafael Giani from comment #11)
> Created attachment 328713 [details]
> Backtrace when souphttpsrc hangs

This looks like that glib/dconf initialization issue, we eliminated it in the tests with 8e2c1d1de56bddbff22170f8b17473882e0e63f9 but I guess it can happen with gst-launch itself.

Could you try getting another backtrace with dconf and libsoup symbols so we have the full stack?
Comment 13 Carlos Rafael Giani 2016-06-01 10:03:37 UTC
Created attachment 328870 [details]
updated backtrace

Here's the new backtrace. Unfortunately, in Ubuntu 16.04 there doesn't seem to be a dconf-gsettings-backend debug package, so I couldn't get dconf debug symbols. I was able to get symbols for soup though.
Comment 14 Thiago Sousa Santos 2016-06-11 11:40:55 UTC
Funny thing: I tried playing with my glib version by installing it to the uninstalled prefix. Installed master, 2.48.1 (same version as my system) and also installed from the debian source I also have installed in my system.

They all stop hanging after this. When I remove the prefix dir it fails before the 20th run. When installed it runs up to 100 times without an issue.
Comment 15 Sebastian Dröge (slomo) 2016-06-13 06:16:21 UTC
Here it usually happens always when playing a DASH stream, but apparently only for me. Not sure what to do about this one, Carlos' backtrace looks like it is a race during g_socket_get_type(), which should all be guarded by g_once_init_*()... and which is apparently causing the deadlock?

It doesn't look like fork() is involved here, why would gst-launch create a new process (other than for the plugin scanner)?
Comment 16 Dan Winship 2016-06-13 12:39:50 UTC
(In reply to Sebastian Dröge (slomo) from comment #15)
> Here it usually happens always when playing a DASH stream, but apparently
> only for me. Not sure what to do about this one, Carlos' backtrace looks
> like it is a race during g_socket_get_type(), which should all be guarded by
> g_once_init_*()... and which is apparently causing the deadlock?

sounds like probably bug 674885; the workaround is to manually g_ensure_type() the types earlier on so they don't both get initialized at the same time in different threads
Comment 17 Tim-Philipp Müller 2016-06-13 13:21:30 UTC
Which types though?

This seems to work well enough, any missing?

  g_type_ensure (G_TYPE_SOCKET);
  g_type_ensure (G_TYPE_SOCKET_ADDRESS);
  g_type_ensure (G_TYPE_SOCKET_SERVICE);
  g_type_ensure (G_TYPE_SOCKET_FAMILY);
  g_type_ensure (G_TYPE_SOCKET_CLIENT);
  g_type_ensure (G_TYPE_RESOLVER);
  g_type_ensure (G_TYPE_PROXY_RESOLVER);
  g_type_ensure (G_TYPE_PROXY_ADDRESS);
  g_type_ensure (G_TYPE_TLS_CERTIFICATE);
  g_type_ensure (G_TYPE_TLS_CONNECTION);
  g_type_ensure (G_TYPE_TLS_DATABASE);
  g_type_ensure (G_TYPE_TLS_INTERACTION);

Do we have to do this in all other plugins that use GSocket as well then?
Comment 18 Dan Winship 2016-06-13 13:57:47 UTC
There are only a few cases that cause problems. It's enough to just pre-register one of the types that shows up in the deadlock in the backtrace
Comment 19 Tim-Philipp Müller 2016-06-13 14:18:13 UTC
Ok. I tried just G_TYPE_SOCKET first, that wasn't enough (then it got stuck in SOCKET_ADDRESs) :)
Comment 20 Sebastian Dröge (slomo) 2016-06-13 20:06:16 UTC
Does that mean that the get_type() functions are actually not thread-safe, and g_once_init_enter/leave() is just useless? :)
Comment 21 Dan Winship 2016-06-14 12:30:20 UTC
g_once itself is fine. The problem is a deadlock inside the type machinery that is triggered by certain pairs of types. The referenced bug has the details.
Comment 22 Tim-Philipp Müller 2016-06-17 22:08:19 UTC
Ok, let's close this again and see if it's enough.

commit 33fb50b308481bc31962f0eeba7a38786cf9f55b
Author: Tim-Philipp Müller <tim@centricular.com>
Date:   Fri Jun 17 19:59:13 2016 +0100

    soup: work around frequent deadlocks in GLib type initialisation
    
    .. by registering the types from the plugin init function. This
    seems to help, but we'll see if it's enough (might need similar
    things elsewhere).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693911
    https://bugzilla.gnome.org/show_bug.cgi?id=674885