Files
servo/components/config/opts.rs
Jan Varga 902d5d10d9 storage: Add support for temporary storage (#44433)
Add support for temporary storage via a new config option
`temporary_storage`
and a corresponding command-line argument `--temporary-storage`.

When enabled, client storage uses a storage directory
(e.g. `clientstorage/temporary/<uuid>`) instead of the shared default
location.
This can be used to provide isolation between concurrent servo
instances.

This is especially useful for WPT runs, where multiple Servo instances
may
execute in parallel and would otherwise share the same storage, leading
to
cross-test interference.

Based on that, this PR also updates the WPT runner to enable temporary
storage
by default.

Testing: Manual testing and a full try run.

Signed-off-by: Jan Varga <jvarga@igalia.com>
2026-04-25 10:18:21 +00:00

266 lines
9.5 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Options are global configuration options that are initialized once and cannot be changed at
//! runtime.
use std::default::Default;
use std::path::PathBuf;
use std::process;
use std::sync::OnceLock;
use serde::{Deserialize, Serialize};
/// The set of global options supported by Servo. The values for these can be configured during
/// initialization of Servo and cannot be changed later at runtime.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Opts {
/// `None` to disable the time profiler or `Some` to enable it with either:
///
/// - an interval in seconds to cause it to produce output on that interval.
/// - a file path to write profiling info to a TSV file upon Servo's termination.
pub time_profiling: Option<OutputOptions>,
/// When the profiler is enabled, this is an optional path to dump a self-contained HTML file
/// visualizing the traces as a timeline.
pub time_profiler_trace_path: Option<String>,
/// True to exit on thread failure instead of displaying about:failure.
pub hard_fail: bool,
/// Debug options that are used by developers to control Servo
/// behavior for debugging purposes.
pub debug: DiagnosticsLogging,
/// Whether we're running in multiprocess mode.
pub multiprocess: bool,
/// Whether to force using ipc_channel instead of crossbeam_channel in singleprocess mode. Does
/// nothing in multiprocess mode.
pub force_ipc: bool,
/// Whether we want background hang monitor enabled or not
pub background_hang_monitor: bool,
/// Whether we're running inside the sandbox.
pub sandbox: bool,
/// Probability of randomly closing a pipeline,
/// used for testing the hardening of the constellation.
pub random_pipeline_closure_probability: Option<f32>,
/// The seed for the RNG used to randomly close pipelines,
/// used for testing the hardening of the constellation.
pub random_pipeline_closure_seed: Option<usize>,
/// Load shaders from disk.
pub shaders_path: Option<PathBuf>,
/// Directory for a default config directory
pub config_dir: Option<PathBuf>,
/// Use temporary storage (data on disk will not persist across restarts).
pub temporary_storage: bool,
/// Path to PEM encoded SSL CA certificate store.
pub certificate_path: Option<String>,
/// Whether or not to completely ignore SSL certificate validation errors.
/// TODO: We should see if we can eliminate the need for this by fixing
/// <https://github.com/servo/servo/issues/30080>.
pub ignore_certificate_errors: bool,
/// Unminify Javascript.
pub unminify_js: bool,
/// Directory path that was created with "unminify-js"
pub local_script_source: Option<String>,
/// Unminify Css.
pub unminify_css: bool,
}
/// Debug options for Servo.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct DiagnosticsLogging {
/// Print all the debug options supported by Servo to the standard output.
pub help: bool,
/// Print the DOM after each restyle.
pub style_tree: bool,
/// Log the rule tree.
pub rule_tree: bool,
/// Log the fragment tree after each layout.
pub flow_tree: bool,
/// Log the stacking context tree after each layout.
pub stacking_context_tree: bool,
/// Log the scroll tree after each layout.
///
/// Displays the hierarchy of scrollable areas and their properties.
pub scroll_tree: bool,
/// Log the display list after each layout.
pub display_list: bool,
/// Log notifications when a relayout occurs.
pub relayout_event: bool,
/// Periodically log on which events script threads spend their processing time.
pub profile_script_events: bool,
/// Log style sharing cache statistics to after each restyle.
///
/// Shows hit/miss statistics for the style sharing cache
pub style_statistics: bool,
/// Log garbage collection passes and their durations.
pub gc_profile: bool,
/// Log Progressive Web Metrics.
pub progressive_web_metrics: bool,
}
impl DiagnosticsLogging {
/// Create a new DiagnosticsLogging configuration.
///
/// In non-production builds, this will automatically read and parse the
/// SERVO_DIAGNOSTICS environment variable if it is set.
pub fn new() -> Self {
let mut config: DiagnosticsLogging = Default::default();
// Disabled for production builds
#[cfg(debug_assertions)]
{
if let Ok(diagnostics_var) = std::env::var("SERVO_DIAGNOSTICS") {
if let Err(error) = config.extend_from_string(&diagnostics_var) {
eprintln!("Could not parse debug logging option: {error}");
}
}
}
config
}
/// Print available diagnostic logging options and their descriptions.
fn print_debug_options_usage(app: &str) {
fn print_option(name: &str, description: &str) {
println!("\t{:<35} {}", name, description);
}
println!(
"Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:",
app
);
print_option("help", "Show this help message");
print_option("style-tree", "Log the style tree after each restyle");
print_option("rule-tree", "Log the rule tree");
print_option("flow-tree", "Log the fragment tree after each layout");
print_option(
"stacking-context-tree",
"Log the stacking context tree after each layout",
);
print_option("scroll-tree", "Log the scroll tree after each layout");
print_option("display-list", "Log the display list after each layout");
print_option("style-stats", "Log style sharing cache statistics");
print_option("relayout-event", "Log when relayout occurs");
print_option("profile-script-events", "Log script event processing time");
print_option("gc-profile", "Log garbage collection statistics");
print_option("progressive-web-metrics", "Log Progressive Web Metrics");
println!();
process::exit(0);
}
/// Extend the current configuration with additional options.
///
/// Parses the string and merges any enabled options into the current configuration.
pub fn extend_from_string(&mut self, option_string: &str) -> Result<(), String> {
for option in option_string.split(',') {
let option = option.trim();
match option {
"help" => Self::print_debug_options_usage("servo"),
"display-list" => self.display_list = true,
"stacking-context-tree" => self.stacking_context_tree = true,
"flow-tree" => self.flow_tree = true,
"rule-tree" => self.rule_tree = true,
"style-tree" => self.style_tree = true,
"style-stats" => self.style_statistics = true,
"scroll-tree" => self.scroll_tree = true,
"gc-profile" => self.gc_profile = true,
"profile-script-events" => self.profile_script_events = true,
"relayout-event" => self.relayout_event = true,
"progressive-web-metrics" => self.progressive_web_metrics = true,
"" => {},
_ => return Err(format!("Unknown diagnostic option: {option}")),
};
}
Ok(())
}
}
/// The destination for the time profiler reports.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum OutputOptions {
FileName(String),
Stdout(f64),
}
impl Default for Opts {
fn default() -> Self {
Self {
time_profiling: None,
time_profiler_trace_path: None,
hard_fail: true,
multiprocess: false,
force_ipc: false,
background_hang_monitor: false,
random_pipeline_closure_probability: None,
random_pipeline_closure_seed: None,
sandbox: false,
debug: Default::default(),
config_dir: None,
temporary_storage: false,
shaders_path: None,
certificate_path: None,
ignore_certificate_errors: false,
unminify_js: false,
local_script_source: None,
unminify_css: false,
}
}
}
// 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: OnceLock<Opts> = OnceLock::new();
/// 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() -> &'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)
}