luaur-repl-cli 0.1.0

Interactive Luau REPL (Rust).
Documentation
//! Faithful port of `static void profilerLoop()` (CLI/src/Profiler.cpp:75).

use core::ffi::c_int;
use core::sync::atomic::Ordering;
use std::thread;

use luaur_vm::functions::lua_clock::lua_clock;
use luaur_vm::records::lua_state::lua_State;

use crate::functions::profiler_trigger::{profiler_trigger, G_PROFILER};

/// The VM safepoint interrupt callback. `extern "C-unwind"` to match
/// `LuaCallbacks::interrupt`; mirrors C++ assigning
/// `gProfiler.callbacks->interrupt = profilerTrigger`.
unsafe extern "C-unwind" fn profiler_interrupt(l: *mut lua_State, gc: c_int) {
    profiler_trigger(l, gc as i32);
}

pub fn profiler_loop() {
    unsafe {
        let p = core::ptr::addr_of_mut!(G_PROFILER);
        // `frequency` and `callbacks` are set by `profiler_start` before this
        // thread is spawned, so they are stable for the lifetime of the loop.
        let frequency = (*p).frequency as f64;
        let callbacks = (*p).callbacks;

        let mut last = lua_clock();

        while !(*p).exit.load(Ordering::Relaxed) {
            let now = lua_clock();

            if now - last >= 1.0 / frequency {
                let ticks = ((now - last) * 1e6) as i64;

                (*p).ticks.fetch_add(ticks as u64, Ordering::Relaxed);
                (*p).samples.fetch_add(1, Ordering::Relaxed);
                if !callbacks.is_null() {
                    (*callbacks).interrupt = Some(profiler_interrupt);
                }

                last += ticks as f64 * 1e-6;
            } else {
                thread::yield_now();
            }
        }
    }
}