Changeset 285680 in webkit
- Timestamp:
- Nov 11, 2021, 3:41:28 PM (5 years ago)
- Location:
- branches/safari-612.3.6.1-branch/Source/WebCore
- Files:
-
- 3 edited
-
ChangeLog (modified) (1 diff)
-
platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (modified) (2 diffs)
-
platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/safari-612.3.6.1-branch/Source/WebCore/ChangeLog
r285679 r285680 1 2021-11-11 Alan Coon <alancoon@apple.com> 2 3 Cherry-pick r285330. rdar://problem/85004449 4 5 Nested run loops under MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange can cause hang when timeout fires 6 https://bugs.webkit.org/show_bug.cgi?id=232695 7 <rdar://problem/85004449> 8 9 Reviewed by Jer Noble. 10 11 It's possible for MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange 12 to be called re-entrantly, if the RunLoop::run call ends up processing 13 an event that also wants to synchronously update the media image. This 14 can cause a hang: 15 16 1. Enter the outer waitForVideoOutputMediaDataWillChange call. 17 2. Set up the outer timeout timer. 18 3. Call RunLoop::run. 19 3.1. Enter the inner waitForVideoOutputMediaDataWillChange call. 20 3.2. Set up the inner timeout timer. 21 3.3. Call RunLoop::run. 22 3.3.1. Wait for new RunLoop events, and none arrive. 23 3.3.2. The outer timeout timer fires, calling RunLoop::stop. 24 3.4. Return from waitForVideoOutputMediaDataWillChange, cancelling 25 the inner timeout timer. 26 3.5. Wait for more events on the run loop, forever. 27 28 To avoid this, we can set up a single timeout timer, and track the 29 nesting level of our RunLoop::run calls. The innermost RunLoop::run call 30 will finish either by the timer firing (which calls RunLoop::stop) or by 31 the video data updating (which also calls RunLoop::stop, under 32 outputMediaDataWillChange). Either way, once the innermost 33 RunLoop::run call is finished, we know we can stop processing all of 34 the ancestor RunLoop:run calls. 35 36 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h: 37 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: 38 (WebCore::MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange): 39 (WebCore::MediaPlayerPrivateAVFoundationObjC::outputMediaDataWillChange): 40 41 git-svn-id: https://svn.webkit.org/repository/webkit/trunk@285330 268f45cc-cd09-0410-ab3c-d52691b4dbfc 42 43 2021-11-04 Cameron McCormack <heycam@apple.com> 44 45 Nested run loops under MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange can cause hang when timeout fires 46 https://bugs.webkit.org/show_bug.cgi?id=232695 47 <rdar://problem/85004449> 48 49 Reviewed by Jer Noble. 50 51 It's possible for MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange 52 to be called re-entrantly, if the RunLoop::run call ends up processing 53 an event that also wants to synchronously update the media image. This 54 can cause a hang: 55 56 1. Enter the outer waitForVideoOutputMediaDataWillChange call. 57 2. Set up the outer timeout timer. 58 3. Call RunLoop::run. 59 3.1. Enter the inner waitForVideoOutputMediaDataWillChange call. 60 3.2. Set up the inner timeout timer. 61 3.3. Call RunLoop::run. 62 3.3.1. Wait for new RunLoop events, and none arrive. 63 3.3.2. The outer timeout timer fires, calling RunLoop::stop. 64 3.4. Return from waitForVideoOutputMediaDataWillChange, cancelling 65 the inner timeout timer. 66 3.5. Wait for more events on the run loop, forever. 67 68 To avoid this, we can set up a single timeout timer, and track the 69 nesting level of our RunLoop::run calls. The innermost RunLoop::run call 70 will finish either by the timer firing (which calls RunLoop::stop) or by 71 the video data updating (which also calls RunLoop::stop, under 72 outputMediaDataWillChange). Either way, once the innermost 73 RunLoop::run call is finished, we know we can stop processing all of 74 the ancestor RunLoop:run calls. 75 76 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h: 77 * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm: 78 (WebCore::MediaPlayerPrivateAVFoundationObjC::waitForVideoOutputMediaDataWillChange): 79 (WebCore::MediaPlayerPrivateAVFoundationObjC::outputMediaDataWillChange): 80 1 81 2021-11-11 Alan Coon <alancoon@apple.com> 2 82 -
branches/safari-612.3.6.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h
r285517 r285680 420 420 unsigned m_pendingStatusChanges { 0 }; 421 421 int m_cachedItemStatus; 422 int m_runLoopNestingLevel { 0 }; 422 423 MediaPlayer::BufferingPolicy m_bufferingPolicy { MediaPlayer::BufferingPolicy::Default }; 423 424 bool m_cachedLikelyToKeepUp { false }; … … 439 440 bool m_shouldPlayToPlaybackTarget { false }; 440 441 #endif 441 bool m_runningModalPaint { false };442 442 bool m_waitForVideoOutputMediaDataWillChangeTimedOut { false }; 443 443 bool m_haveBeenAskedToPaint { false }; -
branches/safari-612.3.6.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm
r285517 r285680 2564 2564 if (m_waitForVideoOutputMediaDataWillChangeTimedOut) 2565 2565 return; 2566 [m_videoOutput requestNotificationOfMediaDataChangeWithAdvanceInterval:0];2567 2566 2568 2567 // Wait for 1 second. 2569 2568 MonotonicTime start = MonotonicTime::now(); 2570 2569 2571 RunLoop::Timer<MediaPlayerPrivateAVFoundationObjC> timeoutTimer { RunLoop::main(), [] { 2570 std::optional<RunLoop::Timer<MediaPlayerPrivateAVFoundationObjC>> timeoutTimer; 2571 2572 if (!m_runLoopNestingLevel) { 2573 [m_videoOutput requestNotificationOfMediaDataChangeWithAdvanceInterval:0]; 2574 2575 timeoutTimer.emplace(RunLoop::main(), [&] { 2576 RunLoop::main().stop(); 2577 }); 2578 timeoutTimer->startOneShot(1_s); 2579 } 2580 2581 ++m_runLoopNestingLevel; 2582 RunLoop::run(); 2583 --m_runLoopNestingLevel; 2584 2585 if (m_runLoopNestingLevel) { 2572 2586 RunLoop::main().stop(); 2573 } }; 2574 timeoutTimer.startOneShot(1_s); 2575 2576 m_runningModalPaint = true; 2577 RunLoop::run(); 2578 m_runningModalPaint = false; 2579 2580 bool satisfied = timeoutTimer.isActive(); 2587 return; 2588 } 2589 2590 bool satisfied = timeoutTimer->isActive(); 2581 2591 if (!satisfied) { 2582 2592 ERROR_LOG(LOGIDENTIFIER, "timed out"); … … 2588 2598 void MediaPlayerPrivateAVFoundationObjC::outputMediaDataWillChange() 2589 2599 { 2590 if (m_run ningModalPaint)2600 if (m_runLoopNestingLevel) 2591 2601 RunLoop::main().stop(); 2592 2602 }
Note:
See TracChangeset
for help on using the changeset viewer.