#pragma once
#include "common.hpp"
#include "tout.hpp"
#include "fdtable.hpp"
#include "queue.hpp"
#include "hooks.hpp"
#include "callout.hpp"
typedef uint32_t event_t; ///< event bitmask TODO: move this out into smaller/more generic header
#define EVENT_NONE 0
extern const event_t EVENT_IN;
extern const event_t EVENT_OUT;
extern const event_t EVENT_CLOSE;
extern const event_t EVENT_TOUT;
extern const event_t EVENT_WAKEUP;
#define EVENT_ALL (EVENT_IN|EVENT_OUT|EVENT_CLOSE)
#define EVENT_LOG_FMT "c%c%c%c"
#define EVENT_LOG(e) event_isset(e,EVENT_IN)?'I':'-',event_isset(e,EVENT_OUT)?'O':'-',event_isset(e,EVENT_CLOSE)?'X':'-',event_isnot(e,EVENT_IN|EVENT_OUT|EVENT_CLOSE)?'+':'-'
#define event_mask(ev, EV) ((ev) & (EV))
#define event_isset(ev, EV) (!!event_mask((ev), (EV))) ///< checks whether an event is set that is in the given mask
#define event_isnot(ev, EV) (!!event_mask((ev), ~(EV))) ///< checks whether an event is set that is not in the given mask
#define event_isonly(ev, EV) (!event_isnot((ev), (EV))) ///< checks whether no other event but the given mask is set
#define event_unset(ev, EV) ev &= ~(EV)
#define event_setonly(ev, EV) ev &= (EV)
typedef void (*poll_handler_t)(int, event_t, unsigned, void*);
class Poll {
private:
typedef struct {
poll_handler_t handler;
void* handler_ctx; ///< user-given ptr for passing to #handler
event_t events; ///< for epoll_ctl caching
bool short_timeout;
unsigned invalid_loop; ///< the loop counter when it was deleted, preventing access during the same iteration
} poll_ctx_t;
Poll();
bool ctl(int, int, event_t);
static Poll* inst;
int efd;
unsigned fd_no;
unsigned loop_counter; ///< is passed along to #poll_handler_t
FdTable<poll_ctx_t> fds;
ToutQueue timeouts, short_timeouts; // TODO: use socket timeouts as long timeouts (as these are fatal anyhow)?
public:
static INLINE Poll* getInst() { return inst ?: new Poll(); }
bool add(int, poll_handler_t, event_t, bool short_timeout=false, void* =NULL);
bool mod(int, poll_handler_t, event_t, bool short_timeout=false, void* =NULL);
bool del(int);
bool wakeup(int); ///< calls fd's handler, if any, and resets timeout. beware of recursion. of course, it must be ensured that the fd is still the same and valid.
void wakeup(); ///< as wakeup(int), but broadcast to all handlers, needed for shutdown, callable from outside the main wait() loop.
void* ctx_get(int); ///< returns the opaque pointer set using add() or mod()
void wait(int tout_ms); ///< waits for and processes events
INLINE unsigned refcount() { return fd_no; } ///< how many fds are watched
~Poll();
};