mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #8603 - benschulz:timers-clean-up, r=jdm
Timers clean up This PR splits the `ActiveTimers` abstraction into - `OneshotTimers` for scheduling "arbitrary" oneshot timers, such as XHR timeouts, and - `JsTimers`, based on `OneshotTimers`, for scheduling JS timers (`setTimeout`/`setInterval`). The result is mich cleaner and the timer initialization steps now closely resemble the specification. **Notes** - The second and third commit are strictly renames and code rearrangements. - I'm not particularily happy with the `OneshotTimerCallback` enum and its circular dependency with `XHRTimeoutCallback`, but I couldn't come up with anything better. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8603) <!-- Reviewable:end -->
This commit is contained in:
commit
8f278109ce
5 changed files with 371 additions and 277 deletions
|
@ -23,7 +23,7 @@ use net_traits::ResourceThread;
|
|||
use profile_traits::mem;
|
||||
use script_thread::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThread};
|
||||
use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest};
|
||||
use timers::{ScheduledCallback, TimerHandle};
|
||||
use timers::{OneshotTimerCallback, OneshotTimerHandle};
|
||||
use url::Url;
|
||||
|
||||
/// A freely-copyable reference to a rooted global object.
|
||||
|
@ -224,9 +224,9 @@ impl<'a> GlobalRef<'a> {
|
|||
/// Schedule the given `callback` to be invoked after at least `duration` milliseconds have
|
||||
/// passed.
|
||||
pub fn schedule_callback(&self,
|
||||
callback: Box<ScheduledCallback>,
|
||||
callback: OneshotTimerCallback,
|
||||
duration: MsDuration)
|
||||
-> TimerHandle {
|
||||
-> OneshotTimerHandle {
|
||||
match *self {
|
||||
GlobalRef::Window(window) => window.schedule_callback(callback, duration),
|
||||
GlobalRef::Worker(worker) => worker.schedule_callback(callback, duration),
|
||||
|
@ -234,7 +234,7 @@ impl<'a> GlobalRef<'a> {
|
|||
}
|
||||
|
||||
/// Unschedule a previously-scheduled callback.
|
||||
pub fn unschedule_callback(&self, handle: TimerHandle) {
|
||||
pub fn unschedule_callback(&self, handle: OneshotTimerHandle) {
|
||||
match *self {
|
||||
GlobalRef::Window(window) => window.unschedule_callback(handle),
|
||||
GlobalRef::Worker(worker) => worker.unschedule_callback(handle),
|
||||
|
|
|
@ -76,7 +76,7 @@ use style::context::ReflowGoal;
|
|||
use style::error_reporting::ParseErrorReporter;
|
||||
use style::selector_impl::PseudoElement;
|
||||
use time;
|
||||
use timers::{ActiveTimers, IsInterval, ScheduledCallback, TimerCallback, TimerHandle};
|
||||
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback};
|
||||
use url::Url;
|
||||
use util::geometry::{self, MAX_RECT};
|
||||
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||
|
@ -149,7 +149,7 @@ pub struct Window {
|
|||
local_storage: MutNullableHeap<JS<Storage>>,
|
||||
#[ignore_heap_size_of = "channels are hard"]
|
||||
scheduler_chan: IpcSender<TimerEventRequest>,
|
||||
timers: ActiveTimers,
|
||||
timers: OneshotTimers,
|
||||
|
||||
next_worker_id: Cell<WorkerId>,
|
||||
|
||||
|
@ -466,7 +466,8 @@ impl WindowMethods for Window {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
|
||||
fn SetTimeout(&self, _cx: *mut JSContext, callback: Rc<Function>, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::FunctionTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Window(self),
|
||||
TimerCallback::FunctionTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::NonInterval,
|
||||
|
@ -475,7 +476,8 @@ impl WindowMethods for Window {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
|
||||
fn SetTimeout_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::StringTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Window(self),
|
||||
TimerCallback::StringTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::NonInterval,
|
||||
|
@ -484,12 +486,13 @@ impl WindowMethods for Window {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-cleartimeout
|
||||
fn ClearTimeout(&self, handle: i32) {
|
||||
self.timers.clear_timeout_or_interval(handle);
|
||||
self.timers.clear_timeout_or_interval(GlobalRef::Window(self), handle);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetInterval(&self, _cx: *mut JSContext, callback: Rc<Function>, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::FunctionTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Window(self),
|
||||
TimerCallback::FunctionTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::Interval,
|
||||
|
@ -498,7 +501,8 @@ impl WindowMethods for Window {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetInterval_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::StringTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Window(self),
|
||||
TimerCallback::StringTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::Interval,
|
||||
|
@ -1155,13 +1159,13 @@ impl Window {
|
|||
self.scheduler_chan.clone()
|
||||
}
|
||||
|
||||
pub fn schedule_callback(&self, callback: Box<ScheduledCallback>, duration: MsDuration) -> TimerHandle {
|
||||
pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle {
|
||||
self.timers.schedule_callback(callback,
|
||||
duration,
|
||||
TimerSource::FromWindow(self.id.clone()))
|
||||
}
|
||||
|
||||
pub fn unschedule_callback(&self, handle: TimerHandle) {
|
||||
pub fn unschedule_callback(&self, handle: OneshotTimerHandle) {
|
||||
self.timers.unschedule_callback(handle);
|
||||
}
|
||||
|
||||
|
@ -1349,7 +1353,7 @@ impl Window {
|
|||
session_storage: Default::default(),
|
||||
local_storage: Default::default(),
|
||||
scheduler_chan: scheduler_chan.clone(),
|
||||
timers: ActiveTimers::new(timer_event_chan, scheduler_chan),
|
||||
timers: OneshotTimers::new(timer_event_chan, scheduler_chan),
|
||||
next_worker_id: Cell::new(WorkerId(0)),
|
||||
id: id,
|
||||
parent_info: parent_info,
|
||||
|
|
|
@ -30,7 +30,7 @@ use std::cell::Cell;
|
|||
use std::default::Default;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use timers::{ActiveTimers, IsInterval, ScheduledCallback, TimerCallback, TimerHandle};
|
||||
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback};
|
||||
use url::Url;
|
||||
use util::str::DOMString;
|
||||
|
||||
|
@ -64,7 +64,7 @@ pub struct WorkerGlobalScope {
|
|||
navigator: MutNullableHeap<JS<WorkerNavigator>>,
|
||||
console: MutNullableHeap<JS<Console>>,
|
||||
crypto: MutNullableHeap<JS<Crypto>>,
|
||||
timers: ActiveTimers,
|
||||
timers: OneshotTimers,
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
|
@ -98,6 +98,7 @@ impl WorkerGlobalScope {
|
|||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
timer_event_chan: IpcSender<TimerEvent>)
|
||||
-> WorkerGlobalScope {
|
||||
|
||||
WorkerGlobalScope {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
next_worker_id: Cell::new(WorkerId(0)),
|
||||
|
@ -109,7 +110,7 @@ impl WorkerGlobalScope {
|
|||
navigator: Default::default(),
|
||||
console: Default::default(),
|
||||
crypto: Default::default(),
|
||||
timers: ActiveTimers::new(timer_event_chan, init.scheduler_chan.clone()),
|
||||
timers: OneshotTimers::new(timer_event_chan, init.scheduler_chan.clone()),
|
||||
mem_profiler_chan: init.mem_profiler_chan,
|
||||
to_devtools_sender: init.to_devtools_sender,
|
||||
from_devtools_sender: init.from_devtools_sender,
|
||||
|
@ -144,13 +145,13 @@ impl WorkerGlobalScope {
|
|||
self.scheduler_chan.clone()
|
||||
}
|
||||
|
||||
pub fn schedule_callback(&self, callback: Box<ScheduledCallback>, duration: MsDuration) -> TimerHandle {
|
||||
pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle {
|
||||
self.timers.schedule_callback(callback,
|
||||
duration,
|
||||
TimerSource::FromWorker)
|
||||
}
|
||||
|
||||
pub fn unschedule_callback(&self, handle: TimerHandle) {
|
||||
pub fn unschedule_callback(&self, handle: OneshotTimerHandle) {
|
||||
self.timers.unschedule_callback(handle);
|
||||
}
|
||||
|
||||
|
@ -250,7 +251,8 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetTimeout(&self, _cx: *mut JSContext, callback: Rc<Function>, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::FunctionTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Worker(self),
|
||||
TimerCallback::FunctionTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::NonInterval,
|
||||
|
@ -259,7 +261,8 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetTimeout_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::StringTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Worker(self),
|
||||
TimerCallback::StringTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::NonInterval,
|
||||
|
@ -268,12 +271,13 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-clearinterval
|
||||
fn ClearTimeout(&self, handle: i32) {
|
||||
self.timers.clear_timeout_or_interval(handle);
|
||||
self.timers.clear_timeout_or_interval(GlobalRef::Worker(self), handle);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetInterval(&self, _cx: *mut JSContext, callback: Rc<Function>, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::FunctionTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Worker(self),
|
||||
TimerCallback::FunctionTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::Interval,
|
||||
|
@ -282,7 +286,8 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
|
||||
fn SetInterval_(&self, _cx: *mut JSContext, callback: DOMString, timeout: i32, args: Vec<HandleValue>) -> i32 {
|
||||
self.timers.set_timeout_or_interval(TimerCallback::StringTimerCallback(callback),
|
||||
self.timers.set_timeout_or_interval(GlobalRef::Worker(self),
|
||||
TimerCallback::StringTimerCallback(callback),
|
||||
args,
|
||||
timeout,
|
||||
IsInterval::Interval,
|
||||
|
|
|
@ -59,7 +59,7 @@ use std::sync::mpsc::channel;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use string_cache::Atom;
|
||||
use time;
|
||||
use timers::{ScheduledCallback, TimerHandle};
|
||||
use timers::{OneshotTimerCallback, OneshotTimerHandle};
|
||||
use url::Url;
|
||||
use url::percent_encoding::{utf8_percent_encode, USERNAME_ENCODE_SET, PASSWORD_ENCODE_SET};
|
||||
use util::str::DOMString;
|
||||
|
@ -146,7 +146,7 @@ pub struct XMLHttpRequest {
|
|||
upload_events: Cell<bool>,
|
||||
send_flag: Cell<bool>,
|
||||
|
||||
timeout_cancel: DOMRefCell<Option<TimerHandle>>,
|
||||
timeout_cancel: DOMRefCell<Option<OneshotTimerHandle>>,
|
||||
fetch_time: Cell<i64>,
|
||||
generation_id: Cell<GenerationId>,
|
||||
response_status: Cell<Result<(), ()>>,
|
||||
|
@ -1055,39 +1055,15 @@ impl XMLHttpRequest {
|
|||
self.dispatch_progress_event(false, type_, len, total);
|
||||
}
|
||||
fn set_timeout(&self, duration_ms: u32) {
|
||||
#[derive(JSTraceable, HeapSizeOf)]
|
||||
struct ScheduledXHRTimeout {
|
||||
#[ignore_heap_size_of = "Because it is non-owning"]
|
||||
xhr: Trusted<XMLHttpRequest>,
|
||||
generation_id: GenerationId,
|
||||
}
|
||||
|
||||
impl ScheduledCallback for ScheduledXHRTimeout {
|
||||
fn invoke(self: Box<Self>) {
|
||||
let this = *self;
|
||||
let xhr = this.xhr.root();
|
||||
if xhr.ready_state.get() != XMLHttpRequestState::Done {
|
||||
xhr.process_partial_response(XHRProgress::Errored(this.generation_id, Error::Timeout));
|
||||
}
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<ScheduledCallback> {
|
||||
box ScheduledXHRTimeout {
|
||||
xhr: self.xhr.clone(),
|
||||
generation_id: self.generation_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets up the object to timeout in a given number of milliseconds
|
||||
// This will cancel all previous timeouts
|
||||
let global = self.global();
|
||||
let callback = ScheduledXHRTimeout {
|
||||
let callback = OneshotTimerCallback::XhrTimeout(XHRTimeoutCallback {
|
||||
xhr: Trusted::new(self, global.r().networking_task_source()),
|
||||
generation_id: self.generation_id.get(),
|
||||
};
|
||||
});
|
||||
let duration = Length::new(duration_ms as u64);
|
||||
*self.timeout_cancel.borrow_mut() = Some(global.r().schedule_callback(box callback, duration));
|
||||
*self.timeout_cancel.borrow_mut() = Some(global.r().schedule_callback(callback, duration));
|
||||
}
|
||||
|
||||
fn cancel_timeout(&self) {
|
||||
|
@ -1368,6 +1344,22 @@ impl XMLHttpRequest {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, HeapSizeOf)]
|
||||
pub struct XHRTimeoutCallback {
|
||||
#[ignore_heap_size_of = "Because it is non-owning"]
|
||||
xhr: Trusted<XMLHttpRequest>,
|
||||
generation_id: GenerationId,
|
||||
}
|
||||
|
||||
impl XHRTimeoutCallback {
|
||||
pub fn invoke(self) {
|
||||
let xhr = self.xhr.root();
|
||||
if xhr.ready_state.get() != XMLHttpRequestState::Done {
|
||||
xhr.process_partial_response(XHRProgress::Errored(self.generation_id, Error::Timeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Extractable {
|
||||
fn extract(&self) -> (Vec<u8>, Option<DOMString>);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue