#![allow(unsafe_code)]
use super::backend::{self, DISPATCH_LIMIT, METHOD};
#[unsafe(export_name = "canister_global_timer")]
extern "C" fn global_timer() {
ic_cdk_executor::in_tracking_executor_context(|| {
let now = ic0::time();
let mut principal = [0; 29];
let len = ic0::canister_self_size();
ic0::canister_self_copy(&mut principal[..len], 0);
for _ in 0..DISPATCH_LIMIT {
let Some(id) = backend::due(now) else {
break;
};
let Some(slot) = backend::reserve(id) else {
backend::defer(now);
break;
};
if ic0::canister_liquid_cycle_balance128() < ic0::cost_call(METHOD.len() as u64, 8) {
drop(backend::take_flight(slot));
backend::defer(now);
break;
}
unsafe {
ic0::call_new(&principal[..len], METHOD, response, slot, response, slot);
ic0::call_on_cleanup(cleanup, slot);
}
ic0::call_data_append(&id.to_le_bytes());
ic0::call_with_best_effort_response(300);
if ic0::call_perform() != 0 {
drop(backend::take_flight(slot));
backend::defer(now);
break;
}
backend::submitted(id);
}
backend::rearm();
});
}
#[cfg_attr(
target_family = "wasm",
unsafe(export_name = "canister_update <ic-timers internal> dispatch")
)]
#[cfg_attr(
not(target_family = "wasm"),
unsafe(export_name = "ic_timers_internal_dispatch")
)]
extern "C" fn dispatch() {
ic_cdk_executor::in_tracking_executor_context(|| {
let mut caller = [0; 29];
let mut own = [0; 29];
let own_len = ic0::canister_self_size();
if ic0::msg_caller_size() != own_len {
ic0::trap(b"ic-timers: self-call required");
}
ic0::msg_caller_copy(&mut caller[..own_len], 0);
ic0::canister_self_copy(&mut own[..own_len], 0);
if caller[..own_len] != own[..own_len] {
ic0::trap(b"ic-timers: self-call required");
}
if ic0::msg_arg_data_size() != 8 {
ic0::trap(b"ic-timers: invalid dispatch payload");
}
let mut bytes = [0; 8];
ic0::msg_arg_data_copy(&mut bytes, 0);
let task = backend::remove(u64::from_le_bytes(bytes));
backend::rearm();
if let Some(task) = task {
ic_cdk_executor::spawn_protected(async move {
task.await;
ic0::msg_reply();
});
} else {
ic0::msg_reply();
}
});
}
unsafe extern "C" fn response(slot: usize) {
let flight = backend::take_flight(slot);
ic_cdk_executor::in_callback_executor_context_for(flight.method, || {
match ic0::msg_reject_code() {
2 | 6 => backend::retry(flight.task),
_ => {
drop(backend::remove(flight.task));
}
}
backend::rearm();
});
}
unsafe extern "C" fn cleanup(slot: usize) {
let flight = backend::take_flight(slot);
ic_cdk_executor::in_trap_recovery_context_for(flight.method, || {
ic_cdk_executor::cancel_all_tasks_attached_to_current_method();
backend::retry(flight.task);
backend::rearm();
});
}