pollable.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. * A test for the pollable events.
  7. *
  8. * A number of threads are in a ring configuration, each waiting on
  9. * a pollable event that is set by its upstream neighbor.
  10. */
  11. #include "prinit.h"
  12. #include "prio.h"
  13. #include "prthread.h"
  14. #include "prerror.h"
  15. #include "prmem.h"
  16. #include "prlog.h"
  17. #include "prprf.h"
  18. #include "plgetopt.h"
  19. #include <stdlib.h>
  20. #define DEFAULT_THREADS 10
  21. #define DEFAULT_LOOPS 100
  22. PRIntn numThreads = DEFAULT_THREADS;
  23. PRIntn numIterations = DEFAULT_LOOPS;
  24. PRIntervalTime dally = PR_INTERVAL_NO_WAIT;
  25. PRFileDesc *debug_out = NULL;
  26. PRBool debug_mode = PR_FALSE;
  27. PRBool verbosity = PR_FALSE;
  28. typedef struct ThreadData {
  29. PRFileDesc *event;
  30. int index;
  31. struct ThreadData *next;
  32. } ThreadData;
  33. void ThreadRoutine(void *arg)
  34. {
  35. ThreadData *data = (ThreadData *) arg;
  36. PRIntn i;
  37. PRPollDesc pd;
  38. PRInt32 rv;
  39. pd.fd = data->event;
  40. pd.in_flags = PR_POLL_READ;
  41. for (i = 0; i < numIterations; i++) {
  42. rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
  43. if (rv == -1) {
  44. PR_fprintf(PR_STDERR, "PR_Poll failed\n");
  45. exit(1);
  46. }
  47. if (verbosity) {
  48. PR_fprintf(debug_out, "thread %d awakened\n", data->index);
  49. }
  50. PR_ASSERT(rv != 0);
  51. PR_ASSERT(pd.out_flags & PR_POLL_READ);
  52. if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) {
  53. PR_fprintf(PR_STDERR, "consume event failed\n");
  54. exit(1);
  55. }
  56. if (dally != PR_INTERVAL_NO_WAIT) {
  57. PR_Sleep(dally);
  58. }
  59. if (verbosity) {
  60. PR_fprintf(debug_out, "thread %d posting event\n", data->index);
  61. }
  62. if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) {
  63. PR_fprintf(PR_STDERR, "post event failed\n");
  64. exit(1);
  65. }
  66. }
  67. }
  68. static void Help(void)
  69. {
  70. debug_out = PR_STDOUT;
  71. PR_fprintf(
  72. debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n");
  73. PR_fprintf(
  74. debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
  75. PR_fprintf(
  76. debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
  77. PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
  78. PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
  79. PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
  80. PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
  81. PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n");
  82. } /* Help */
  83. int main(int argc, char **argv)
  84. {
  85. ThreadData selfData;
  86. ThreadData *data;
  87. PRThread **thread;
  88. void *block;
  89. PRIntn i;
  90. PRIntervalTime timeStart, timeEnd;
  91. PRPollDesc pd;
  92. PRInt32 rv;
  93. PRThreadScope thread_scope = PR_LOCAL_THREAD;
  94. PRBool help = PR_FALSE;
  95. PRUintn concurrency = 1;
  96. PRUintn average;
  97. PLOptStatus os;
  98. PLOptState *opt;
  99. PR_STDIO_INIT();
  100. opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:");
  101. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
  102. if (PL_OPT_BAD == os) {
  103. continue;
  104. }
  105. switch (opt->option) {
  106. case 'v': /* verbose mode */
  107. verbosity = PR_TRUE;
  108. case 'd': /* debug mode */
  109. debug_mode = PR_TRUE;
  110. break;
  111. case 'c': /* loop counter */
  112. numIterations = atoi(opt->value);
  113. break;
  114. case 't': /* thread limit */
  115. numThreads = atoi(opt->value);
  116. break;
  117. case 'C': /* Concurrency limit */
  118. concurrency = atoi(opt->value);
  119. break;
  120. case 'G': /* global threads only */
  121. thread_scope = PR_GLOBAL_THREAD;
  122. break;
  123. case 'D': /* dally */
  124. dally = PR_MillisecondsToInterval(atoi(opt->value));
  125. break;
  126. case 'h': /* help message */
  127. Help();
  128. help = PR_TRUE;
  129. break;
  130. default:
  131. break;
  132. }
  133. }
  134. PL_DestroyOptState(opt);
  135. if (help) {
  136. return 1;
  137. }
  138. if (concurrency > 1) {
  139. PR_SetConcurrency(concurrency);
  140. }
  141. if (PR_TRUE == debug_mode) {
  142. debug_out = PR_STDOUT;
  143. PR_fprintf(debug_out, "Test parameters\n");
  144. PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads);
  145. PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations);
  146. PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
  147. PR_fprintf(debug_out, "\tThread type: %s\n",
  148. (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
  149. }
  150. /*
  151. * Malloc a block of memory and divide it into data and thread.
  152. */
  153. block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *)));
  154. if (block == NULL) {
  155. PR_fprintf(PR_STDERR, "cannot malloc, failed\n");
  156. exit(1);
  157. }
  158. data = (ThreadData *) block;
  159. thread = (PRThread **) &data[numThreads];
  160. /* Pollable event */
  161. selfData.event = PR_NewPollableEvent();
  162. if (selfData.event == NULL) {
  163. PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
  164. PR_GetError(), PR_GetOSError());
  165. exit(1);
  166. }
  167. selfData.next = &data[0];
  168. for (i = 0; i < numThreads; i++) {
  169. data[i].event = PR_NewPollableEvent();
  170. if (data[i].event == NULL) {
  171. PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
  172. PR_GetError(), PR_GetOSError());
  173. exit(1);
  174. }
  175. data[i].index = i;
  176. if (i != numThreads - 1) {
  177. data[i].next = &data[i + 1];
  178. } else {
  179. data[i].next = &selfData;
  180. }
  181. thread[i] = PR_CreateThread(PR_USER_THREAD,
  182. ThreadRoutine, &data[i], PR_PRIORITY_NORMAL,
  183. thread_scope, PR_JOINABLE_THREAD, 0);
  184. if (thread[i] == NULL) {
  185. PR_fprintf(PR_STDERR, "cannot create thread\n");
  186. exit(1);
  187. }
  188. }
  189. timeStart = PR_IntervalNow();
  190. pd.fd = selfData.event;
  191. pd.in_flags = PR_POLL_READ;
  192. for (i = 0; i < numIterations; i++) {
  193. if (dally != PR_INTERVAL_NO_WAIT) {
  194. PR_Sleep(dally);
  195. }
  196. if (verbosity) {
  197. PR_fprintf(debug_out, "main thread posting event\n");
  198. }
  199. if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) {
  200. PR_fprintf(PR_STDERR, "set event failed\n");
  201. exit(1);
  202. }
  203. rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
  204. if (rv == -1) {
  205. PR_fprintf(PR_STDERR, "wait failed\n");
  206. exit(1);
  207. }
  208. PR_ASSERT(rv != 0);
  209. PR_ASSERT(pd.out_flags & PR_POLL_READ);
  210. if (verbosity) {
  211. PR_fprintf(debug_out, "main thread awakened\n");
  212. }
  213. if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) {
  214. PR_fprintf(PR_STDERR, "consume event failed\n");
  215. exit(1);
  216. }
  217. }
  218. timeEnd = PR_IntervalNow();
  219. if (debug_mode) {
  220. average = PR_IntervalToMicroseconds(timeEnd - timeStart)
  221. / (numIterations * numThreads);
  222. PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n",
  223. average, numThreads);
  224. }
  225. for (i = 0; i < numThreads; i++) {
  226. if (PR_JoinThread(thread[i]) == PR_FAILURE) {
  227. PR_fprintf(PR_STDERR, "join thread failed\n");
  228. exit(1);
  229. }
  230. PR_DestroyPollableEvent(data[i].event);
  231. }
  232. PR_DELETE(block);
  233. PR_DestroyPollableEvent(selfData.event);
  234. PR_fprintf(PR_STDOUT, "PASSED\n");
  235. return 0;
  236. }