std1.0.0-beta-7 SafeC docs

Source sched/reactor.sc

View in the repository

// SafeC Standard Library — Reactor: portable scheduling loop
//
// reactor_run's body, and Reactor::poll (a callback over each backend's
// poll_events_raw_), are entirely backend-agnostic (it only calls through
// the portable std::Reactor/std::TaskScheduler interface declared in
// reactor.h/task.h), so it lives here once rather than being duplicated
// verbatim in every backend file (reactor_kqueue.sc, reactor_epoll.sc,
// reactor_win32.sc) — each of those includes this file instead of
// redefining it, the same way collections/*.sc share one implementation
// regardless of which platform ends up linking it in.
#pragma once
#include <std/sched/reactor.h>
#include <std/sync/task.h>

namespace std {

// poll()'s callback: what readiness means to a TaskScheduler.
static void reactor_unblock_(?&TaskScheduler sq, int fd, int filter) {
    match (sq) {
        case some(s): s.unblock_fd(fd, filter);
        case null: { }
    }
}

int Reactor::poll(&TaskScheduler sched, long long timeout_ms) {
    fn void(?&TaskScheduler, int, int) cb = reactor_unblock_;
    unsafe { return self.poll_events_raw_((fn void(?&Erased, int, int))cb, (?&Erased)sched, timeout_ms); }
}

// close_()'s shared part: frees both registration tables, leaving them
// empty (and the reactor reusable).
void Reactor::free_tables_() {
    struct Vec<struct SigFdEntry> no_sig = Vec::new();
    struct Vec<struct WatchedFd>  no_fd  = Vec::new();
    std::replace(&self.sigfds, no_sig).drop();
    std::replace(&self.watched, no_fd).drop();
}

void Reactor::drop() {
    self.close_();           // the OS queue; leaves the tables empty
    self.sigfds.drop();
    self.watched.drop();
}

void reactor_run(&TaskScheduler sched, &Reactor r) {
    while (sched->active_count() > 0) {
        int active = sched->tick();
        if (active == 0) {
            break;
        }
        if (sched->has_ready() != 0) {
            // Some task is still immediately runnable this round — drain
            // any already-pending events without stalling, then loop back
            // to tick() right away.
            r->poll(sched, 0LL);
        } else {
            // Everything remaining is blocked on I/O: nothing to do until
            // the OS reports something, so wait for it instead of spinning.
            r->poll(sched, -1LL);
        }
    }
}

} // namespace std