#ifndef _event_api_H_
#define _event_api_H_
/*
The API for the operating system dictates which events are
truly asyncronous. Event needs C-level support only for
these types of events.
*/
typedef struct pe_watcher_vtbl pe_watcher_vtbl;
typedef struct pe_watcher pe_watcher;
typedef struct pe_event_vtbl pe_event_vtbl;
typedef struct pe_event pe_event;
typedef struct pe_ring pe_ring;
struct pe_ring { void *self; pe_ring *next, *prev; };
struct pe_watcher {
pe_watcher_vtbl *vtbl;
SV *mysv;
NV cbtime; /* float? XXX */
void *callback;
void *ext_data;
void *stats;
int running; /* SAVEINT */
U32 flags;
SV *desc;
pe_ring all; /* all watchers */
pe_ring events; /* this watcher's queued events */
HV *FALLBACK;
I16 refcnt; /* internal to Event; not perl related */
I16 prio;
I16 max_cb_tm;
};
struct pe_event {
pe_event_vtbl *vtbl;
SV *mysv;
pe_watcher *up;
U32 flags;
void *callback;
void *ext_data;
pe_ring peer; /* homogeneous */
pe_ring que; /* heterogeneous */
I16 hits;
I16 prio;
};
/* This must be placed directly after pe_watcher so the memory
layouts are always compatible. XXX? */
typedef struct pe_timeable pe_timeable;
struct pe_timeable {
pe_ring ring;
NV at;
};
typedef struct pe_qcallback pe_qcallback;
struct pe_qcallback {
pe_ring ring;
int is_perl;
void *callback;
void *ext_data;
};
/* PUBLIC FLAGS */
#define PE_REENTRANT 0x0008
#define PE_HARD 0x0010
#define PE_DEBUG 0x1000
#define PE_REPEAT 0x2000
#define PE_INVOKE1 0x4000
#define WaFLAGS(ev) ((pe_watcher*)ev)->flags
#define WaDEBUG(ev) ((WaFLAGS(ev) & PE_DEBUG)? 2:0) /*arthimetical*/
#define WaDEBUG_on(ev) (WaFLAGS(ev) |= PE_DEBUG)
#define WaDEBUG_off(ev) (WaFLAGS(ev) &= ~PE_DEBUG)
#define WaREPEAT(ev) (WaFLAGS(ev) & PE_REPEAT)
#define WaREPEAT_on(ev) (WaFLAGS(ev) |= PE_REPEAT)
#define WaREPEAT_off(ev) (WaFLAGS(ev) &= ~PE_REPEAT)
#define WaREENTRANT(ev) (WaFLAGS(ev) & PE_REENTRANT)
#define WaREENTRANT_on(ev) (WaFLAGS(ev) |= PE_REENTRANT)
#define WaREENTRANT_off(ev) (WaFLAGS(ev) &= ~PE_REENTRANT)
#define WaHARD(ev) (WaFLAGS(ev) & PE_HARD)
#define WaHARD_on(ev) (WaFLAGS(ev) |= PE_HARD) /* :-) */
#define WaHARD_off(ev) (WaFLAGS(ev) &= ~PE_HARD)
#define WaINVOKE1(ev) (WaFLAGS(ev) & PE_INVOKE1)
#define WaINVOKE1_on(ev) (WaFLAGS(ev) |= PE_INVOKE1)
#define WaINVOKE1_off(ev) (WaFLAGS(ev) &= ~PE_INVOKE1)
/* QUEUE INFO */
#define PE_QUEUES 7 /* Hard to imagine a need for more than 7 queues... */
#define PE_PRIO_HIGH 2
#define PE_PRIO_NORMAL 4
/* io-ish flags */
#define PE_R 0x1
#define PE_W 0x2
#define PE_E 0x4
#define PE_T 0x8
typedef struct pe_ioevent pe_ioevent;
struct pe_ioevent {
pe_event base;
U16 got;
};
typedef struct pe_datafulevent pe_datafulevent;
struct pe_datafulevent {
pe_event base;
SV *data;
};
typedef struct pe_idle pe_idle;
struct pe_idle {
pe_watcher base;
pe_timeable tm;
pe_ring iring;
SV *max_interval, *min_interval;
};
typedef struct pe_io pe_io;
struct pe_io {
pe_watcher base;
pe_timeable tm; /*timeout*/
pe_ring ioring;
SV *handle;
void *tm_callback;
void *tm_ext_data;
float timeout;
U16 poll;
/* ifdef UNIX */
int fd;
int xref; /*private: for poll*/
/* endif */
};
typedef struct pe_signal pe_signal;
struct pe_signal {
pe_watcher base;
pe_ring sring;
IV signal;
};
typedef struct pe_timer pe_timer;
struct pe_timer {
pe_watcher base;
pe_timeable tm;
SV *interval;
};
typedef struct pe_var pe_var;
struct pe_var {
pe_watcher base;
SV *variable;
U16 events;
};
typedef struct pe_group pe_group;
struct pe_group {
pe_watcher base;
NV since;
pe_timeable tm;
SV *timeout;
int members;
pe_watcher **member;
};
typedef struct pe_generic pe_generic;
struct pe_generic {
pe_watcher base;
SV *source;
pe_ring active;
};
typedef struct pe_genericsrc pe_genericsrc;
struct pe_genericsrc {
SV *mysv;
pe_ring watchers;
};
typedef struct pe_event_stats_vtbl pe_event_stats_vtbl;
struct pe_event_stats_vtbl {
int on;
/* if frame == -1 then we are timing pe_multiplex */
void*(*enter)(int frame, int max_tm);
void (*suspend)(void *);
void (*resume)(void *);
void (*commit)(void *, pe_watcher *); /* callback finished OK */
void (*scrub)(void *, pe_watcher *); /* callback died */
void (*dtor)(void *);
};
struct EventAPI {
#define EventAPI_VERSION 22
I32 Ver;
/* EVENTS */
void (*queue )(pe_event *ev);
void (*start )(pe_watcher *ev, int repeat);
void (*now )(pe_watcher *ev);
void (*stop )(pe_watcher *ev, int cancel_events);
void (*cancel )(pe_watcher *ev);
void (*suspend )(pe_watcher *ev);
void (*resume )(pe_watcher *ev);
/* All constructors optionally take a stash and template. Either
or both can be NULL. The template should not be a reference. */
pe_idle *(*new_idle )(HV*, SV*);
pe_timer *(*new_timer )(HV*, SV*);
pe_io *(*new_io )(HV*, SV*);
pe_var *(*new_var )(HV*, SV*);
pe_signal *(*new_signal)(HV*, SV*);
/* TIMEABLE */
NV (*NVtime)();
void (*tstart)(pe_timeable *);
void (*tstop)(pe_timeable *);
/* HOOKS */
pe_qcallback *(*add_hook)(char *which, void *cb, void *ext_data);
void (*cancel_hook)(pe_qcallback *qcb);
/* STATS */
void (*install_stats)(pe_event_stats_vtbl *esvtbl);
void (*collect_stats)(int yes);
pe_ring *AllWatchers;
/* TYPEMAP */
SV *(*watcher_2sv)(pe_watcher *wa);
void *(*sv_2watcher)(SV *sv);
SV *(*event_2sv)(pe_event *ev);
void *(*sv_2event)(SV *sv);
int (*sv_2interval)(char *label, SV *in, NV *out);
SV *(*events_mask_2sv)(int mask);
int (*sv_2events_mask)(SV *sv, int bits);
/* EVERYTHING ELSE */
void (*unloop)(SV *);
void (*unloop_all)(SV *);
};
static struct EventAPI *GEventAPI=0;
#define I_EVENT_API(YourName) \
STMT_START { \
SV *sv = perl_get_sv("Event::API",0); \
if (!sv) croak("Event::API not found"); \
GEventAPI = (struct EventAPI*) SvIV(sv); \
if (GEventAPI->Ver != EventAPI_VERSION) { \
croak("Event::API version mismatch (%d != %d) -- please recompile %s", \
GEventAPI->Ver, EventAPI_VERSION, YourName); \
} \
} STMT_END
#endif