Finally, this is it, the event handler. This function usually is called after you have initialised all your
watchers and you want to start handling events. It will ask the operating system for any new events, call
the watcher callbacks, and then repeat the whole process indefinitely: This is why event loops are called
loops.
If the flags argument is specified as 0, it will keep handling events until either no event watchers are active
anymore or ev_break was called.
The return value is false if there are no more active watchers (which usually means "all jobs done" or
"deadlock"), and true in all other cases (which usually means " you should call ev_run again").
Please note that an explicit ev_break is usually better than relying on all watchers to be stopped when
deciding when a program has finished (especially in interactive programs), but having a program that
automatically loops as long as it has to and no longer by virtue of relying on its watchers stopping
correctly, that is truly a thing of beauty.
This function is mostly exception-safe - you can break out of a ev_run call by calling longjmp in a callback,
throwing a C++ exception and so on. This does not decrement the ev_depth value, nor will it clear any
outstanding EVBREAK_ONE breaks.
A flags value of EVRUN_NOWAIT will look for new events, will handle those events and any already
outstanding ones, but will not wait and block your process in case there are no events and will return after
one iteration of the loop. This is sometimes useful to poll and handle new events while doing lengthy
calculations, to keep the program responsive.
A flags value of EVRUN_ONCE will look for new events (waiting if necessary) and will handle those and any
already outstanding ones. It will block your process until at least one new event arrives (which could be an
event internal to libev itself, so there is no guarantee that a user-registered callback will be called), and
will return after one iteration of the loop.
This is useful if you are waiting for some external event in conjunction with something not expressible
using other libev watchers (i.e. "roll your own ev_run"). However, a pair of ev_prepare/ev_check
watchers is usually a better approach for this kind of thing.
Here are the gory details of what ev_run does (this is for your understanding, not a guarantee that things
will work exactly like this in future versions):
- Increment loop depth.
- Reset the ev_break status.
- Before the first iteration, call any pending watchers.
LOOP:
- If EVFLAG_FORKCHECK was used, check for a fork.
- If a fork was detected (by any means), queue and call all fork watchers.
- Queue and call all prepare watchers.
- If ev_break was called, goto FINISH.
- If we have been forked, detach and recreate the kernel state
as to not disturb the other process.
- Update the kernel state with all outstanding changes.
- Update the "event loop time" (ev_now ()).
- Calculate for how long to sleep or block, if at all
(active idle watchers, EVRUN_NOWAIT or not having
any active watchers at all will result in not sleeping).
- Sleep if the I/O and timer collect interval say so.
- Increment loop iteration counter.
- Block the process, waiting for any events.
- Queue all outstanding I/O (fd) events.
- Update the "event loop time" (ev_now ()), and do time jump adjustments.
- Queue all expired timers.
- Queue all expired periodics.
- Queue all idle watchers with priority higher than that of pending events.
- Queue all check watchers.
- Call all queued watchers in reverse order (i.e. check watchers first).
Signals and child watchers are implemented as I/O watchers, and will
be handled here by queueing them when their watcher gets executed.
- If ev_break has been called, or EVRUN_ONCE or EVRUN_NOWAIT
were used, or there are no active watchers, goto FINISH, otherwise
continue with step LOOP.
FINISH:
- Reset the ev_break status iff it was EVBREAK_ONE.
- Decrement the loop depth.
- Return.
Example: Queue some jobs and then loop until no events are outstanding anymore.
... queue jobs here, make sure they register event watchers as long
... as they still have work to do (even an idle watcher will do..)
ev_run (my_loop, 0);
... jobs done or somebody called break. yeah!