diff options
Diffstat (limited to 'components/constellation/constellation.rs')
-rw-r--r-- | components/constellation/constellation.rs | 171 |
1 files changed, 73 insertions, 98 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 2f9345c416f..ad89c435717 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -115,9 +115,10 @@ use constellation_traits::{ AuxiliaryWebViewCreationRequest, AuxiliaryWebViewCreationResponse, BroadcastMsg, DocumentState, EmbedderToConstellationMessage, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, IFrameSizeMsg, Job, LoadData, LoadOrigin, LogEntry, MessagePortMsg, NavigationHistoryBehavior, - PaintMetricEvent, PortMessageTask, SWManagerMsg, SWManagerSenders, ScriptToConstellationChan, - ScriptToConstellationMessage, ScrollState, ServiceWorkerManagerFactory, ServiceWorkerMsg, - StructuredSerializedData, TraversalDirection, WindowSizeType, + PaintMetricEvent, PortMessageTask, PortTransferInfo, SWManagerMsg, SWManagerSenders, + ScriptToConstellationChan, ScriptToConstellationMessage, ScrollState, + ServiceWorkerManagerFactory, ServiceWorkerMsg, StructuredSerializedData, TraversalDirection, + WindowSizeType, }; use crossbeam_channel::{Receiver, Select, Sender, unbounded}; use devtools_traits::{ @@ -202,9 +203,6 @@ enum TransferState { /// While a completion failed, another global requested to complete the transfer. /// We are still buffering messages, and awaiting the return of the buffer from the global who failed. CompletionRequested(MessagePortRouterId, VecDeque<PortMessageTask>), - /// The entangled port has been removed while the port was in-transfer, - /// the current port should be removed as well once it is managed again. - EntangledRemoved, } #[derive(Debug)] @@ -1524,12 +1522,12 @@ where ScriptToConstellationMessage::NewMessagePort(router_id, port_id) => { self.handle_new_messageport(router_id, port_id); }, - ScriptToConstellationMessage::RemoveMessagePort(port_id) => { - self.handle_remove_messageport(port_id); - }, ScriptToConstellationMessage::EntanglePorts(port1, port2) => { self.handle_entangle_messageports(port1, port2); }, + ScriptToConstellationMessage::DisentanglePorts(port1, port2) => { + self.handle_disentangle_messageports(port1, port2); + }, ScriptToConstellationMessage::NewBroadcastChannelRouter( router_id, response_sender, @@ -2117,17 +2115,6 @@ where Entry::Occupied(entry) => entry, }; match entry.get().state { - TransferState::EntangledRemoved => { - // If the entangled port has been removed while this one was in-transfer, - // remove it now. - if let Some(ipc_sender) = self.message_port_routers.get(&router_id) { - let _ = ipc_sender.send(MessagePortMsg::RemoveMessagePort(port_id)); - } else { - warn!("No message-port sender for {:?}", router_id); - } - entry.remove_entry(); - continue; - }, TransferState::CompletionInProgress(expected_router_id) => { // Here, the transfer was normally completed. @@ -2151,9 +2138,9 @@ where fn handle_message_port_transfer_failed( &mut self, - ports: HashMap<MessagePortId, VecDeque<PortMessageTask>>, + ports: HashMap<MessagePortId, PortTransferInfo>, ) { - for (port_id, mut previous_buffer) in ports.into_iter() { + for (port_id, mut transfer_info) in ports.into_iter() { let entry = match self.message_ports.remove(&port_id) { None => { warn!( @@ -2165,11 +2152,6 @@ where Some(entry) => entry, }; let new_info = match entry.state { - TransferState::EntangledRemoved => { - // If the entangled port has been removed while this one was in-transfer, - // just drop it. - continue; - }, TransferState::CompletionFailed(mut current_buffer) => { // The transfer failed, // and now the global has returned us the buffer we previously sent. @@ -2177,7 +2159,7 @@ where // Tasks in the previous buffer are older, // hence need to be added to the front of the current one. - while let Some(task) = previous_buffer.pop_back() { + while let Some(task) = transfer_info.port_message_queue.pop_back() { current_buffer.push_front(task); } // Update the state to transfer-in-progress. @@ -2196,7 +2178,7 @@ where // Tasks in the previous buffer are older, // hence need to be added to the front of the current one. - while let Some(task) = previous_buffer.pop_back() { + while let Some(task) = transfer_info.port_message_queue.pop_back() { current_buffer.push_front(task); } // Forward the buffered message-queue to complete the current transfer. @@ -2204,7 +2186,10 @@ where if ipc_sender .send(MessagePortMsg::CompletePendingTransfer( port_id, - current_buffer, + PortTransferInfo { + port_message_queue: current_buffer, + disentangled: entry.entangled_with.is_none(), + }, )) .is_err() { @@ -2251,18 +2236,14 @@ where Some(entry) => entry, }; let new_info = match entry.state { - TransferState::EntangledRemoved => { - // If the entangled port has been removed while this one was in-transfer, - // remove it now. - if let Some(ipc_sender) = self.message_port_routers.get(&router_id) { - let _ = ipc_sender.send(MessagePortMsg::RemoveMessagePort(port_id)); - } else { - warn!("No message-port sender for {:?}", router_id); - } - continue; - }, TransferState::TransferInProgress(buffer) => { - response.insert(port_id, buffer); + response.insert( + port_id, + PortTransferInfo { + port_message_queue: buffer, + disentangled: entry.entangled_with.is_none(), + }, + ); // If the port was in transfer, and a global is requesting completion, // we note the start of the completion. @@ -2341,10 +2322,6 @@ where TransferState::TransferInProgress(queue) => queue.push_back(task), TransferState::CompletionFailed(queue) => queue.push_back(task), TransferState::CompletionRequested(_, queue) => queue.push_back(task), - TransferState::EntangledRemoved => warn!( - "Messageport received a message, but entangled has alread been removed {:?}", - port_id - ), } } @@ -2410,59 +2387,6 @@ where feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") )] - fn handle_remove_messageport(&mut self, port_id: MessagePortId) { - let entangled = match self.message_ports.remove(&port_id) { - Some(info) => info.entangled_with, - None => { - return warn!( - "Constellation asked to remove unknown messageport {:?}", - port_id - ); - }, - }; - let entangled_id = match entangled { - Some(id) => id, - None => return, - }; - let info = match self.message_ports.get_mut(&entangled_id) { - Some(info) => info, - None => { - return warn!( - "Constellation asked to remove unknown entangled messageport {:?}", - entangled_id - ); - }, - }; - let router_id = match info.state { - TransferState::EntangledRemoved => { - return warn!( - "Constellation asked to remove entangled messageport by a port that was already removed {:?}", - port_id - ); - }, - TransferState::TransferInProgress(_) | - TransferState::CompletionInProgress(_) | - TransferState::CompletionFailed(_) | - TransferState::CompletionRequested(_, _) => { - // Note: since the port is in-transer, we don't have a router to send it a message - // to let it know that its entangled port has been removed. - // Hence we mark it so that it will be messaged and removed once the transfer completes. - info.state = TransferState::EntangledRemoved; - return; - }, - TransferState::Managed(router_id) => router_id, - }; - if let Some(sender) = self.message_port_routers.get(&router_id) { - let _ = sender.send(MessagePortMsg::RemoveMessagePort(entangled_id)); - } else { - warn!("No message-port sender for {:?}", router_id); - } - } - - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") - )] fn handle_entangle_messageports(&mut self, port1: MessagePortId, port2: MessagePortId) { if let Some(info) = self.message_ports.get_mut(&port1) { info.entangled_with = Some(port2); @@ -2482,6 +2406,57 @@ where } } + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") + )] + /// <https://html.spec.whatwg.org/multipage/#disentangle> + fn handle_disentangle_messageports( + &mut self, + port1: MessagePortId, + port2: Option<MessagePortId>, + ) { + // Disentangle initiatorPort and otherPort, + // so that they are no longer entangled or associated with each other. + // Note: If `port2` is some, then this is the first message + // and `port1` is the initiatorPort, `port2` is the otherPort. + // We can immediately remove the initiator. + let _ = self.message_ports.remove(&port1); + + // Note: the none case is when otherPort sent this message + // in response to completing its own local disentanglement. + let Some(port2) = port2 else { + return; + }; + + // Start disentanglement of the other port. + if let Some(info) = self.message_ports.get_mut(&port2) { + info.entangled_with = None; + match &mut info.state { + TransferState::Managed(router_id) | + TransferState::CompletionInProgress(router_id) => { + // We try to disentangle the other port now, + // and if it has been transfered out by the time the message is received, + // it will be ignored, + // and disentanglement will be completed as part of the transfer. + if let Some(ipc_sender) = self.message_port_routers.get(router_id) { + let _ = ipc_sender.send(MessagePortMsg::CompleteDisentanglement(port2)); + } else { + warn!("No message-port sender for {:?}", router_id); + } + }, + _ => { + // Note: the port is in transfer, disentanglement will complete along with it. + }, + } + } else { + warn!( + "Constellation asked to disentangle unknown messageport: {:?}", + port2 + ); + } + } + /// <https://w3c.github.io/ServiceWorker/#schedule-job-algorithm> /// and /// <https://w3c.github.io/ServiceWorker/#dfn-job-queue> |