+ event ((W)w, EV_TIMEOUT);
+ }
+}
+
+static void
+periodics_reify ()
+{
+ while (periodiccnt && periodics [0]->at <= ev_now)
+ {
+ struct ev_periodic *w = periodics [0];
+
+ /* first reschedule or stop timer */
+ if (w->interval)
+ {
+ w->at += floor ((ev_now - w->at) / w->interval + 1.) * w->interval;
+ assert (("periodic timeout in the past, negative interval?", w->at > ev_now));
+ downheap ((WT *)periodics, periodiccnt, 0);
+ }
+ else
+ evperiodic_stop (w); /* nonrepeating: stop timer */
+
+ event ((W)w, EV_TIMEOUT);
+ }
+}
+
+static void
+periodics_reschedule (ev_tstamp diff)
+{
+ int i;
+
+ /* adjust periodics after time jump */
+ for (i = 0; i < periodiccnt; ++i)
+ {
+ struct ev_periodic *w = periodics [i];
+
+ if (w->interval)
+ {
+ ev_tstamp diff = ceil ((ev_now - w->at) / w->interval) * w->interval;
+
+ if (fabs (diff) >= 1e-4)
+ {
+ evperiodic_stop (w);
+ evperiodic_start (w);
+
+ i = 0; /* restart loop, inefficient, but time jumps should be rare */
+ }
+ }
+ }
+}
+
+static void
+time_update ()
+{
+ int i;
+
+ ev_now = ev_time ();
+
+ if (have_monotonic)
+ {
+ ev_tstamp odiff = diff;
+
+ for (i = 4; --i; ) /* loop a few times, before making important decisions */
+ {
+ now = get_clock ();
+ diff = ev_now - now;
+
+ if (fabs (odiff - diff) < MIN_TIMEJUMP)
+ return; /* all is well */
+
+ ev_now = ev_time ();
+ }
+
+ periodics_reschedule (diff - odiff);
+ /* no timer adjustment, as the monotonic clock doesn't jump */
+ }
+ else
+ {
+ if (now > ev_now || now < ev_now - MAX_BLOCKTIME - MIN_TIMEJUMP)
+ {
+ periodics_reschedule (ev_now - now);
+
+ /* adjust timers. this is easy, as the offset is the same for all */
+ for (i = 0; i < timercnt; ++i)
+ timers [i]->at += diff;
+ }
+
+ now = ev_now;