perl - Why won't AnyEvent::child callbacks ever run if interval timer events are always ready? -


update issue can resolved using fixes present in https://github.com/zbentley/anyevent-impl-perl-improved/tree/io-starvation

context:

i integrating anyevent otherwise-synchronous code. synchronous code needs install watchers (on timers, child processes, , files), wait @ least 1 watcher complete, synchronous/blocking/legacy stuff, , repeat.

i using pure-perl anyevent::loop-based event loop, enough purposes @ point; of need signal/process/timer tracking.

the problem:

if have callback can block event loop moment, child-process-exit events/callbacks never fire. simplest example make watches child process , runs interval timer. interval timer blocking before finishes:

use anyevent;  # start timer that, every 0.5 seconds, sleeps 1 second, prints "timer": $w2 = anyevent->timer(     after => 0,     interval => 0.5,     cb => sub {         sleep 1; # simulated blocking operation. if removed, works.         "timer";     }, );  # fork off pid waits 1 second , exits: $pid = fork(); if ( $pid == 0 ) {     sleep 1;     exit; }  # print "child" when child process exits: $w1 = anyevent->child(     pid => $pid,     cb => sub {         "child";     }, );  anyevent->condvar->recv; 

this code leaves child process zombied, , prints "timer" on , over, "ever" (i ran several minutes). if sleep 1 call removed callback timer, code works correctly , child process watcher fires expected.

i'd expect child watcher run (at point after child exited, , interval events in event queue ran, blocked, , finished), not.

the sleep 1 blocking operation. can replaced busy-wait or other thing takes long enough. doesn't need take second; appears need a) running during child-exit event/sigchld delivery, , b) result in interval being due run according wallclock.

questions:

why isn't anyevent ever running child-process watcher callback?

how can multiplex child-process-exit events interval events may block long next interval becomes due?

what i've tried:

my theory timer events become "ready" due time spent outside of event loop can indefinitely pre-empt other types of ready events (like child process watchers) somewhere inside anyevent. i've tried few things:

  • using anyevent::strict doesn't surface errors or change behavior in way.
  • partial solution: removing interval event @ point does make child process watcher fire (as if there's internal event polling/queue population done inside anyevent happens if there no timer events "ready" according wallclock). drawbacks: in general case doesn't work, since i'd have know when child process had exited know when postpone intervals, tautological.
  • partial solution: unlike child-process watchers, other interval timers seem able multiplex each other fine, can install manual call waitpid in interval timer check , reap children. drawbacks: child-waiting can artificially delayed (my use case involves lots of frequent process creation/destruction), anyevent::child watchers are installed , fire auto-reap child , not tell interval/waitpid timer, requiring orchestration, , feels i'm misusing anyevent.

the interval time between start of each timer callback, i.e. not time between end of callback , start of next callback. setup timer interval 0.5 , action timer sleep 1 second. means once timer triggered triggered again , again because interval on after timer returned.

thus depending on implementation of event loop might happen no other events processed because busy running same timer on , over. don't know underlying event loop using (check $anyevent::model) if @ source code of anyevent::loop (the loop pure perl implementation, i.e. model anyevent::impl::perl) find following code:

   if (@timer && $timer[0][0] <= $mnow) {       {          $timer = shift @timer;          $timer->[1] && $timer->[1]($timer);       } while @timer && $timer[0][0] <= $mnow; 

as can see busy executing timers long there timers need run. , setup of interval (0.5) , behavior of timer (sleep 1 second) there timer needs executed.

if instead change timer there actual room processing of other events setting interval larger blocking time (like 2 seconds instead of 0.5) works fine:

... interval => 2, cb => sub {     sleep 1; # simulated blocking operation. sleep less interval!!     "timer";   ... timer child timer timer 

Comments

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -