#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include "EventAPI.h" static GMainContext * get_gcontext (SV *context) { if (!SvOK (context)) return g_main_context_default (); croak ("only the default context is currently supported."); } struct info { int *got_events; pe_io *w; GPollFD *pfd; }; static void event_timer_cb (pe_event *pe) { *(int *)(pe->up->ext_data) = -1; } static void event_io_cb (pe_event *pe) { U16 got = ((pe_ioevent *)pe)->got; struct info *i = (struct info *)(pe->up->ext_data); i->pfd->revents |= i->pfd->events & ( (got & PE_R ? G_IO_IN : 0) | (got & PE_W ? G_IO_OUT : 0) | (got & PE_E ? G_IO_PRI : 0) ); if (i->pfd->revents) (*(i->got_events))++; } static gint event_poll_func (GPollFD *fds, guint nfds, gint timeout) { dSP; // yes, I use C99. If your compiler barfs here, fix it, but don't // tell me your compiler vendor was too incompetent to implement // the C standard within the last six years. struct info info[nfds]; pe_timer *w_timeout = 0; int got_events = 0, got_timeout = 0; int n; for (n = 0; n < nfds; n++) { GPollFD *pfd = fds + n; struct info *i = info + n; i->pfd = pfd; i->got_events = &got_events; pe_io *w = i->w = GEventAPI->new_io (0, 0); w->base.callback = (void *)event_io_cb; w->base.ext_data = (void *)i; w->fd = pfd->fd; w->poll = (pfd->events & G_IO_IN ? PE_R : 0) | (pfd->events & G_IO_OUT ? PE_W : 0) | (pfd->events & G_IO_PRI ? PE_E : 0); pfd->revents = 0; GEventAPI->start ((pe_watcher *)w, 0); } if (timeout >= 0) { w_timeout = GEventAPI->new_timer (0, 0); w_timeout->base.callback = (void *)event_timer_cb; w_timeout->base.ext_data = (void *)&got_timeout; w_timeout->tm.at = GEventAPI->NVtime () + timeout * 0.001; GEventAPI->start ((pe_watcher *)w_timeout, 0); } do { PUSHMARK (SP); XPUSHs (sv_2mortal (newSVnv (86400))); PUTBACK; call_pv ("Event::one_event", G_DISCARD | G_EVAL); SPAGAIN; } while (!got_events && !got_timeout); if (w_timeout) GEventAPI->cancel ((pe_watcher *)w_timeout); for (n = 0; n < nfds; n++) GEventAPI->cancel ((pe_watcher *)info[n].w); if (SvTRUE (ERRSV)) croak (0); if (got_timeout) return 0; return got_events; } MODULE = Glib::Event PACKAGE = Glib::Event PROTOTYPES: ENABLE BOOT: { I_EVENT_API ("Glib::Event"); } long install (SV *context) CODE: { GMainContext *ctx = get_gcontext (context); RETVAL = (long)g_main_context_get_poll_func (ctx); g_main_context_set_poll_func (ctx, event_poll_func); } OUTPUT: RETVAL void uninstall (SV *context, long prev_poll_func) CODE: { GMainContext *ctx = get_gcontext (context); g_main_context_set_poll_func (ctx, (GPollFunc) prev_poll_func); }