Changeset 242682 in webkit
- Timestamp:
- Mar 9, 2019 9:43:36 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r242679 r242682 1 2019-03-09 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 REGRESSION (r242551): Sporadic hangs when tapping to change selection on iOS 4 https://bugs.webkit.org/show_bug.cgi?id=195475 5 <rdar://problem/48721153> 6 7 Reviewed by Chris Dumez. 8 9 Add a new layout test that taps to change selection 20 times in a contenteditable area and additionally 10 disables IPC timeout, to ensure that any IPC deadlocks will result in the test failing due to timing out. 11 12 * editing/selection/ios/change-selection-by-tapping-expected.txt: Added. 13 * editing/selection/ios/change-selection-by-tapping.html: Added. 14 1 15 2019-03-09 Zalan Bujtas <zalan@apple.com> 2 16 -
trunk/Source/WebKit/ChangeLog
r242681 r242682 1 2019-03-09 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 REGRESSION (r242551): Sporadic hangs when tapping to change selection on iOS 4 https://bugs.webkit.org/show_bug.cgi?id=195475 5 <rdar://problem/48721153> 6 7 Reviewed by Chris Dumez. 8 9 r242551 refactored synchronous autocorrection context requests to send an async IPC message and then use 10 waitForAndDispatchImmediately, instead of calling sendSync. However, this exposes a couple of existing issues in 11 the implementation of waitForAndDispatchImmediately that causes sporadic IPC deadlocks when changing selection. 12 13 First, passing in InterruptWaitingIfSyncMessageArrives when synchronously waiting for an IPC message currently 14 does not fulfill its intended behavior of interrupting waiting when a sync message arrives. This is because sync 15 IPC messages, by default, may be dispatched while the receiver is waiting for a sync reply. This means that the 16 logic in Connection::SyncMessageState::processIncomingMessage to dispatch an incoming sync message on the main 17 thread will attempt to handle the incoming message by enqueueing it on the main thread, and then waking up the 18 client runloop (i.e. signaling m_waitForSyncReplySemaphore). This works in the case of sendSync since the sync 19 reply semaphore is used to block the main thread, but in the case of waitForAndDispatchImmediately, a different 20 m_waitForMessageCondition is used instead, so SyncMessageState::processIncomingMessage will only enqueue the 21 incoming sync message on the main thread, and not actually invoke it. 22 23 To fix this first issue, observe that there is pre-existing logic to enqueue the incoming message and signal 24 m_waitForMessageCondition in Connection::processIncomingMessage. This codepath is currently not taken because we 25 end up bailing early in the call to SyncMessageState::processIncomingMessage. Instead, we can move this early 26 return further down in the function, such that if there is an incoming sync message and we're waiting with the 27 InterruptWaitingIfSyncMessageArrives option, we will correctly enqueue the incoming message, wake the runloop, 28 and proceed to handle the incoming message. 29 30 The second issue is more subtle; consider the scenario in which we send a sync message A from the web process to 31 the UI process, and simultaneously, in the UI process, we schedule some work to be done on the main thread. 32 Let's additionally suppose that this scheduled work will send an IPC message B to the web process and 33 synchronously wait for a reply (in the case of this particular bug, this is the sync autocorrection context 34 request). What happens upon receiving sync message A is that the IPC thread in the UI process will schedule A on 35 the main thread; however, before the scheduled response to A is invoked, we will first invoke previously 36 scheduled work that attempts to block synchronously until a message B is received. In summary: 37 38 1. (Web process) sends sync IPC message A to UI process. 39 2. (UI process) schedules some main runloop task that will block synchronously on IPC message B. 40 3. (UI process) receives sync IPC message A and schedules A on the main runloop. 41 4. (UI process) carry out the task scheduled in (2) and block on B. 42 43 ...and then, the UI process and web process are now deadlocked because the UI process is waiting for B to 44 arrive, but the web process can't send B because it's waiting for a reply for IPC message A! To fix this second 45 deadlock, we first make an important observation: when using sendSync, we don't run into this problem because 46 immediately before sending sync IPC, we will attempt to handle any incoming sync IPC messages that have been 47 queued up. However, when calling waitForAndDispatchImmediately, we don't have this extra step, so a deadlock may 48 occur in the manner described above. To fix this, we make waitForAndDispatchImmediately behave more like 49 sendSync, by handling all incoming sync messages prior to blocking on an IPC response. 50 51 Test: editing/selection/ios/change-selection-by-tapping.html 52 53 * Platform/IPC/Connection.cpp: 54 (IPC::Connection::waitForMessage): 55 (IPC::Connection::processIncomingMessage): 56 1 57 2019-03-09 Andy Estes <aestes@apple.com> 2 58 -
trunk/Source/WebKit/Platform/IPC/Connection.cpp
r240661 r242682 515 515 // Now wait for it to be set. 516 516 while (true) { 517 // Handle any messages that are blocked on a response from us. 518 SyncMessageState::singleton().dispatchMessages(nullptr); 519 517 520 std::unique_lock<Lock> lock(m_waitForMessageMutex); 518 521 … … 723 726 } 724 727 725 // Check if this is a sync message or if it's a message that should be dispatched even when waiting for 726 // a sync reply. If it is, and we're waiting for a sync reply this message needs to be dispatched. 727 // If we don't we'll end up with a deadlock where both sync message senders are stuck waiting for a reply. 728 if (SyncMessageState::singleton().processIncomingMessage(*this, message)) 729 return; 730 731 // Check if we're waiting for this message. 728 // Check if we're waiting for this message, or if we need to interrupt waiting due to an incoming sync message. 732 729 { 733 730 std::lock_guard<Lock> lock(m_waitForMessageMutex); … … 744 741 m_waitingForMessage->messageWaitingInterrupted = true; 745 742 m_waitForMessageCondition.notifyOne(); 743 enqueueIncomingMessage(WTFMove(message)); 744 return; 746 745 } 747 746 } 748 747 } 748 749 // Check if this is a sync message or if it's a message that should be dispatched even when waiting for 750 // a sync reply. If it is, and we're waiting for a sync reply this message needs to be dispatched. 751 // If we don't we'll end up with a deadlock where both sync message senders are stuck waiting for a reply. 752 if (SyncMessageState::singleton().processIncomingMessage(*this, message)) 753 return; 749 754 750 755 enqueueIncomingMessage(WTFMove(message));
Note: See TracChangeset
for help on using the changeset viewer.