/** * Returns the default event loop object, this object is a global singleton * and it is not recommended to use it unless you require ChildEvent watchers * as they can only be attached to the default loop. * * @return EventLoop */ PHP_METHOD(EventLoop, getDefaultLoop) { /* Singleton */ if( ! default_event_loop_object) { ALLOC_INIT_ZVAL(default_event_loop_object); /* Create object without calling constructor, we now have an EventLoop missing the ev_loop */ if(object_init_ex(default_event_loop_object, event_loop_ce) != SUCCESS) { /* TODO: Error handling */ RETURN_BOOL(0); return; } event_loop_object *obj = (event_loop_object *)zend_object_store_get_object(default_event_loop_object TSRMLS_CC); assert( ! obj->loop); /* TODO: allow other EVFLAGs */ obj->loop = ev_default_loop(EVFLAG_AUTO); IF_DEBUG(ev_verify(obj->loop)); IF_DEBUG(libev_printf("Created default_event_loop_object\n")); } /* Return copy, no destruct on our local zval */ RETURN_ZVAL(default_event_loop_object, 1, 0); }
PHP_METHOD(PeriodicEvent, again) { /* TODO: Optional EventLoop parameter? */ event_object *event_obj = (event_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if(event_has_loop(event_obj)) { event_periodic_again(event_obj); if( ! event_is_active(event_obj) && ! event_is_pending(event_obj)) { /* No longer referenced by libev, so remove GC protection */ IF_DEBUG(libev_printf("ev_periodic_again() stopped non-repeating timer\n")); EVENT_LOOP_REF_DEL(event_obj); } RETURN_BOOL(1); } /* TODO: Throw exception */ RETURN_BOOL(0); }
/** * Feeds the given event set into the event loop, as if the specified event * had happened for the specified watcher. * * The watcher will be GC protected until it has fired or clearPending is called * on it (unless you feed it again in the callback or add() it to an event loop * it won't accidentally be freed). * * NOTE: As of libev 4.0.4; If you feed an event in the callback of a fed event, * the newly fed event will be invoked before any other events (except other * fed events). So do NOT create loops by re-feeding an event into the EventLoop * as that loop will block just as much as a normal loop. * * TODO: Add note about AsyncEvent when AsyncEvent is implemented * * @param Event * @return boolean false if either the EventLoop or Event has not been initialized */ PHP_METHOD(EventLoop, feedEvent) { int revents = 0; zval *event_obj; event_object *event; event_loop_object *loop_obj = (event_loop_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &event_obj, event_ce, &revents) != SUCCESS) { return; } event = (event_object *)zend_object_store_get_object(event_obj TSRMLS_CC); assert(loop_obj->loop); /* Only allow Events which are associated with this EventLoop or those which are not associated with any EventLoop yet */ if(loop_obj->loop && ( ! event_has_loop(event) || event_in_loop(loop_obj, event))) { IF_DEBUG(libev_printf("Feeding event with pending %d and active %d...", event_is_pending(event), event_is_active(event))); /* The event might already have a loop, no need to increase refcount */ if( ! event_has_loop(event)) { EVENT_LOOP_REF_ADD(event, loop_obj); } event_feed_event(loop_obj, event, revents); IF_DEBUG(php_printf(" done\n")); RETURN_BOOL(1); } RETURN_BOOL(0); }
/** * Removes the event from the event loop, will skip all pending events on it too. * * @param Event * @return boolean False if the Event is not associated with this EventLoop, * can also be false if there is an error */ PHP_METHOD(EventLoop, remove) { zval *event_obj; event_object *event; event_loop_object *loop_obj = (event_loop_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &event_obj, event_ce) != SUCCESS) { return; } event = (event_object *)zend_object_store_get_object(event_obj TSRMLS_CC); assert(loop_obj->loop); if(loop_obj->loop && event_is_active(event)) { assert(event->loop_obj); /* Check that the event is associated with us */ if( ! event_in_loop(loop_obj, event)) { IF_DEBUG(libev_printf("Event is not in this EventLoop\n")); RETURN_BOOL(0); } EVENT_STOP(event); /* Remove GC protection, no longer active or pending */ EVENT_LOOP_REF_DEL(event); RETURN_BOOL(1); } RETURN_BOOL(0); }
/** * Adds the event to the event loop. * * This method will increase the refcount on the supplied Event, protecting it * from garbage collection. Refcount will be decreased on remove or if the * EventLoop object is GCd. * * @param Event * @return boolean */ PHP_METHOD(EventLoop, add) { zval *zevent; event_object *event; event_loop_object *loop_obj = (event_loop_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zevent, event_ce) != SUCCESS) { return; } event = (event_object *)zend_object_store_get_object(zevent TSRMLS_CC); assert(loop_obj->loop); /* Check so the event is not associated with any EventLoop, also needs to check for active, no need to perform logic if it already is started */ if(loop_obj->loop && ! event_is_active(event)) { if(event_has_loop(event)) { if( ! event_in_loop(loop_obj, event)) { /* Attempting to add a fed event to this EventLoop which has been fed to another loop */ IF_DEBUG(libev_printf("Attempting to add() an event already associated with another EventLoop\n")); RETURN_BOOL(0); } } EVENT_WATCHER_ACTION(event, loop_obj, start, io) else EVENT_WATCHER_ACTION(event, loop_obj, start, timer) else EVENT_WATCHER_ACTION(event, loop_obj, start, periodic) else EVENT_WATCHER_ACTION(event, loop_obj, start, signal) else if(instance_of_class(event->std.ce, child_event_ce)) { /* Special logic, ev_child can only be attached to the default loop */ if( ! ev_is_default_loop(loop_obj->loop)) { /* TODO: libev-specific exception class here */ zend_throw_exception(NULL, "libev\\ChildEvent can only be added to the default event-loop", 1 TSRMLS_DC); return; } ev_child_start(loop_obj->loop, (ev_child *)event->watcher); IF_DEBUG(libev_printf("Calling ev_child_start\n")); } else EVENT_WATCHER_ACTION(event, loop_obj, start, stat) else EVENT_WATCHER_ACTION(event, loop_obj, start, idle) else EVENT_WATCHER_ACTION(event, loop_obj, start, async) else EVENT_WATCHER_ACTION(event, loop_obj, start, cleanup) if( ! event_has_loop(event)) { /* GC protection */ EVENT_LOOP_REF_ADD(event, loop_obj); } RETURN_BOOL(1); } RETURN_BOOL(0); }