test_threads.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* Copyright (c) 2001-2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2013, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "orconfig.h"
  6. #include "or.h"
  7. #include "compat_threads.h"
  8. #include "test.h"
  9. /** mutex for thread test to stop the threads hitting data at the same time. */
  10. static tor_mutex_t *thread_test_mutex_ = NULL;
  11. /** mutexes for the thread test to make sure that the threads have to
  12. * interleave somewhat. */
  13. static tor_mutex_t *thread_test_start1_ = NULL,
  14. *thread_test_start2_ = NULL;
  15. /** Shared strmap for the thread test. */
  16. static strmap_t *thread_test_strmap_ = NULL;
  17. /** The name of thread1 for the thread test */
  18. static char *thread1_name_ = NULL;
  19. /** The name of thread2 for the thread test */
  20. static char *thread2_name_ = NULL;
  21. static void thread_test_func_(void* _s) ATTR_NORETURN;
  22. /** How many iterations have the threads in the unit test run? */
  23. static int t1_count = 0, t2_count = 0;
  24. /** Helper function for threading unit tests: This function runs in a
  25. * subthread. It grabs its own mutex (start1 or start2) to make sure that it
  26. * should start, then it repeatedly alters _test_thread_strmap protected by
  27. * thread_test_mutex_. */
  28. static void
  29. thread_test_func_(void* _s)
  30. {
  31. char *s = _s;
  32. int i, *count;
  33. tor_mutex_t *m;
  34. char buf[64];
  35. char **cp;
  36. if (!strcmp(s, "thread 1")) {
  37. m = thread_test_start1_;
  38. cp = &thread1_name_;
  39. count = &t1_count;
  40. } else {
  41. m = thread_test_start2_;
  42. cp = &thread2_name_;
  43. count = &t2_count;
  44. }
  45. tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id());
  46. *cp = tor_strdup(buf);
  47. tor_mutex_acquire(m);
  48. for (i=0; i<10000; ++i) {
  49. tor_mutex_acquire(thread_test_mutex_);
  50. strmap_set(thread_test_strmap_, "last to run", *cp);
  51. ++*count;
  52. tor_mutex_release(thread_test_mutex_);
  53. }
  54. tor_mutex_acquire(thread_test_mutex_);
  55. strmap_set(thread_test_strmap_, s, *cp);
  56. tor_mutex_release(thread_test_mutex_);
  57. tor_mutex_release(m);
  58. spawn_exit();
  59. }
  60. /** Run unit tests for threading logic. */
  61. static void
  62. test_threads_basic(void *arg)
  63. {
  64. char *s1 = NULL, *s2 = NULL;
  65. int done = 0, timedout = 0;
  66. time_t started;
  67. #ifndef _WIN32
  68. struct timeval tv;
  69. tv.tv_sec=0;
  70. tv.tv_usec=100*1000;
  71. #endif
  72. (void)arg;
  73. thread_test_mutex_ = tor_mutex_new();
  74. thread_test_start1_ = tor_mutex_new();
  75. thread_test_start2_ = tor_mutex_new();
  76. thread_test_strmap_ = strmap_new();
  77. s1 = tor_strdup("thread 1");
  78. s2 = tor_strdup("thread 2");
  79. tor_mutex_acquire(thread_test_start1_);
  80. tor_mutex_acquire(thread_test_start2_);
  81. spawn_func(thread_test_func_, s1);
  82. spawn_func(thread_test_func_, s2);
  83. tor_mutex_release(thread_test_start2_);
  84. tor_mutex_release(thread_test_start1_);
  85. started = time(NULL);
  86. while (!done) {
  87. tor_mutex_acquire(thread_test_mutex_);
  88. strmap_assert_ok(thread_test_strmap_);
  89. if (strmap_get(thread_test_strmap_, "thread 1") &&
  90. strmap_get(thread_test_strmap_, "thread 2")) {
  91. done = 1;
  92. } else if (time(NULL) > started + 150) {
  93. timedout = done = 1;
  94. }
  95. tor_mutex_release(thread_test_mutex_);
  96. #ifndef _WIN32
  97. /* Prevent the main thread from starving the worker threads. */
  98. select(0, NULL, NULL, NULL, &tv);
  99. #endif
  100. }
  101. tor_mutex_acquire(thread_test_start1_);
  102. tor_mutex_release(thread_test_start1_);
  103. tor_mutex_acquire(thread_test_start2_);
  104. tor_mutex_release(thread_test_start2_);
  105. tor_mutex_free(thread_test_mutex_);
  106. if (timedout) {
  107. printf("\nTimed out: %d %d", t1_count, t2_count);
  108. tt_assert(strmap_get(thread_test_strmap_, "thread 1"));
  109. tt_assert(strmap_get(thread_test_strmap_, "thread 2"));
  110. tt_assert(!timedout);
  111. }
  112. /* different thread IDs. */
  113. tt_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
  114. strmap_get(thread_test_strmap_, "thread 2")));
  115. tt_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
  116. strmap_get(thread_test_strmap_, "last to run")) ||
  117. !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
  118. strmap_get(thread_test_strmap_, "last to run")));
  119. done:
  120. tor_free(s1);
  121. tor_free(s2);
  122. tor_free(thread1_name_);
  123. tor_free(thread2_name_);
  124. if (thread_test_strmap_)
  125. strmap_free(thread_test_strmap_, NULL);
  126. if (thread_test_start1_)
  127. tor_mutex_free(thread_test_start1_);
  128. if (thread_test_start2_)
  129. tor_mutex_free(thread_test_start2_);
  130. }
  131. #define THREAD_TEST(name) \
  132. { #name, test_threads_##name, TT_FORK, NULL, NULL }
  133. struct testcase_t thread_tests[] = {
  134. THREAD_TEST(basic),
  135. END_OF_TESTCASES
  136. };