Event::add() on event signal notice in forked child...

Issue #9 closed
Former user created an issue

Description:

i initialise EventBase on master process. $this->base = new EventBase();

i add signal event like that on master process:

$event = new Event($this->base, SIGTERM, Event::SIGNAL | Event::PERSIST , array($this, "EventTERM")); $event->add();

i initialise another eventbase

$this->listenerbase = new EventBase();

i initialise EventListener on socket in master process on this base. $listener = new EventListener($this->listenerbase, [$this, 'ev_accept'], $this, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, "localhost:80"))

i fork and in the child i reinit the EventListener EventBase and try to unset the first EventBase who i've attached the signal SIGTERM and add new signal event SIGTERM on the listenerbase then dispatch on them.

but notice a the message: Notice: Event::add(): Added a signal to event base 0x1d43f30 with signals already added to event_base 0x1d3aec0. Only one can have signals at a time with the epoll backend.

when searching on the net about this message i found similar use of signal handler on libevent list: http://archives.seul.org/libevent/users/Mar-2011/msg00008.html http://sourceforge.net/p/levent/bugs/224/

the probleme are in fact that cannot free completly the master process eventbase on the child...

i've tryed to reinit, and delete/free all event, and unset the eventbase object... and force collecting garbage...

and the notice while continue to appeare...

Expected result:

to abel to completely free the eventbase to avoid this notice message. in the object version of this extension the freeing of the eventbase rely on the destruction of the object... adding free method on the eventbase to explicitly free the object while resolve the probleme i think...

Comments (5)

  1. Mathieu CARBONNEAUX

    i've added method free on event_base object to call event_base_free. and using it after fork resolve the problem has espected in libevent bugtraker.

  2. Mathieu CARBONNEAUX
    diff --git a/classes/base.c b/classes/base.c
    index 8f3520a..28fa00c 100644
    --- a/classes/base.c
    +++ b/classes/base.c
    @@ -318,6 +318,23 @@ PHP_METHOD(EventBase, updateCacheTime)
     /* }}} */
     #endif
    
    +/* {{{ proto void EventBase::free(void); */
    +PHP_METHOD(EventBase, free)
    +{
    +       zval               *zbase = getThis();
    +       php_event_base_t *b;
    +
    +       if (zend_parse_parameters_none() == FAILURE) {
    +               return;
    +       }
    +
    +       PHP_EVENT_FETCH_BASE(b, zbase);
    +
    +       event_base_free(b->base);
    +       b->base=NULL;
    +}
    +/* }}} */
    +
     /* {{{ proto bool EventBase::reInit(void);
      * Re-initialize event base. Should be called after a fork.
      * XXX pthread_atfork() in MINIT */
    diff --git a/src/fe.c b/src/fe.c
    index 11c3794..98c6da5 100644
    --- a/src/fe.c
    +++ b/src/fe.c
    @@ -527,6 +527,7 @@ const zend_function_entry php_event_base_ce_functions[] = {/* {{{ */
            PHP_ME(EventBase, gotExit,            arginfo_event__void,              ZEND_ACC_PUBLIC)
            PHP_ME(EventBase, getTimeOfDayCached, arginfo_event__void,              ZEND_ACC_PUBLIC)
            PHP_ME(EventBase, reInit,             arginfo_event__void,              ZEND_ACC_PUBLIC)
    +       PHP_ME(EventBase, free,               arginfo_event__void,              ZEND_ACC_PUBLIC)
     #if LIBEVENT_VERSION_NUMBER >= 0x02010100
            PHP_ME(EventBase, updateCacheTime, arginfo_event__void, ZEND_ACC_PUBLIC)
     #endif
    diff --git a/src/fe.h b/src/fe.h
    index 0f89336..5d93049 100644
    --- a/src/fe.h
    +++ b/src/fe.h
    @@ -50,6 +50,7 @@ PHP_METHOD(EventBase, getTimeOfDayCached);
     PHP_METHOD(EventBase, updateCacheTime);
     #endif
     PHP_METHOD(EventBase, reInit);
    +PHP_METHOD(EventBase, free);
     #if LIBEVENT_VERSION_NUMBER >= 0x02010200
     PHP_METHOD(EventBase, resume);
     #endif
    
  3. Mathieu CARBONNEAUX

    her the snipet of code...

     // in master process create two event base ($base), one for managing child exit signal and timer to supervise information about child
     // the second event base ($listenbase) are attached with eventlistener on socket that while be listened on child
     // when fork to create worker:
    
    function create_worker()
    {
         $pid = pcntl_fork();
         if ( $pid === -1 )
         {
            printf("Fork Failure\n");
            return false;
         }
         if ( $pid === 0 )
         {
            $worker_pid = posix_getpid();
            printf("Worker with pid:%s started at <%s>\n",$worker_pid,gmdate('r'));
    
            // The child process ignores SIGINT (small race here)
            pcntl_sigprocmask( SIG_BLOCK, array(SIGINT) );
    
            // purge global event base
            // and lets go of the parent's libevent base
            if (!$base->reInit())
            {
              die("Error EventBase reInit!\n");
            }
            // and breaks out of the service event loop
            if (!$base->stop())
            {
              die("Error EventBase reInit!\n");
            }
    
            // in process master a store refence of all added event
            // and in child i dismantles the whole event structure
            foreach ( $this->events as $i => &$event )
            {
              $event->free();
              unset($events);
            }
    
            // try to free eventbase
            $base->free();
            unset($base);
    
            // worker running there ... 
            $listenbase->reInit()
            // add signal on child handling to handle TERM signal form master process when it die
            // without the event_base_free when add signal on signal already added on master process on the other eventbase they send the warning ...
            // Notice: Event::add(): Added a signal to event base 0x1d43f30 with signals already added to event_base 0x1d3aec0. Only one can have signals at a time with the epoll backend.
            // and then dispatch to listen on eventlistener initialised on socket in master process
            $listenbase->dispatch();
          }
    }
    
  4. Log in to comment