1use alloc::collections::BTreeMap;
14use alloc::vec;
15use alloc::vec::Vec;
16use core::ptr::NonNull;
17
18use iceoryx2_bb_concurrency::lazy_lock::LazyLock;
19use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
20use iceoryx2_bb_posix::mutex::*;
21use iceoryx2_bb_system_types::{file_name::FileName, file_path::FilePath, path::Path};
22use iceoryx2_log::{fail, fatal_panic, warn};
23
24use crate::{
25 monitoring::{MonitoringCreateCleanerError, MonitoringCreateTokenError, MonitoringStateError},
26 named_concept::NamedConceptConfiguration,
27};
28
29use super::{
30 Monitoring, MonitoringBuilder, MonitoringCleaner, MonitoringMonitor, MonitoringToken,
31 NamedConcept, NamedConceptBuilder, NamedConceptMgmt, State,
32};
33
34#[derive(Debug)]
35enum MonitoringState {
36 Alive,
37 Dead,
38 OwnedByCleaner,
39}
40
41static PROCESS_LOCAL_MTX_HANDLE: LazyLock<MutexHandle<BTreeMap<FilePath, MonitoringState>>> =
42 LazyLock::new(MutexHandle::new);
43
44static PROCESS_LOCAL_STORAGE: LazyLock<
45 Mutex<'static, 'static, BTreeMap<FilePath, MonitoringState>>,
46> = LazyLock::new(|| {
47 fatal_panic!(from "PROCESS_LOCAL_STORAGE",
48 when MutexBuilder::new()
49 .is_interprocess_capable(false)
50 .create(BTreeMap::new(), &PROCESS_LOCAL_MTX_HANDLE),
51 "Failed to create global monitoring storage")
52});
53
54#[derive(Clone, PartialEq, Eq, Debug)]
55pub struct Configuration {
56 suffix: FileName,
57 prefix: FileName,
58 path_hint: Path,
59}
60
61impl Default for Configuration {
62 fn default() -> Self {
63 Self {
64 suffix: ProcessLocalMonitoring::default_suffix(),
65 prefix: ProcessLocalMonitoring::default_prefix(),
66 path_hint: ProcessLocalMonitoring::default_path_hint(),
67 }
68 }
69}
70
71impl NamedConceptConfiguration for Configuration {
72 fn prefix(mut self, value: &FileName) -> Self {
73 self.prefix = *value;
74 self
75 }
76
77 fn get_prefix(&self) -> &FileName {
78 &self.prefix
79 }
80
81 fn suffix(mut self, value: &FileName) -> Self {
82 self.suffix = *value;
83 self
84 }
85
86 fn get_suffix(&self) -> &FileName {
87 &self.suffix
88 }
89
90 fn path_hint(mut self, value: &Path) -> Self {
91 self.path_hint = *value;
92 self
93 }
94
95 fn get_path_hint(&self) -> &Path {
96 &self.path_hint
97 }
98}
99
100#[derive(Debug)]
101pub struct ProcessLocalMonitoring {}
102
103impl NamedConceptMgmt for ProcessLocalMonitoring {
104 type Configuration = Configuration;
105
106 fn list_cfg(
107 cfg: &Self::Configuration,
108 ) -> Result<Vec<FileName>, crate::named_concept::NamedConceptListError> {
109 let msg = "Unable to list all monitoring::process_local";
110 let origin = "monitoring::process_local::ProcessLocalMonitoring::list_cfg()";
111
112 let guard = fatal_panic!(from origin,
113 when PROCESS_LOCAL_STORAGE.lock(),
114 "{} since the lock could not be acquired.", msg);
115
116 let mut result = vec![];
117 for storage_name in guard.iter() {
118 if let Some(v) = cfg.extract_name_from_path(storage_name.0) {
119 result.push(v);
120 }
121 }
122
123 Ok(result)
124 }
125
126 fn does_exist_cfg(
127 name: &FileName,
128 cfg: &Self::Configuration,
129 ) -> Result<bool, crate::named_concept::NamedConceptDoesExistError> {
130 let msg = "Unable to check if monitoring::process_local exists";
131 let origin = "monitoring::process_local::ProcessLocalMonitoring::does_exist_cfg()";
132
133 let guard = fatal_panic!(from origin,
134 when PROCESS_LOCAL_STORAGE.lock(),
135 "{} since the lock could not be acquired.", msg);
136
137 match guard.get(&cfg.path_for(name)) {
138 Some(_) => Ok(true),
139 None => Ok(false),
140 }
141 }
142
143 unsafe fn remove_cfg(
144 name: &FileName,
145 cfg: &Self::Configuration,
146 ) -> Result<bool, crate::named_concept::NamedConceptRemoveError> {
147 let storage_name = cfg.path_for(name);
148 let msg = "Unable to remove monitoring::process_local";
149 let origin = "monitoring::process_local::ProcessLocalMonitoring::remove_cfg()";
150
151 let guard = PROCESS_LOCAL_STORAGE.lock();
152 if guard.is_err() {
153 fatal_panic!(from origin,
154 "{} since the lock could not be acquired.", msg);
155 }
156
157 Ok(guard.unwrap().remove(&storage_name).is_some())
158 }
159
160 fn remove_path_hint(
161 _value: &Path,
162 ) -> Result<(), crate::named_concept::NamedConceptPathHintRemoveError> {
163 Ok(())
164 }
165}
166
167impl Monitoring for ProcessLocalMonitoring {
168 type Token = Token;
169 type Monitor = Monitor;
170 type Cleaner = Cleaner;
171 type Builder = Builder;
172}
173
174#[derive(Debug)]
175pub struct Cleaner {
176 name: FileName,
177 config: Configuration,
178}
179
180impl Drop for Cleaner {
181 fn drop(&mut self) {
182 let msg = "Failed to remove";
183
184 let mut guard = fatal_panic!(from self, when PROCESS_LOCAL_STORAGE.lock(),
185 "{} due to a failure while acquiring the lock.", msg);
186
187 let full_name = self.config.path_for(&self.name);
188 if guard.remove(&full_name).is_none() {
189 fatal_panic!(from self,
190 "{} since the entry was not existing anymore. This should never happen!", msg);
191 }
192 }
193}
194
195impl NamedConcept for Cleaner {
196 fn name(&self) -> &FileName {
197 &self.name
198 }
199}
200
201impl MonitoringCleaner for Cleaner {
202 fn relinquish(self) {
203 self.abandon();
204 }
205}
206
207impl Abandonable for Cleaner {
208 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
209 let this = unsafe { this.as_mut() };
210 let msg = "Failed to remove";
211
212 let mut guard = fatal_panic!(from this, when PROCESS_LOCAL_STORAGE.lock(),
213 "{} due to a failure while acquiring the lock.", msg);
214
215 let full_name = this.config.path_for(&this.name);
216 match guard.get_mut(&full_name) {
217 Some(v) => *v = MonitoringState::Dead,
218 None => {
219 fatal_panic!(from this,
220 "{msg} the key \"{:?}\" no longer exist. This should never happen!", full_name);
221 }
222 }
223 }
224}
225
226#[derive(Debug)]
227pub struct Token {
228 name: FileName,
229 config: Configuration,
230}
231
232impl NamedConcept for Token {
233 fn name(&self) -> &FileName {
234 &self.name
235 }
236}
237
238impl MonitoringToken for Token {}
239
240impl Abandonable for Token {
241 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
242 let msg = "Failed to leak";
243
244 let this = unsafe { this.as_mut() };
245 let mut guard = fatal_panic!(from this, when PROCESS_LOCAL_STORAGE.lock(),
246 "{} due to a failure while acquiring the lock.", msg);
247
248 let full_name = this.config.path_for(&this.name);
249 match guard.get_mut(&full_name) {
250 Some(v) => *v = MonitoringState::Dead,
251 None => {
252 fatal_panic!(from this,
253 "{msg} the key \"{:?}\" no longer exist. This should never happen!", full_name);
254 }
255 }
256 }
257}
258
259impl Drop for Token {
260 fn drop(&mut self) {
261 let msg = "Failed to remove";
262
263 let mut guard = fatal_panic!(from self, when PROCESS_LOCAL_STORAGE.lock(),
264 "{} due to a failure while acquiring the lock.", msg);
265
266 let full_name = self.config.path_for(&self.name);
267 if guard.remove(&full_name).is_none() {
268 warn!(from self,
269 "{} since the entry was not existing anymore. Someone else removed a token that was owned by this object!", msg);
270 }
271 }
272}
273
274#[derive(Debug)]
275pub struct Monitor {
276 name: FileName,
277 full_name: FilePath,
278}
279
280impl NamedConcept for Monitor {
281 fn name(&self) -> &FileName {
282 &self.name
283 }
284}
285
286impl MonitoringMonitor for Monitor {
287 fn state(&self) -> Result<super::State, super::MonitoringStateError> {
288 let msg = "Failed to acquire state of monitor";
289
290 let guard = fail!(from self, when PROCESS_LOCAL_STORAGE.lock(),
291 with MonitoringStateError::InternalError,
292 "{} due to a failure while acquiring the lock.", msg);
293
294 match guard.get(&self.full_name) {
295 Some(MonitoringState::Alive) => Ok(State::Alive),
296 Some(MonitoringState::Dead) | Some(MonitoringState::OwnedByCleaner) => Ok(State::Dead),
297 None => Ok(State::DoesNotExist),
298 }
299 }
300}
301
302#[derive(Debug)]
303pub struct Builder {
304 name: FileName,
305 config: Configuration,
306}
307
308impl NamedConceptBuilder<ProcessLocalMonitoring> for Builder {
309 fn new(name: &FileName) -> Self {
310 Self {
311 name: *name,
312 config: Configuration::default(),
313 }
314 }
315
316 fn config(
317 mut self,
318 config: &<ProcessLocalMonitoring as NamedConceptMgmt>::Configuration,
319 ) -> Self {
320 self.config = config.clone();
321 self
322 }
323}
324
325impl MonitoringBuilder<ProcessLocalMonitoring> for Builder {
326 fn token(
327 self,
328 ) -> Result<<ProcessLocalMonitoring as Monitoring>::Token, super::MonitoringCreateTokenError>
329 {
330 let msg = "Failed to create monitoring token";
331
332 let mut guard = fail!(from self, when PROCESS_LOCAL_STORAGE.lock(),
333 with MonitoringCreateTokenError::InternalError,
334 "{} due to a failure while acquiring the lock.", msg);
335
336 let full_name = self.config.path_for(&self.name);
337 if guard.contains_key(&full_name) {
338 fail!(from self, with MonitoringCreateTokenError::AlreadyExists,
339 "{} since the token already exists.", msg);
340 }
341
342 guard.insert(full_name, MonitoringState::Alive);
343
344 Ok(Token {
345 name: self.name,
346 config: self.config,
347 })
348 }
349
350 fn monitor(
351 self,
352 ) -> Result<<ProcessLocalMonitoring as Monitoring>::Monitor, super::MonitoringCreateMonitorError>
353 {
354 let full_name = self.config.path_for(&self.name);
355
356 Ok(Monitor {
357 name: self.name,
358 full_name,
359 })
360 }
361
362 fn cleaner(
363 self,
364 ) -> Result<<ProcessLocalMonitoring as Monitoring>::Cleaner, super::MonitoringCreateCleanerError>
365 {
366 let msg = "Failed to create monitoring cleaner";
367
368 let mut guard = fail!(from self, when PROCESS_LOCAL_STORAGE.lock(),
369 with MonitoringCreateCleanerError::InternalError,
370 "{} due to a failure while acquiring the lock.", msg);
371
372 let full_name = self.config.path_for(&self.name);
373
374 match guard.get_mut(&full_name) {
375 Some(v) => match v {
376 MonitoringState::Alive => {
377 fail!(from self, with MonitoringCreateCleanerError::InstanceStillAlive,
378 "{} since the instance is still alive.", msg);
379 }
380 MonitoringState::Dead => {
381 *v = MonitoringState::OwnedByCleaner;
382 Ok(Cleaner {
383 name: self.name,
384 config: self.config,
385 })
386 }
387 MonitoringState::OwnedByCleaner => {
388 fail!(from self, with MonitoringCreateCleanerError::AlreadyOwnedByAnotherInstance,
389 "{} since the instance is currently cleaned up by another cleaner.", msg);
390 }
391 },
392 None => {
393 fail!(from self, with MonitoringCreateCleanerError::DoesNotExist,
394 "{} since the instance does not exist.", msg);
395 }
396 }
397 }
398}