1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
// 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/.
//! IPC Implementation, Rust part
use crate::private::{Instant, MetricId};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[cfg(not(feature = "with_gecko"))]
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
#[cfg(feature = "with_gecko")]
use {
std::sync::atomic::{AtomicU32, Ordering},
xpcom::interfaces::nsIXULRuntime,
};
use super::metrics::__glean_metric_maps;
type EventRecord = (Instant, Option<HashMap<i32, String>>);
/// Contains all the information necessary to update the metrics on the main
/// process.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct IPCPayload {
pub counters: HashMap<MetricId, i32>,
pub events: HashMap<MetricId, Vec<EventRecord>>,
pub memory_samples: HashMap<MetricId, Vec<u64>>,
pub string_lists: HashMap<MetricId, Vec<String>>,
pub timing_samples: HashMap<MetricId, Vec<u128>>,
}
/// Global singleton: pending IPC payload.
static PAYLOAD: Lazy<Mutex<IPCPayload>> = Lazy::new(|| Mutex::new(IPCPayload::default()));
pub fn with_ipc_payload<F, R>(f: F) -> R
where
F: FnOnce(&mut IPCPayload) -> R,
{
let mut payload = PAYLOAD.lock().unwrap();
f(&mut payload)
}
/// Do we need IPC?
///
/// Thread-safe.
#[cfg(feature = "with_gecko")]
static PROCESS_TYPE: Lazy<AtomicU32> = Lazy::new(|| {
if let Some(appinfo) = xpcom::services::get_XULRuntime() {
let mut process_type = nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32;
let rv = unsafe { appinfo.GetProcessType(&mut process_type) };
if rv.succeeded() {
return AtomicU32::new(process_type);
}
}
AtomicU32::new(nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32)
});
#[cfg(feature = "with_gecko")]
pub fn need_ipc() -> bool {
PROCESS_TYPE.load(Ordering::Relaxed) != nsIXULRuntime::PROCESS_TYPE_DEFAULT as u32
}
/// An RAII that, on drop, restores the value used to determine whether FOG
/// needs IPC. Used in tests.
/// ```rust,ignore
/// #[test]
/// fn test_need_ipc_raii() {
/// assert!(false == ipc::need_ipc());
/// {
/// let _raii = ipc::test_set_need_ipc(true);
/// assert!(ipc::need_ipc());
/// }
/// assert!(false == ipc::need_ipc());
/// }
/// ```
#[cfg(not(feature = "with_gecko"))]
pub struct TestNeedIpcRAII {
prev_value: bool,
}
#[cfg(not(feature = "with_gecko"))]
impl Drop for TestNeedIpcRAII {
fn drop(&mut self) {
TEST_NEED_IPC.store(self.prev_value, Ordering::Relaxed);
}
}
#[cfg(not(feature = "with_gecko"))]
static TEST_NEED_IPC: AtomicBool = AtomicBool::new(false);
/// Test-only API for telling FOG to use IPC mechanisms even if the test has
/// only the one process. See TestNeedIpcRAII for an example.
#[cfg(not(feature = "with_gecko"))]
pub fn test_set_need_ipc(need_ipc: bool) -> TestNeedIpcRAII {
TestNeedIpcRAII {
prev_value: TEST_NEED_IPC.swap(need_ipc, Ordering::Relaxed),
}
}
#[cfg(not(feature = "with_gecko"))]
pub fn need_ipc() -> bool {
TEST_NEED_IPC.load(Ordering::Relaxed)
}
pub fn take_buf() -> Option<Vec<u8>> {
with_ipc_payload(move |payload| {
let buf = bincode::serialize(&payload).ok();
*payload = IPCPayload {
..Default::default()
};
buf
})
}
pub fn replay_from_buf(buf: &[u8]) -> Result<(), ()> {
let ipc_payload: IPCPayload = bincode::deserialize(buf).map_err(|_| ())?;
for (id, value) in ipc_payload.counters.into_iter() {
log::info!("Asked to replay {:?}, {:?}", id, value);
if let Some(metric) = __glean_metric_maps::COUNTER_MAP.get(&id) {
metric.add(value);
}
}
Ok(())
}
|