test-timer-correctness.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Test program to verify that scheduled timers are executed in the
  3. * correct order.
  4. *
  5. * Copyright (C) 2013 by Open Source Routing.
  6. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
  7. *
  8. * This file is part of Quagga
  9. *
  10. * Quagga is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2, or (at your option) any
  13. * later version.
  14. *
  15. * Quagga is distributed in the hope that it will be useful, but
  16. * WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with Quagga; see the file COPYING. If not, write to the Free
  22. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  23. * 02111-1307, USA.
  24. */
  25. #include <zebra.h>
  26. #include <stdio.h>
  27. #include <unistd.h>
  28. #include "memory.h"
  29. #include "pqueue.h"
  30. #include "prng.h"
  31. #include "thread.h"
  32. #define SCHEDULE_TIMERS 800
  33. #define REMOVE_TIMERS 200
  34. #define TIMESTR_LEN strlen("4294967296.999999")
  35. struct thread_master *master;
  36. static size_t log_buf_len;
  37. static size_t log_buf_pos;
  38. static char *log_buf;
  39. static size_t expected_buf_len;
  40. static size_t expected_buf_pos;
  41. static char *expected_buf;
  42. static struct prng *prng;
  43. static struct thread **timers;
  44. static int timers_pending;
  45. static void terminate_test(void)
  46. {
  47. int exit_code;
  48. if (strcmp(log_buf, expected_buf))
  49. {
  50. fprintf(stderr, "Expected output and received output differ.\n");
  51. fprintf(stderr, "---Expected output: ---\n%s", expected_buf);
  52. fprintf(stderr, "---Actual output: ---\n%s", log_buf);
  53. exit_code = 1;
  54. }
  55. else
  56. {
  57. printf("Expected output and actual output match.\n");
  58. exit_code = 0;
  59. }
  60. thread_master_free(master);
  61. XFREE(MTYPE_TMP, log_buf);
  62. XFREE(MTYPE_TMP, expected_buf);
  63. prng_free(prng);
  64. XFREE(MTYPE_TMP, timers);
  65. exit(exit_code);
  66. }
  67. static int timer_func(struct thread *thread)
  68. {
  69. int rv;
  70. rv = snprintf(log_buf + log_buf_pos, log_buf_len - log_buf_pos,
  71. "%s\n", (char*)thread->arg);
  72. assert(rv >= 0);
  73. log_buf_pos += rv;
  74. assert(log_buf_pos < log_buf_len);
  75. XFREE(MTYPE_TMP, thread->arg);
  76. timers_pending--;
  77. if (!timers_pending)
  78. terminate_test();
  79. return 0;
  80. }
  81. static int cmp_timeval(const void* a, const void *b)
  82. {
  83. const struct timeval *ta = *(struct timeval * const *)a;
  84. const struct timeval *tb = *(struct timeval * const *)b;
  85. if (timercmp(ta, tb, <))
  86. return -1;
  87. if (timercmp(ta, tb, >))
  88. return 1;
  89. return 0;
  90. }
  91. int main(int argc, char **argv)
  92. {
  93. int i, j;
  94. struct thread t;
  95. struct timeval **alarms;
  96. master = thread_master_create();
  97. log_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1;
  98. log_buf_pos = 0;
  99. log_buf = XMALLOC(MTYPE_TMP, log_buf_len);
  100. expected_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1;
  101. expected_buf_pos = 0;
  102. expected_buf = XMALLOC(MTYPE_TMP, expected_buf_len);
  103. prng = prng_new(0);
  104. timers = XMALLOC(MTYPE_TMP, SCHEDULE_TIMERS * sizeof(*timers));
  105. for (i = 0; i < SCHEDULE_TIMERS; i++)
  106. {
  107. long interval_msec;
  108. int ret;
  109. char *arg;
  110. /* Schedule timers to expire in 0..5 seconds */
  111. interval_msec = prng_rand(prng) % 5000;
  112. arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1);
  113. timers[i] = thread_add_timer_msec(master, timer_func, arg, interval_msec);
  114. ret = snprintf(arg, TIMESTR_LEN + 1, "%lld.%06lld",
  115. (long long)timers[i]->u.sands.tv_sec,
  116. (long long)timers[i]->u.sands.tv_usec);
  117. assert(ret > 0);
  118. assert((size_t)ret < TIMESTR_LEN + 1);
  119. timers_pending++;
  120. }
  121. for (i = 0; i < REMOVE_TIMERS; i++)
  122. {
  123. int index;
  124. index = prng_rand(prng) % SCHEDULE_TIMERS;
  125. if (!timers[index])
  126. continue;
  127. XFREE(MTYPE_TMP, timers[index]->arg);
  128. thread_cancel(timers[index]);
  129. timers[index] = NULL;
  130. timers_pending--;
  131. }
  132. /* We create an array of pointers to the alarm times and sort
  133. * that array. That sorted array is used to generate a string
  134. * representing the expected "output" of the timers when they
  135. * are run. */
  136. j = 0;
  137. alarms = XMALLOC(MTYPE_TMP, timers_pending * sizeof(*alarms));
  138. for (i = 0; i < SCHEDULE_TIMERS; i++)
  139. {
  140. if (!timers[i])
  141. continue;
  142. alarms[j++] = &timers[i]->u.sands;
  143. }
  144. qsort(alarms, j, sizeof(*alarms), cmp_timeval);
  145. for (i = 0; i < j; i++)
  146. {
  147. int ret;
  148. ret = snprintf(expected_buf + expected_buf_pos,
  149. expected_buf_len - expected_buf_pos,
  150. "%lld.%06lld\n",
  151. (long long)alarms[i]->tv_sec,
  152. (long long)alarms[i]->tv_usec);
  153. assert(ret > 0);
  154. expected_buf_pos += ret;
  155. assert(expected_buf_pos < expected_buf_len);
  156. }
  157. XFREE(MTYPE_TMP, alarms);
  158. while (thread_fetch(master, &t))
  159. thread_call(&t);
  160. return 0;
  161. }