Changeset 202615 in webkit
- Timestamp:
- Jun 28, 2016 11:33:57 PM (8 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r202614 r202615 1 2016-06-28 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GStreamer] Adaptive streaming issues 4 https://bugs.webkit.org/show_bug.cgi?id=144040 5 6 Reviewed by Philippe Normand. 7 8 There are multiple deadlocks in the web process when HLS content is loaded by GStreamer. It happens because gst 9 is using several threads to download manifest, fragments, monitor the downloads, etc. To download the fragments 10 and manifest it always creates the source element in a separate thread, something that is not actually expected 11 to happen in WebKit source element. Our source element is always scheduling tasks (start, stop, need-data, 12 enough-data and seek) to the main thread, and those downloads that use the ResourceHandleStreamingClient 13 (there's no player associated) also happen in the main thread, because libsoup calls all its async callbacks in 14 the main thread. So, the result is that it can happen that we end up blocking the main thread in a lock until 15 the download finishes, but the download never finishes because tasks are scheduled in the main thread that is 16 blocked in a lock. This can be prevented by always using a secondary thread for downloads made by 17 ResourceHandleStreamingClient, using its own run loop with a different GMainContext so that libsoup sends 18 callbacks to the right thread. We also had to refactor the tasks a bit, leaving the thread safe parts to be run 19 in the calling thread always, and only scheduling to the main thread in case of not using 20 ResourceHandleStreamingClient and only for the non thread safe parts. 21 This patch also includes r200455 that was rolled out, but it was a perfectly valid workaround for GST bug. 22 23 * platform/graphics/gstreamer/GRefPtrGStreamer.cpp: 24 (WTF::ensureGRef): Consume the floating ref if needed. 25 * platform/graphics/gstreamer/GRefPtrGStreamer.h: 26 * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: 27 (webkit_web_src_init): Check if object is being created in the main thread. 28 (webKitWebSrcStop): Stop the media resource loader in the main thread and the resource handle streaming in the 29 current thread. 30 (webKitWebSrcStart): Start the media resource loader in the main thread and the resource handle streaming in 31 the current thread. 32 (webKitWebSrcChangeState): Call webKitWebSrcStart and webKitWebSrcStop in the current thread. 33 (webKitWebSrcNeedData): Update status in the current thread and notify the media resource loader in the main thread. 34 (webKitWebSrcEnoughData): Ditto. 35 (webKitWebSrcSeek): Ditto. 36 (webKitWebSrcSetMediaPlayer): Add an assert to ensure that source elements used by WebKit are always created in 37 the main thread. 38 (ResourceHandleStreamingClient::ResourceHandleStreamingClient): Use a secondary thread to do the download. 39 (ResourceHandleStreamingClient::~ResourceHandleStreamingClient): Stop the secondary thread. 40 (ResourceHandleStreamingClient::setDefersLoading): Notify the secondary thread. 41 1 42 2016-06-28 Youenn Fablet <youennf@gmail.com> 2 43 -
trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp
r202050 r202615 343 343 } 344 344 345 // This method is only available for WebKitWebSrc and should not be used for any other type. 346 // This is only to work around a bug in GST where the URI downloader is not taking the ownership of WebKitWebSrc. 347 // See https://bugs.webkit.org/show_bug.cgi?id=144040. 348 GRefPtr<WebKitWebSrc> ensureGRef(WebKitWebSrc* ptr) 349 { 350 if (ptr && g_object_is_floating(ptr)) 351 gst_object_ref_sink(GST_OBJECT(ptr)); 352 return GRefPtr<WebKitWebSrc>(ptr); 353 } 354 345 355 template <> WebKitWebSrc* refGPtr<WebKitWebSrc>(WebKitWebSrc* ptr) 346 356 { -
trunk/Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h
r202050 r202615 109 109 110 110 template<> GRefPtr<WebKitWebSrc> adoptGRef(WebKitWebSrc* ptr); 111 GRefPtr<WebKitWebSrc> ensureGRef(WebKitWebSrc* ptr); 111 112 template<> WebKitWebSrc* refGPtr<WebKitWebSrc>(WebKitWebSrc* ptr); 112 113 template<> void derefGPtr<WebKitWebSrc>(WebKitWebSrc* ptr); -
trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
r202556 r202615 84 84 WTF_MAKE_NONCOPYABLE(ResourceHandleStreamingClient); WTF_MAKE_FAST_ALLOCATED; 85 85 public: 86 ResourceHandleStreamingClient(WebKitWebSrc*, const ResourceRequest&);86 ResourceHandleStreamingClient(WebKitWebSrc*, ResourceRequest&&); 87 87 virtual ~ResourceHandleStreamingClient(); 88 88 … … 105 105 void cannotShowURL(ResourceHandle*) override; 106 106 107 ThreadIdentifier m_thread { 0 }; 108 Lock m_initializeRunLoopConditionMutex; 109 Condition m_initializeRunLoopCondition; 110 RunLoop* m_runLoop { nullptr }; 111 Lock m_terminateRunLoopConditionMutex; 112 Condition m_terminateRunLoopCondition; 107 113 RefPtr<ResourceHandle> m_resource; 108 114 }; … … 130 136 RefPtr<PlatformMediaResourceLoader> loader; 131 137 RefPtr<PlatformMediaResource> resource; 132 ResourceHandleStreamingClient*client;138 std::unique_ptr<ResourceHandleStreamingClient> client; 133 139 134 140 bool didPassAccessControlCheck; … … 137 143 guint64 size; 138 144 gboolean seekable; 139 gbooleanpaused;145 bool paused; 140 146 bool isSeeking; 141 147 142 148 guint64 requestedOffset; 143 149 150 bool createdInMainThread; 144 151 MainThreadNotifier<MainThreadSourceNotification> notifier; 145 152 GRefPtr<GstBuffer> buffer; … … 175 182 static void webKitWebSrcNeedData(WebKitWebSrc*); 176 183 static void webKitWebSrcEnoughData(WebKitWebSrc*); 177 static void webKitWebSrcSeek(WebKitWebSrc*);184 static gboolean webKitWebSrcSeek(WebKitWebSrc*, guint64); 178 185 179 186 static GstAppSrcCallbacks appsrcCallbacks = { 180 187 // need_data 181 188 [](GstAppSrc*, guint, gpointer userData) { 182 WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); 183 WebKitWebSrcPrivate* priv = src->priv; 184 185 { 186 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 187 if (!priv->paused) 188 return; 189 } 190 191 GRefPtr<WebKitWebSrc> protector(src); 192 priv->notifier.notify(MainThreadSourceNotification::NeedData, [protector] { webKitWebSrcNeedData(protector.get()); }); 189 webKitWebSrcNeedData(WEBKIT_WEB_SRC(userData)); 193 190 }, 194 191 // enough_data 195 192 [](GstAppSrc*, gpointer userData) { 196 WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); 197 WebKitWebSrcPrivate* priv = src->priv; 198 199 { 200 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 201 if (priv->paused) 202 return; 203 } 204 205 GRefPtr<WebKitWebSrc> protector(src); 206 priv->notifier.notify(MainThreadSourceNotification::EnoughData, [protector] { webKitWebSrcEnoughData(protector.get()); }); 193 webKitWebSrcEnoughData(WEBKIT_WEB_SRC(userData)); 207 194 }, 208 195 // seek_data 209 196 [](GstAppSrc*, guint64 offset, gpointer userData) -> gboolean { 210 WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); 211 WebKitWebSrcPrivate* priv = src->priv; 212 213 { 214 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 215 if (offset == priv->offset && priv->requestedOffset == priv->offset) 216 return TRUE; 217 218 if (!priv->seekable) 219 return FALSE; 220 221 priv->isSeeking = true; 222 priv->requestedOffset = offset; 223 } 224 225 GRefPtr<WebKitWebSrc> protector(src); 226 priv->notifier.notify(MainThreadSourceNotification::Seek, [protector] { webKitWebSrcSeek(protector.get()); }); 227 return TRUE; 197 return webKitWebSrcSeek(WEBKIT_WEB_SRC(userData), offset); 228 198 }, 229 199 { nullptr } … … 289 259 src->priv = priv; 290 260 new (priv) WebKitWebSrcPrivate(); 261 262 priv->createdInMainThread = isMainThread(); 291 263 292 264 priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0)); … … 415 387 WebKitWebSrcPrivate* priv = src->priv; 416 388 417 ASSERT(isMainThread()); 389 if (priv->resource || (priv->loader && !priv->keepAlive)) { 390 GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); 391 priv->notifier.cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek); 392 priv->notifier.notify(MainThreadSourceNotification::Stop, [protector, keepAlive = priv->keepAlive] { 393 WebKitWebSrcPrivate* priv = protector->priv; 394 395 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(protector.get())); 396 if (priv->resource) { 397 priv->resource->stop(); 398 priv->resource->setClient(nullptr); 399 priv->resource = nullptr; 400 } 401 402 if (!keepAlive) 403 priv->loader = nullptr; 404 }); 405 } 418 406 419 407 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); … … 421 409 bool wasSeeking = std::exchange(priv->isSeeking, false); 422 410 423 priv->notifier.cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek); 424 425 if (priv->client) { 426 delete priv->client; 427 priv->client = 0; 428 } 429 430 if (!priv->keepAlive) 431 priv->loader = nullptr; 411 priv->client = nullptr; 432 412 433 413 if (priv->buffer) { … … 436 416 } 437 417 438 priv->paused = FALSE;418 priv->paused = false; 439 419 440 420 priv->offset = 0; … … 512 492 { 513 493 WebKitWebSrcPrivate* priv = src->priv; 514 515 ASSERT(isMainThread());516 494 517 495 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); … … 579 557 request.setHTTPHeaderField(HTTPHeaderName::IcyMetadata, "1"); 580 558 581 bool loadFailed = true; 582 if (priv->player && !priv->loader) 583 priv->loader = priv->player->createResourceLoader(); 584 585 if (priv->loader) { 559 if (!priv->player || !priv->createdInMainThread) { 560 priv->client = std::make_unique<ResourceHandleStreamingClient>(src, WTFMove(request)); 561 if (priv->client->loadFailed()) { 562 GST_ERROR_OBJECT(src, "Failed to setup streaming client"); 563 priv->client = nullptr; 564 locker.unlock(); 565 webKitWebSrcStop(src); 566 } else 567 GST_DEBUG_OBJECT(src, "Started request"); 568 return; 569 } 570 571 locker.unlock(); 572 GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); 573 priv->notifier.notify(MainThreadSourceNotification::Start, [protector, request = WTFMove(request)] { 574 WebKitWebSrcPrivate* priv = protector->priv; 575 576 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(protector.get())); 577 if (!priv->loader) 578 priv->loader = priv->player->createResourceLoader(); 579 586 580 PlatformMediaResourceLoader::LoadOptions loadOptions = 0; 587 581 if (request.url().protocolIsBlob()) 588 582 loadOptions |= PlatformMediaResourceLoader::LoadOption::BufferData; 589 583 priv->resource = priv->loader->requestResource(request, loadOptions); 590 loadFailed = !priv->resource; 591 592 if (priv->resource) 593 priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(src)); 594 } else { 595 priv->client = new ResourceHandleStreamingClient(src, request); 596 loadFailed = priv->client->loadFailed(); 597 } 598 599 if (loadFailed) { 600 GST_ERROR_OBJECT(src, "Failed to setup streaming client"); 601 if (priv->client) { 602 delete priv->client; 603 priv->client = nullptr; 584 if (priv->resource) { 585 priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(protector.get())); 586 GST_DEBUG_OBJECT(protector.get(), "Started request"); 587 } else { 588 GST_ERROR_OBJECT(protector.get(), "Failed to setup streaming client"); 589 priv->loader = nullptr; 590 locker.unlock(); 591 webKitWebSrcStop(protector.get()); 604 592 } 605 priv->loader = nullptr; 606 priv->resource = nullptr; 607 locker.unlock(); 608 webKitWebSrcStop(src); 609 return; 610 } 611 GST_DEBUG_OBJECT(src, "Started request"); 593 }); 612 594 } 613 595 … … 641 623 { 642 624 GST_DEBUG_OBJECT(src, "READY->PAUSED"); 643 GRefPtr<WebKitWebSrc> protector(src); 644 priv->notifier.notify(MainThreadSourceNotification::Start, [protector] { webKitWebSrcStart(protector.get()); }); 625 webKitWebSrcStart(src); 645 626 break; 646 627 } … … 648 629 { 649 630 GST_DEBUG_OBJECT(src, "PAUSED->READY"); 650 priv->notifier.cancelPendingNotifications(); 651 GRefPtr<WebKitWebSrc> protector(src); 652 priv->notifier.notify(MainThreadSourceNotification::Stop, [protector] { webKitWebSrcStop(protector.get()); }); 631 webKitWebSrcStop(src); 653 632 break; 654 633 } … … 782 761 } 783 762 784 // appsrc callbacks785 786 763 static void webKitWebSrcNeedData(WebKitWebSrc* src) 787 764 { 788 765 WebKitWebSrcPrivate* priv = src->priv; 789 790 ASSERT(isMainThread());791 766 792 767 GST_DEBUG_OBJECT(src, "Need more data"); … … 794 769 { 795 770 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 796 priv->paused = FALSE; 797 } 798 799 if (priv->client) 800 priv->client->setDefersLoading(false); 801 if (priv->resource) 802 priv->resource->setDefersLoading(false); 771 if (!priv->paused) 772 return; 773 priv->paused = false; 774 if (priv->client) { 775 priv->client->setDefersLoading(false); 776 return; 777 } 778 } 779 780 GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); 781 priv->notifier.notify(MainThreadSourceNotification::NeedData, [protector] { 782 WebKitWebSrcPrivate* priv = protector->priv; 783 if (priv->resource) 784 priv->resource->setDefersLoading(false); 785 }); 803 786 } 804 787 … … 806 789 { 807 790 WebKitWebSrcPrivate* priv = src->priv; 808 809 ASSERT(isMainThread());810 791 811 792 GST_DEBUG_OBJECT(src, "Have enough data"); … … 813 794 { 814 795 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 815 priv->paused = TRUE; 816 } 817 818 if (priv->client) 819 priv->client->setDefersLoading(true); 820 if (priv->resource) 821 priv->resource->setDefersLoading(true); 822 } 823 824 static void webKitWebSrcSeek(WebKitWebSrc* src) 825 { 826 ASSERT(isMainThread()); 796 if (priv->paused) 797 return; 798 priv->paused = true; 799 if (priv->client) { 800 priv->client->setDefersLoading(true); 801 return; 802 } 803 } 804 805 GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); 806 priv->notifier.notify(MainThreadSourceNotification::EnoughData, [protector] { 807 WebKitWebSrcPrivate* priv = protector->priv; 808 if (priv->resource) 809 priv->resource->setDefersLoading(true); 810 }); 811 } 812 813 static gboolean webKitWebSrcSeek(WebKitWebSrc* src, guint64 offset) 814 { 815 WebKitWebSrcPrivate* priv = src->priv; 816 817 { 818 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 819 if (offset == priv->offset && priv->requestedOffset == priv->offset) 820 return TRUE; 821 822 if (!priv->seekable) 823 return FALSE; 824 825 priv->isSeeking = true; 826 priv->requestedOffset = offset; 827 } 827 828 828 829 GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, src->priv->requestedOffset); 829 830 webKitWebSrcStop(src); 831 webKitWebSrcStart(src); 830 if (priv->client) { 831 webKitWebSrcStop(src); 832 webKitWebSrcStart(src); 833 return TRUE; 834 } 835 836 GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); 837 priv->notifier.notify(MainThreadSourceNotification::Seek, [protector] { 838 webKitWebSrcStop(protector.get()); 839 webKitWebSrcStart(protector.get()); 840 }); 841 return TRUE; 832 842 } 833 843 … … 835 845 { 836 846 ASSERT(player); 847 ASSERT(src->priv->createdInMainThread); 837 848 WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); 838 849 src->priv->player = player; … … 1061 1072 } 1062 1073 1063 ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, const ResourceRequest& request)1074 ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, ResourceRequest&& request) 1064 1075 : StreamingClient(src) 1065 1076 { 1066 m_resource = ResourceHandle::create(0 /*context*/, request, this, false, false); 1077 LockHolder locker(m_initializeRunLoopConditionMutex); 1078 m_thread = createThread("ResourceHandleStreamingClient", [this, request = WTFMove(request)] { 1079 { 1080 LockHolder locker(m_initializeRunLoopConditionMutex); 1081 m_runLoop = &RunLoop::current(); 1082 m_resource = ResourceHandle::create(nullptr /*context*/, request, this, true, false); 1083 m_initializeRunLoopCondition.notifyOne(); 1084 } 1085 if (!m_resource) 1086 return; 1087 1088 m_runLoop->dispatch([this] { m_resource->setDefersLoading(false); }); 1089 m_runLoop->run(); 1090 { 1091 LockHolder locker(m_terminateRunLoopConditionMutex); 1092 m_runLoop = nullptr; 1093 m_resource->clearClient(); 1094 m_resource->cancel(); 1095 m_resource = nullptr; 1096 m_terminateRunLoopCondition.notifyOne(); 1097 } 1098 }); 1099 m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex); 1067 1100 } 1068 1101 1069 1102 ResourceHandleStreamingClient::~ResourceHandleStreamingClient() 1070 1103 { 1071 if (m_resource) { 1072 m_resource->cancel(); 1073 m_resource = nullptr; 1104 if (m_thread) { 1105 detachThread(m_thread); 1106 m_thread = 0; 1107 } 1108 1109 if (m_runLoop == &RunLoop::current()) 1110 m_runLoop->stop(); 1111 else { 1112 LockHolder locker(m_terminateRunLoopConditionMutex); 1113 m_runLoop->stop(); 1114 m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex); 1074 1115 } 1075 1116 } … … 1082 1123 void ResourceHandleStreamingClient::setDefersLoading(bool defers) 1083 1124 { 1084 if (m_resource) 1085 m_resource->setDefersLoading(defers); 1125 m_runLoop->dispatch([this, defers] { 1126 if (m_resource) 1127 m_resource->setDefersLoading(defers); 1128 }); 1086 1129 } 1087 1130
Note: See TracChangeset
for help on using the changeset viewer.