Skip to main content

iceoryx2_cal/monitoring/
process_local.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13use 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}