I don't claim to be an expert in libev, but I found that using the ev_suspend(loop) and ev_resume(loop) will prevent the behaviour you are seeing. From the man page:
ev_suspend (loop) ev_resume (loop) These two functions suspend and resume an event loop, for use when the loop is not used for a while and timeouts should not be processed.
E.g.:
ev_run(loop, EVRUN_NOWAIT); // callback should not be called
ev_timer_stop(loop, &timer); // stop the timer
ev_suspend(loop); // suspend timer processing
sleep(5); // sleep 5 seconds, 5 is also the timer's timeout value
ev_resume(loop); // resume timer processing
// restart timer
ev_timer_init(&timer, timeout_cb, 5.0, 0.0);
ev_timer_start(loop, &timer);
Also I found that another possible solution is to use ev_timer_again() instead of ev_timer_start() which also prevents the behaviour you reported.
E.g.:
ev_timer_stop(loop, &timer); // stop the timer
sleep(5); // sleep 5 seconds, 5 is also the timer's timeout value
// restart timer
ev_timer_again(loop, &timer);