opts: Use OnceLock for Options (#38638)

Currently, the options are only initialized once and then never changed.
Making this explicit allows optimizing accesses, e.g. caching opt
values.
For some options like `multiprocess` it is obvious that we would never
want to support changing the value at runtime, however there are other
options where it could be conceivable that we want to change them at
runtime. However, imho such options might be better suited to put into a
different datastructure, so that it is explicit which options can be
changed at runtime, and which are fixed.

Testing: Covered by existing tests (and manually running servo in
multiprocess mode).

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-08-14 09:05:11 +02:00 committed by GitHub
parent cd3d982a2a
commit d2ccce6052
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 8 deletions

View file

@ -7,7 +7,7 @@
use std::default::Default;
use std::path::PathBuf;
use std::sync::{LazyLock, RwLock, RwLockReadGuard};
use std::sync::OnceLock;
use serde::{Deserialize, Serialize};
use servo_url::ServoUrl;
@ -209,13 +209,27 @@ impl Default for Opts {
// Make Opts available globally. This saves having to clone and pass
// opts everywhere it is used, which gets particularly cumbersome
// when passing through the DOM structures.
static OPTIONS: LazyLock<RwLock<Opts>> = LazyLock::new(|| RwLock::new(Opts::default()));
static OPTIONS: OnceLock<Opts> = OnceLock::new();
pub fn set_options(opts: Opts) {
*OPTIONS.write().unwrap() = opts;
/// Initialize options.
///
/// Should only be called once at process startup.
/// Must be called before the first call to [get].
pub fn initialize_options(opts: Opts) {
OPTIONS.set(opts).expect("Already initialized");
}
/// Get the servo options
///
/// If the servo options have not been initialized by calling [initialize_options], then the
/// options will be initialized to default values. Outside of tests the options should
/// be explicitly initialized.
#[inline]
pub fn get() -> RwLockReadGuard<'static, Opts> {
OPTIONS.read().unwrap()
pub fn get() -> &'static Opts {
// In unit-tests using default options reduces boilerplate.
// We can't use `cfg(test)` since that only is enabled when this crate
// is compiled in test mode.
// We rely on the `expect` in `initialize_options` to inform us if refactoring
// causes a `get` call to move before `initialize_options`.
OPTIONS.get_or_init(Default::default)
}