+/* This is intended to use from automated tests. */
+
+#ifdef ENABLE_CHECKING
+
+#define MAXTIMERS 10
+
+struct atimer_result
+{
+ /* Time when we expect this timer to trigger. */
+ struct timespec expected;
+
+ /* Timer status: -1 if not triggered, 0 if triggered
+ too early or too late, 1 if triggered timely. */
+ int intime;
+};
+
+static void
+debug_timer_callback (struct atimer *t)
+{
+ struct timespec now = current_timespec ();
+ struct atimer_result *r = (struct atimer_result *) t->client_data;
+ int result = timespec_cmp (now, r->expected);
+
+ if (result < 0)
+ /* Too early. */
+ r->intime = 0;
+ else if (result >= 0)
+ {
+#ifdef HAVE_SETITIMER
+ struct timespec delta = timespec_sub (now, r->expected);
+ /* Too late if later than expected + 0.01s. FIXME:
+ this should depend from system clock resolution. */
+ if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0)
+ r->intime = 0;
+ else
+#endif /* HAVE_SETITIMER */
+ r->intime = 1;
+ }
+}
+
+DEFUN ("debug-timer-check", Fdebug_timer_check, Sdebug_timer_check, 0, 0, 0,
+ doc: /* Run internal self-tests to check timers subsystem.
+Return t if all self-tests are passed, nil otherwise. */)
+ (void)
+{
+ int i, ok;
+ struct atimer *timer;
+ struct atimer_result *results[MAXTIMERS];
+ struct timespec t = make_timespec (0, 0);
+
+ /* Arm MAXTIMERS relative timers to trigger with 0.1s intervals. */
+ for (i = 0; i < MAXTIMERS; i++)
+ {
+ results[i] = xmalloc (sizeof (struct atimer_result));
+ t = timespec_add (t, make_timespec (0, 100000000));
+ results[i]->expected = timespec_add (current_timespec (), t);
+ results[i]->intime = -1;
+ timer = start_atimer (ATIMER_RELATIVE, t,
+ debug_timer_callback, results[i]);
+ }
+
+ /* Wait for 1s but process timers. */
+ wait_reading_process_output (1, 0, 0, false, Qnil, NULL, 0);
+ /* Shut up the compiler by "using" this variable. */
+ (void) timer;
+
+ for (i = 0, ok = 0; i < MAXTIMERS; i++)
+ ok += results[i]->intime, xfree (results[i]);
+
+ return ok == MAXTIMERS ? Qt : Qnil;
+}
+
+#endif /* ENABLE_CHECKING */