Skip to content

Commit

Permalink
let go of TIMERS and QUEUE before exec
Browse files Browse the repository at this point in the history
  • Loading branch information
bmisiak committed Feb 21, 2024
1 parent 7244f7c commit 6f93349
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 39 deletions.
57 changes: 32 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,22 +169,7 @@ impl SampPlugin for PreciseTimers {
// Rust's Instant is monotonic and nondecreasing, even during NTP time adjustment.
let now = Instant::now();

loop {
let triggered_timer = QUEUE.with_borrow(|q| match q.peek() {
Some((
&key,
&Reverse(TimerScheduling {
next_trigger,
interval,
execution_forbidden,
}),
)) if next_trigger <= now => Some((key, interval, execution_forbidden)),
_ => None,
});
let Some((key, interval, execution_forbidden)) = triggered_timer else {
break;
};

while let Some((key, interval, execution_forbidden)) = next_triggered_timer(now) {
if let (Some(interval), false) = (interval, execution_forbidden) {
let next_trigger = now + interval;
QUEUE.with_borrow_mut(|q| {
Expand All @@ -199,25 +184,33 @@ impl SampPlugin for PreciseTimers {
.expect("failed to reschedule repeating timer");
});

TIMERS.with_borrow_mut(|t| {
// Only holding onto TIMERS until we need to push the arguments
let (amx,idx) = TIMERS.with_borrow_mut(|t| {
let timer = t.get_mut(key).expect("slab should contain repeating timer");

if let Err(err) = timer.execute_pawn_callback() {
error!("Error executing repeating timer callback: {}", err);
}
let amx = samp::amx::get(timer.amx_identifier).expect("missing amx");
timer.passed_arguments.push_onto_amx_stack(amx, &amx.allocator()).expect("failed to push args to amx");
(amx, timer.amx_callback_index)
});
// Now that we let go of TIMERS and QUEUE,
// we can execute the callback. It can add new timers etc
if let Err(err) = amx.exec(idx) {
error!("error executing repeating timer: {}", err);
}
} else {
// Must pop before the timer is executed, so that
// it can't schedule anything as the very next timer before
// the callback can't schedule anything as the very next timer before
// we have a chance to pop from the queue.
let (popped_key, _) = QUEUE
.with_borrow_mut(|q| q.pop())
.expect("priority queue should have at least the timer we peeked");
assert_eq!(popped_key, key);
let mut removed_timer = TIMERS.with_borrow_mut(|t| t.remove(key));

// Remove from slab
let timer = TIMERS.with_borrow_mut(|t| t.remove(key));
// Only execute if not marked for deletion
if !execution_forbidden {
if let Err(err) = removed_timer.execute_pawn_callback() {
let amx = samp::amx::get(timer.amx_identifier).expect("missing amx");
timer.passed_arguments.push_onto_amx_stack(amx, &amx.allocator()).expect("failed to push args to amx");
if let Err(err) = amx.exec(timer.amx_callback_index) {
error!("Error executing non-repeating timer callback: {}", err);
}
}
Expand All @@ -243,6 +236,20 @@ impl SampPlugin for PreciseTimers {
}
}

fn next_triggered_timer(now: Instant) -> Option<(usize, Option<Duration>, bool)> {
QUEUE.with_borrow(|q| match q.peek() {
Some((
&key,
&Reverse(TimerScheduling {
next_trigger,
interval,
execution_forbidden,
}),
)) if next_trigger <= now => Some((key, interval, execution_forbidden)),
_ => None,
})
}

samp::initialize_plugin!(
natives: [
PreciseTimers::delete,
Expand Down
14 changes: 0 additions & 14 deletions src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,4 @@ impl Timer {
pub fn was_scheduled_by_amx(&self, amx: &samp::amx::Amx) -> bool {
self.amx_identifier == AmxIdent::from(amx.amx().as_ptr())
}

/// This function executes the callback provided to the `SetPreciseTimer` native.
pub fn execute_pawn_callback(&mut self) -> AmxResult<()> {
// Get the AMX which scheduled the timer
let amx = samp::amx::get(self.amx_identifier).ok_or(AmxError::NotFound)?;
let allocator = amx.allocator();

// Execute the callback (after pushing its arguments onto the stack)
// Amx::exec should actually be marked unsafe in the samp-rs crate
self.passed_arguments.push_onto_amx_stack(amx, &allocator)?;
amx.exec(self.amx_callback_index)?;

Ok(())
}
}

0 comments on commit 6f93349

Please sign in to comment.