fix(diagnostics): bound formatting and release ingress before callbacks
Bound UTF-8 formatting and release diagnostic ingress before invoking callbacks. Check error-ID collisions at Rust/C++ release final link. Validation: diagnostic tests, strict Clippy, Miri and final-link cases.
This commit is contained in:
1 parent
3226ef97fe
commit
84807dde4e
12 files changed
+547
-48
No files matched your search
@@ -78,6 +78,54 @@ mod tests {
|
||||
use super::ErrorIngress;
|
||||
use crate::ErrorId;
|
||||
|
||||
#[test]
|
||||
fn concurrent_publication_and_take_preserve_complete_unique_records() {
|
||||
let ingress = ErrorIngress::new();
|
||||
let start = std::sync::Barrier::new(3);
|
||||
let mut records = std::thread::scope(|scope| {
|
||||
let ingress = &ingress;
|
||||
let start = &start;
|
||||
let producers: [_; 2] = core::array::from_fn(|producer| {
|
||||
scope.spawn(move || {
|
||||
start.wait();
|
||||
for sequence in 0..8 {
|
||||
ingress.publish(
|
||||
ErrorId::new(1000 + (producer * 8 + sequence) as u16),
|
||||
["left", "right"][producer],
|
||||
);
|
||||
std::thread::yield_now();
|
||||
}
|
||||
})
|
||||
});
|
||||
let consumer = scope.spawn(move || {
|
||||
start.wait();
|
||||
let mut records = std::vec::Vec::new();
|
||||
for _ in 0..64 {
|
||||
records.extend(ingress.take());
|
||||
std::thread::yield_now();
|
||||
}
|
||||
records
|
||||
});
|
||||
for producer in producers {
|
||||
producer.join().unwrap();
|
||||
}
|
||||
consumer.join().unwrap()
|
||||
});
|
||||
records.extend(ingress.take());
|
||||
assert!(ingress.take().is_none());
|
||||
assert!(!records.is_empty());
|
||||
|
||||
// Contention may discard publications. Every retained record must be
|
||||
// one complete publication, and it may be consumed only once.
|
||||
let mut seen = [false; 16];
|
||||
for record in records {
|
||||
let index = usize::from(record.id().checked_sub(1000).unwrap());
|
||||
assert!(index < seen.len());
|
||||
assert_eq!(record.raised_at(), ["left", "right"][index / 8]);
|
||||
assert!(!core::mem::replace(&mut seen[index], true));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retains_the_first_id_and_location_until_consumed() {
|
||||
let ingress = ErrorIngress::new();
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
//! Stable reportable firmware errors with bounded diagnostic ingress.
|
||||
//!
|
||||
//! This crate owns error identity and ingress. It contains no logging levels,
|
||||
//! filtering, MAVLink, board, filesystem, or clock dependency.
|
||||
//!
|
||||
//! `#[propagate]` turns an annotated function into a reporting point. When a
|
||||
//! reportable error leaves that function, the macro makes one reporting
|
||||
//! attempt. Nested annotated callers would therefore attempt to report the
|
||||
|
||||
Reference in new issue
Block a user