xref: /libuv/test/test-barrier.c (revision 011a1ac1)
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "task.h"
24 
25 #include <string.h>
26 #include <errno.h>
27 
28 typedef struct {
29   uv_barrier_t barrier;
30   unsigned delay;
31   unsigned niter;
32   unsigned main_barrier_wait_rval;
33   unsigned worker_barrier_wait_rval;
34 } worker_config;
35 
36 
worker(void * arg)37 static void worker(void* arg) {
38   worker_config* c = arg;
39   unsigned i;
40 
41   if (c->delay)
42     uv_sleep(c->delay);
43 
44   for (i = 0; i < c->niter; i++)
45     c->worker_barrier_wait_rval += uv_barrier_wait(&c->barrier);
46 }
47 
48 
TEST_IMPL(barrier_1)49 TEST_IMPL(barrier_1) {
50   uv_thread_t thread;
51   worker_config wc;
52 
53   memset(&wc, 0, sizeof(wc));
54   wc.niter = 1;
55 
56   ASSERT_OK(uv_barrier_init(&wc.barrier, 2));
57   ASSERT_OK(uv_thread_create(&thread, worker, &wc));
58 
59   uv_sleep(100);
60   wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
61 
62   ASSERT_OK(uv_thread_join(&thread));
63   uv_barrier_destroy(&wc.barrier);
64 
65   ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
66 
67   return 0;
68 }
69 
70 
TEST_IMPL(barrier_2)71 TEST_IMPL(barrier_2) {
72   uv_thread_t thread;
73   worker_config wc;
74 
75   memset(&wc, 0, sizeof(wc));
76   wc.delay = 100;
77   wc.niter = 1;
78 
79   ASSERT_OK(uv_barrier_init(&wc.barrier, 2));
80   ASSERT_OK(uv_thread_create(&thread, worker, &wc));
81 
82   wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
83 
84   ASSERT_OK(uv_thread_join(&thread));
85   uv_barrier_destroy(&wc.barrier);
86 
87   ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
88 
89   return 0;
90 }
91 
92 
TEST_IMPL(barrier_3)93 TEST_IMPL(barrier_3) {
94   uv_thread_t thread;
95   worker_config wc;
96   unsigned i;
97 
98   memset(&wc, 0, sizeof(wc));
99   wc.niter = 5;
100 
101   ASSERT_OK(uv_barrier_init(&wc.barrier, 2));
102   ASSERT_OK(uv_thread_create(&thread, worker, &wc));
103 
104   for (i = 0; i < wc.niter; i++)
105     wc.main_barrier_wait_rval += uv_barrier_wait(&wc.barrier);
106 
107   ASSERT_OK(uv_thread_join(&thread));
108   uv_barrier_destroy(&wc.barrier);
109 
110   ASSERT_EQ(wc.niter, wc.main_barrier_wait_rval + wc.worker_barrier_wait_rval);
111 
112   return 0;
113 }
114 
serial_worker(void * data)115 static void serial_worker(void* data) {
116   uv_barrier_t* barrier;
117   unsigned i;
118 
119   barrier = data;
120   for (i = 0; i < 5; i++)
121     uv_barrier_wait(barrier);
122   if (uv_barrier_wait(barrier) > 0)
123     uv_barrier_destroy(barrier);
124 
125   uv_sleep(100);  /* Wait a bit before terminating. */
126 }
127 
128 /* Ensure that uv_barrier_wait returns positive only after all threads have
129  * exited the barrier. If this value is returned too early and the barrier is
130  * destroyed prematurely, then this test may see a crash. */
TEST_IMPL(barrier_serial_thread)131 TEST_IMPL(barrier_serial_thread) {
132   uv_thread_t threads[4];
133   uv_barrier_t barrier;
134   unsigned i;
135 
136   ASSERT_OK(uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1));
137 
138   for (i = 0; i < ARRAY_SIZE(threads); ++i)
139     ASSERT_OK(uv_thread_create(&threads[i], serial_worker, &barrier));
140 
141   for (i = 0; i < 5; i++)
142     uv_barrier_wait(&barrier);
143   if (uv_barrier_wait(&barrier) > 0)
144     uv_barrier_destroy(&barrier);
145 
146   for (i = 0; i < ARRAY_SIZE(threads); ++i)
147     ASSERT_OK(uv_thread_join(&threads[i]));
148 
149   return 0;
150 }
151 
152 /* Single thread uv_barrier_wait should return correct return value. */
TEST_IMPL(barrier_serial_thread_single)153 TEST_IMPL(barrier_serial_thread_single) {
154   uv_barrier_t barrier;
155 
156   ASSERT_OK(uv_barrier_init(&barrier, 1));
157   ASSERT_LT(0, uv_barrier_wait(&barrier));
158   uv_barrier_destroy(&barrier);
159   return 0;
160 }
161