Title: [225635] trunk/Source/WebCore
Revision
225635
Author
[email protected]
Date
2017-12-07 11:25:35 -0800 (Thu, 07 Dec 2017)

Log Message

[EME] Possible deadlock when aborting a SourceBufferPrivateAVFObjC append operation
https://bugs.webkit.org/show_bug.cgi?id=180486

Reviewed by Eric Carlson.

It's possible that an abort() operation which is blocked on the ongoing appendBuffer()
operation completing will deadlock forever, with either the willProvideContentKeyRequest
or didProvideContentKeyRequest callbacks blocking waiting to be run on the main thread
(which is itself blocked waiting for the append operation to complete).

To break this deadlock, add a new abortSemaphore which is signaled in the abort() method
and have the willProvide... and didProvide... methods block both on their own semaphores
as well as the abortSemaphore, allowing them to break out even if their main thread calls
never get a chance to execute.

* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(-[WebAVStreamDataParserListener streamDataParserWillProvideContentKeyRequestInitializationData:forTrackID:]):
(-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID:]):
(WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
(WebCore::SourceBufferPrivateAVFObjC::abort):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (225634 => 225635)


--- trunk/Source/WebCore/ChangeLog	2017-12-07 19:06:17 UTC (rev 225634)
+++ trunk/Source/WebCore/ChangeLog	2017-12-07 19:25:35 UTC (rev 225635)
@@ -1,3 +1,26 @@
+2017-12-07  Jer Noble  <[email protected]>
+
+        [EME] Possible deadlock when aborting a SourceBufferPrivateAVFObjC append operation
+        https://bugs.webkit.org/show_bug.cgi?id=180486
+
+        Reviewed by Eric Carlson.
+
+        It's possible that an abort() operation which is blocked on the ongoing appendBuffer()
+        operation completing will deadlock forever, with either the willProvideContentKeyRequest
+        or didProvideContentKeyRequest callbacks blocking waiting to be run on the main thread
+        (which is itself blocked waiting for the append operation to complete).
+
+        To break this deadlock, add a new abortSemaphore which is signaled in the abort() method
+        and have the willProvide... and didProvide... methods block both on their own semaphores
+        as well as the abortSemaphore, allowing them to break out even if their main thread calls
+        never get a chance to execute.
+
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (-[WebAVStreamDataParserListener streamDataParserWillProvideContentKeyRequestInitializationData:forTrackID:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID:]):
+        (WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
+        (WebCore::SourceBufferPrivateAVFObjC::abort):
+
 2017-12-07  Eric Carlson  <[email protected]>
 
         Simplify log channel configuration UI

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (225634 => 225635)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2017-12-07 19:06:17 UTC (rev 225634)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2017-12-07 19:25:35 UTC (rev 225635)
@@ -108,9 +108,11 @@
 
 @interface WebAVStreamDataParserListener : NSObject<AVStreamDataParserOutputHandling> {
     WeakPtr<WebCore::SourceBufferPrivateAVFObjC> _parent;
+    OSObjectPtr<dispatch_semaphore_t> _abortSemaphore;
     AVStreamDataParser* _parser;
 }
 @property (assign) WeakPtr<WebCore::SourceBufferPrivateAVFObjC> parent;
+@property (assign) OSObjectPtr<dispatch_semaphore_t> abortSemaphore;
 - (id)initWithParser:(AVStreamDataParser*)parser parent:(WeakPtr<WebCore::SourceBufferPrivateAVFObjC>)parent;
 @end
 
@@ -129,6 +131,7 @@
 }
 
 @synthesize parent=_parent;
+@synthesize abortSemaphore=_abortSemaphore;
 
 - (void)dealloc
 {
@@ -203,10 +206,22 @@
 
     // We must call synchronously to the main thread, as the AVStreamSession must be associated
     // with the streamDataParser before the delegate method returns.
-    dispatch_sync(dispatch_get_main_queue(), [parent = _parent, trackID]() {
+    OSObjectPtr<dispatch_semaphore_t> respondedSemaphore = adoptOSObject(dispatch_semaphore_create(0));
+    callOnMainThread([parent = _parent, trackID, respondedSemaphore]() {
         if (parent)
             parent->willProvideContentKeyRequestInitializationDataForTrackID(trackID);
+        dispatch_semaphore_signal(respondedSemaphore.get());
     });
+
+    while (true) {
+        if (!dispatch_semaphore_wait(respondedSemaphore.get(), dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * 100)))
+            return;
+
+        if (!dispatch_semaphore_wait(_abortSemaphore.get(), dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * 100))) {
+            dispatch_semaphore_signal(_abortSemaphore.get());
+            return;
+        }
+    }
 }
 
 - (void)streamDataParser:(AVStreamDataParser *)streamDataParser didProvideContentKeyRequestInitializationData:(NSData *)initData forTrackID:(CMPersistentTrackID)trackID
@@ -218,7 +233,16 @@
         if (parent)
             parent->didProvideContentKeyRequestInitializationDataForTrackID(protectedInitData.get(), trackID, hasSessionSemaphore);
     });
-    dispatch_semaphore_wait(hasSessionSemaphore.get(), DISPATCH_TIME_FOREVER);
+
+    while (true) {
+        if (!dispatch_semaphore_wait(hasSessionSemaphore.get(), dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * 100)))
+            return;
+
+        if (!dispatch_semaphore_wait(_abortSemaphore.get(), dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * 100))) {
+            dispatch_semaphore_signal(_abortSemaphore.get());
+            return;
+        }
+    }
 }
 @end
 
@@ -487,6 +511,7 @@
     , m_mediaSource(parent)
 {
     CMNotificationCenterAddListener(CMNotificationCenterGetDefaultLocalCenter(), this, bufferWasConsumedCallback, kCMSampleBufferConsumerNotification_BufferConsumed, nullptr, 0);
+    m_delegate.get().abortSemaphore = adoptOSObject(dispatch_semaphore_create(0));
 }
 
 SourceBufferPrivateAVFObjC::~SourceBufferPrivateAVFObjC()
@@ -713,9 +738,11 @@
     // semaphore, the m_isAppendingGroup wait operation will deadlock.
     if (m_hasSessionSemaphore)
         dispatch_semaphore_signal(m_hasSessionSemaphore.get());
+    dispatch_semaphore_signal(m_delegate.get().abortSemaphore.get());
     dispatch_group_wait(m_isAppendingGroup.get(), DISPATCH_TIME_FOREVER);
     m_appendWeakFactory.revokeAll();
     m_delegate.get().parent = m_appendWeakFactory.createWeakPtr(*this);
+    m_delegate.get().abortSemaphore = adoptOSObject(dispatch_semaphore_create(0));
 }
 
 void SourceBufferPrivateAVFObjC::resetParserState()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to