#pragma once
#include "inc.h"
#include "forward.h"
#include "backend/Backend.h"
#include <vector>
#include <panda/intrusive_chain.h>
#include <panda/CallbackDispatcher.h>
namespace panda { namespace unievent {
backend::Backend* default_backend ();
void set_default_backend (backend::Backend* backend);
struct Loop : Refcnt {
using Backend = backend::Backend;
using LoopImpl = backend::LoopImpl;
using Handles = IntrusiveChain<Handle*>;
using RunMode = LoopImpl::RunMode;
using fork_fptr = void(const LoopSP&);
using fork_fn = function<fork_fptr>;
using new_handle_fptr = void(const LoopSP&, Handle* handle);
using new_handle_fn = function<new_handle_fptr>;
using remove_handle_fptr = void(const LoopSP&, Handle* handle);
using remove_handle_fn = function<remove_handle_fptr>;
static LoopSP global_loop () {
if (!_global_loop) _init_global_loop();
return _global_loop;
}
static LoopSP default_loop () {
if (!_default_loop) _init_default_loop();
return _default_loop;
}
CallbackDispatcher<fork_fptr> fork_event;
CallbackDispatcher<new_handle_fptr> new_handle_event;
CallbackDispatcher<remove_handle_fptr> remove_handle_event;
Loop (Backend* backend = nullptr) : Loop(backend, LoopImpl::Type::LOCAL) {}
Backend* backend () const { return _backend; }
bool is_default () const { return _default_loop == this; }
bool is_global () const { return _global_loop == this; }
uint64_t now () const { return _impl->now(); }
void update_time () { _impl->update_time(); }
bool alive () const { return _impl->alive(); }
virtual bool run (RunMode = RunMode::DEFAULT);
virtual void stop ();
bool run_once () { return run(RunMode::ONCE); }
bool run_nowait () { return run(RunMode::NOWAIT); }
const Handles& handles () const { return _handles; }
uint64_t delay (const LoopImpl::delayed_fn& f, const iptr<Refcnt>& guard = {}) {
return impl()->delay(f, guard);
}
void cancel_delay (uint64_t id) noexcept {
impl()->cancel_delay(id);
}
const ResolverSP& resolver ();
void track_load_average (uint32_t for_last_n_seconds);
double get_load_average () const;
LoopImpl* impl () { return _impl; }
void dump () const;
protected:
~Loop ();
private:
friend Handle; friend Work;
using Works = IntrusiveChain<WorkSP>;
Backend* _backend;
LoopImpl* _impl;
Handles _handles;
ResolverSP _resolver;
Works _works;
Loop (Backend*, LoopImpl::Type);
void register_handle (Handle* h) { _handles.push_back(h); new_handle_event(this, h); }
void unregister_handle (Handle* h) noexcept { _handles.erase(h); remove_handle_event(this, h); }
void register_work (const WorkSP& w) { _works.push_back(w); }
void unregister_work (const WorkSP& w) noexcept { _works.erase(w); }
static LoopSP _global_loop;
static thread_local LoopSP _default_loop;
static void _init_global_loop ();
static void _init_default_loop ();
friend void set_default_backend (backend::Backend*);
};
struct SyncLoop {
using Backend = backend::Backend;
static const LoopSP& get (Backend* b) {
auto& list = loops;
for (const auto& row : list) if (row.backend == b) return row.loop;
list.push_back({b, new Loop(b)});
return list.back().loop;
}
private:
struct Item {
Backend* backend;
LoopSP loop;
};
static thread_local std::vector<Item> loops;
};
}}
#include "Work.h"
#include "Handle.h"