library + trace: rewrite panic sites as explicit match+panic
Apply the same explicit match+panic shape to the library layer (channel, gen_server, gen_statem). Extend it to the smarm-trace-gated code that the default `cargo clippy --lib` does not see: the GLOBAL lock-poison sites in trace.rs and the current_pid sites inside te!() in channel.rs. Keep the current_pid match inside the te!() argument so non-trace builds evaluate nothing extra on the recv-wake hot path. const-init the trace thread-local.
This commit is contained in:
+54
-18
@@ -176,8 +176,10 @@ impl<T> Receiver<T> {
|
||||
if g.senders == 0 {
|
||||
return Err(RecvError);
|
||||
}
|
||||
let me = crate::actor::current_pid()
|
||||
.expect("recv() called outside an actor");
|
||||
let me = match crate::actor::current_pid() {
|
||||
Some(me) => me,
|
||||
None => panic!("smarm: recv() called outside an actor"),
|
||||
};
|
||||
debug_assert!(
|
||||
g.parked_receiver.is_none_or(|(p, _)| p == me),
|
||||
"channel has more than one receiver"
|
||||
@@ -191,7 +193,10 @@ impl<T> Receiver<T> {
|
||||
// Release the lock before parking — the unparker will need it.
|
||||
crate::scheduler::park_current();
|
||||
// Woken up — record it before looping to check the queue.
|
||||
crate::te!(crate::trace::Event::RecvWake(crate::actor::current_pid().unwrap()));
|
||||
crate::te!(crate::trace::Event::RecvWake(match crate::actor::current_pid() {
|
||||
Some(p) => p,
|
||||
None => panic!("smarm: RecvWake outside an actor (core corrupt)"),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,8 +227,10 @@ impl<T> Receiver<T> {
|
||||
where
|
||||
T: Send + 'static,
|
||||
{
|
||||
let me = crate::actor::current_pid()
|
||||
.expect("recv_timeout() called outside an actor");
|
||||
let me = match crate::actor::current_pid() {
|
||||
Some(me) => me,
|
||||
None => panic!("smarm: recv_timeout() called outside an actor"),
|
||||
};
|
||||
|
||||
// Fast path + wait registration, one critical section.
|
||||
let epoch;
|
||||
@@ -254,7 +261,10 @@ impl<T> Receiver<T> {
|
||||
crate::scheduler::insert_wait_timer(deadline, me, target, epoch);
|
||||
|
||||
crate::scheduler::park_current();
|
||||
crate::te!(crate::trace::Event::RecvWake(crate::actor::current_pid().unwrap()));
|
||||
crate::te!(crate::trace::Event::RecvWake(match crate::actor::current_pid() {
|
||||
Some(p) => p,
|
||||
None => panic!("smarm: RecvWake outside an actor (core corrupt)"),
|
||||
}));
|
||||
let mut g = self.inner.lock();
|
||||
if let Some(v) = g.queue.pop_front() {
|
||||
crate::preempt::note_message_received();
|
||||
@@ -283,17 +293,23 @@ impl<T> Receiver<T> {
|
||||
loop {
|
||||
{
|
||||
let mut g = self.inner.lock();
|
||||
if let Some(i) = g.queue.iter().position(|v| pred(v)) {
|
||||
if let Some(i) = g.queue.iter().position(&pred) {
|
||||
// position() found it, so remove() returns Some.
|
||||
crate::preempt::note_message_received();
|
||||
return Ok(g.queue.remove(i).unwrap());
|
||||
let v = match g.queue.remove(i) {
|
||||
Some(v) => v,
|
||||
None => panic!("smarm: channel queue.remove after position (logic bug)"),
|
||||
};
|
||||
return Ok(v);
|
||||
}
|
||||
if g.senders == 0 {
|
||||
// Closed and nothing queued can ever match.
|
||||
return Err(RecvError);
|
||||
}
|
||||
let me = crate::actor::current_pid()
|
||||
.expect("recv_match() called outside an actor");
|
||||
let me = match crate::actor::current_pid() {
|
||||
Some(me) => me,
|
||||
None => panic!("smarm: recv_match() called outside an actor"),
|
||||
};
|
||||
debug_assert!(
|
||||
g.parked_receiver.is_none_or(|(p, _)| p == me),
|
||||
"channel has more than one receiver"
|
||||
@@ -303,7 +319,10 @@ impl<T> Receiver<T> {
|
||||
}
|
||||
// Release the lock before parking — the unparker will need it.
|
||||
crate::scheduler::park_current();
|
||||
crate::te!(crate::trace::Event::RecvWake(crate::actor::current_pid().unwrap()));
|
||||
crate::te!(crate::trace::Event::RecvWake(match crate::actor::current_pid() {
|
||||
Some(p) => p,
|
||||
None => panic!("smarm: RecvWake outside an actor (core corrupt)"),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,9 +335,13 @@ impl<T> Receiver<T> {
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
let mut g = self.inner.lock();
|
||||
if let Some(i) = g.queue.iter().position(|v| pred(v)) {
|
||||
if let Some(i) = g.queue.iter().position(&pred) {
|
||||
crate::preempt::note_message_received();
|
||||
return Ok(Some(g.queue.remove(i).unwrap()));
|
||||
let v = match g.queue.remove(i) {
|
||||
Some(v) => v,
|
||||
None => panic!("smarm: channel queue.remove after position (logic bug)"),
|
||||
};
|
||||
return Ok(Some(v));
|
||||
}
|
||||
if g.senders == 0 {
|
||||
return Err(RecvError);
|
||||
@@ -466,7 +489,10 @@ impl<T> Selectable for Receiver<T> {
|
||||
/// see [`try_select`] for the fallible form; channel-only selects cannot
|
||||
/// fail).
|
||||
pub fn select(arms: &[&dyn Selectable]) -> usize {
|
||||
try_select(arms).expect("select(): fd arm failed to register (use try_select)")
|
||||
match try_select(arms) {
|
||||
Ok(i) => i,
|
||||
Err(e) => panic!("smarm: select() fd arm failed to register (use try_select): {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// [`select`], fallible: `Err` when an arm fails to register (only fd
|
||||
@@ -476,7 +502,10 @@ pub fn select(arms: &[&dyn Selectable]) -> usize {
|
||||
/// one has been unregistered.
|
||||
pub fn try_select(arms: &[&dyn Selectable]) -> std::io::Result<usize> {
|
||||
assert!(!arms.is_empty(), "select() on an empty arm list");
|
||||
let me = crate::actor::current_pid().expect("select() called outside an actor");
|
||||
let me = match crate::actor::current_pid() {
|
||||
Some(me) => me,
|
||||
None => panic!("smarm: select() called outside an actor"),
|
||||
};
|
||||
loop {
|
||||
let epoch = crate::scheduler::begin_wait();
|
||||
if let Some(i) = register_arms(me, epoch, arms)? {
|
||||
@@ -626,8 +655,12 @@ pub fn select_timeout(
|
||||
arms: &[&dyn Selectable],
|
||||
timeout: std::time::Duration,
|
||||
) -> Option<usize> {
|
||||
try_select_timeout(arms, timeout)
|
||||
.expect("select_timeout(): fd arm failed to register (use try_select_timeout)")
|
||||
match try_select_timeout(arms, timeout) {
|
||||
Ok(r) => r,
|
||||
Err(e) => panic!(
|
||||
"smarm: select_timeout() fd arm failed to register (use try_select_timeout): {e}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// [`select_timeout`], fallible: `Err` when an arm fails to register
|
||||
@@ -638,7 +671,10 @@ pub fn try_select_timeout(
|
||||
timeout: std::time::Duration,
|
||||
) -> std::io::Result<Option<usize>> {
|
||||
assert!(!arms.is_empty(), "select_timeout() on an empty arm list");
|
||||
let me = crate::actor::current_pid().expect("select_timeout() called outside an actor");
|
||||
let me = match crate::actor::current_pid() {
|
||||
Some(me) => me,
|
||||
None => panic!("smarm: select_timeout() called outside an actor"),
|
||||
};
|
||||
let epoch = crate::scheduler::begin_wait();
|
||||
if let Some(i) = register_arms(me, epoch, arms)? {
|
||||
return Ok(Some(i)); // ready now: the timer was never armed
|
||||
|
||||
Reference in New Issue
Block a user