test-condvar.c
Go to the documentation of this file.
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 struct worker_config;
29 
30 typedef void (*signal_func)(struct worker_config* c, int* flag);
31 typedef int (*wait_func)(struct worker_config* c, const int* flag);
32 
33 typedef struct worker_config {
34  uv_sem_t sem_waiting; /* post before waiting. */
35  uv_sem_t sem_signaled; /* post after signaling. */
39  int posted_1;
40  int posted_2;
44 
46  int use_broadcast,
47  signal_func signal_f,
48  wait_func wait_f) {
49  /* Wipe. */
50  memset(wc, 0, sizeof(*wc));
51 
52  /* Copy vars. */
53  wc->signal_cond = signal_f;
54  wc->wait_cond = wait_f;
55  wc->use_broadcast = use_broadcast;
56 
57  /* Init. */
58  ASSERT(0 == uv_sem_init(&wc->sem_waiting, 0));
59  ASSERT(0 == uv_sem_init(&wc->sem_signaled, 0));
60  ASSERT(0 == uv_cond_init(&wc->cond));
61  ASSERT(0 == uv_mutex_init(&wc->mutex));
62 }
63 
65  uv_mutex_destroy(&wc->mutex);
66  uv_cond_destroy(&wc->cond);
69 }
70 
71 /* arg is a worker_config.
72  * Call signal_cond then wait_cond.
73  * Partner should call wait then signal. */
74 static void worker(void* arg) {
75  worker_config* c = arg;
76  c->signal_cond(c, &c->posted_1);
77  c->wait_cond(c, &c->posted_2);
78 }
79 
80 /* 1. Signal a waiting waiter.
81  * 2. Tell waiter we finished. */
82 static void condvar_signal(worker_config* c, int* flag) {
83  /* Wait until waiter holds mutex and is preparing to wait. */
84  uv_sem_wait(&c->sem_waiting);
85 
86  /* Make sure waiter has begun waiting. */
87  uv_mutex_lock(&c->mutex);
88 
89  /* Help waiter differentiate between spurious and legitimate wakeup. */
90  ASSERT(*flag == 0);
91  *flag = 1;
92 
93  if (c->use_broadcast)
94  uv_cond_broadcast(&c->cond);
95  else
96  uv_cond_signal(&c->cond);
97 
98  uv_mutex_unlock(&c->mutex);
99 
100  /* Done signaling. */
101  uv_sem_post(&c->sem_signaled);
102 }
103 
104 /* 1. Wait on a signal.
105  * 2. Ensure that the signaler finished. */
106 static int condvar_wait(worker_config* c, const int* flag) {
107  uv_mutex_lock(&c->mutex);
108 
109  /* Tell signal'er that I am waiting. */
110  uv_sem_post(&c->sem_waiting);
111 
112  /* Wait until I get a non-spurious signal. */
113  do {
114  uv_cond_wait(&c->cond, &c->mutex);
115  } while (*flag == 0);
116  ASSERT(*flag == 1);
117 
118  uv_mutex_unlock(&c->mutex);
119 
120  /* Wait for my signal'er to finish. */
121  uv_sem_wait(&c->sem_signaled);
122 
123  return 0;
124 }
125 
126 /* uv_cond_wait: One thread signals, the other waits. */
127 TEST_IMPL(condvar_1) {
128  worker_config wc;
130 
131  /* Helper signal-then-wait. */
133  ASSERT(0 == uv_thread_create(&thread, worker, &wc));
134 
135  /* We wait-then-signal. */
136  ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1));
137  wc.signal_cond(&wc, &wc.posted_2);
138 
139  ASSERT(0 == uv_thread_join(&thread));
141 
142  return 0;
143 }
144 
145 /* uv_cond_wait: One thread broadcasts, the other waits. */
146 TEST_IMPL(condvar_2) {
147  worker_config wc;
149 
150  /* Helper to signal-then-wait. */
152  ASSERT(0 == uv_thread_create(&thread, worker, &wc));
153 
154  /* We wait-then-signal. */
155  ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1));
156  wc.signal_cond(&wc, &wc.posted_2);
157 
158  ASSERT(0 == uv_thread_join(&thread));
160 
161  return 0;
162 }
163 
164 /* 1. Wait on a signal (hopefully not timeout, else we'll hang).
165  * 2. Ensure that the signaler finished. */
166 static int condvar_timedwait(worker_config* c, const int* flag) {
167  int r;
168 
169  r = 0;
170 
171  uv_mutex_lock(&c->mutex);
172 
173  /* Tell signal'er that I am waiting. */
174  uv_sem_post(&c->sem_waiting);
175 
176  /* Wait until I get a non-spurious signal. */
177  do {
178  r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(1 * 1e9)); /* 1 s */
179  ASSERT(r == 0); /* Should not time out. */
180  } while (*flag == 0);
181  ASSERT(*flag == 1);
182 
183  uv_mutex_unlock(&c->mutex);
184 
185  /* Wait for my signal'er to finish. */
186  uv_sem_wait(&c->sem_signaled);
187  return r;
188 }
189 
190 /* uv_cond_timedwait: One thread signals, the other timedwaits. */
191 TEST_IMPL(condvar_3) {
192  worker_config wc;
194 
195  /* Helper to signal-then-wait. */
197  ASSERT(0 == uv_thread_create(&thread, worker, &wc));
198 
199  /* We wait-then-signal. */
200  wc.wait_cond(&wc, &wc.posted_1);
201  wc.signal_cond(&wc, &wc.posted_2);
202 
203  ASSERT(0 == uv_thread_join(&thread));
205 
206  return 0;
207 }
208 
209 /* uv_cond_timedwait: One thread broadcasts, the other waits. */
210 TEST_IMPL(condvar_4) {
211  worker_config wc;
213 
214  /* Helper to signal-then-wait. */
216  ASSERT(0 == uv_thread_create(&thread, worker, &wc));
217 
218  /* We wait-then-signal. */
219  wc.wait_cond(&wc, &wc.posted_1);
220  wc.signal_cond(&wc, &wc.posted_2);
221 
222  ASSERT(0 == uv_thread_join(&thread));
224 
225  return 0;
226 }
227 
228 /* uv_cond_timedwait: One thread waits, no signal. Timeout should be delivered. */
229 TEST_IMPL(condvar_5) {
230  worker_config wc;
231  int r;
232  /* ns */
234  uint64_t after;
235  uint64_t elapsed;
237 
238  timeout = 100 * 1000 * 1000; /* 100 ms in ns */
239 
240  /* Mostly irrelevant. We need cond and mutex initialized. */
241  worker_config_init(&wc, 0, NULL, NULL);
242 
243  uv_mutex_lock(&wc.mutex);
244 
245  /* We wait.
246  * No signaler, so this will only return if timeout is delivered. */
247  before = uv_hrtime();
248  r = uv_cond_timedwait(&wc.cond, &wc.mutex, timeout);
249  after = uv_hrtime();
250 
251  uv_mutex_unlock(&wc.mutex);
252 
253  /* It timed out. */
254  ASSERT(r == UV_ETIMEDOUT);
255 
256  /* It must have taken at least timeout, modulo system timer ticks.
257  * But it should not take too much longer.
258  * cf. MSDN docs:
259  * https://msdn.microsoft.com/en-us/library/ms687069(VS.85).aspx */
260  elapsed = after - before;
261  ASSERT(0.75 * timeout <= elapsed); /* 1.0 too large for Windows. */
262  ASSERT(elapsed <= 5.0 * timeout); /* MacOS has reported failures up to 1.75. */
263 
265 
266  return 0;
267 }
flag
uint32_t flag
Definition: ssl_versions.cc:162
worker_config::cond
uv_cond_t cond
Definition: test-condvar.c:37
worker_config::use_broadcast
int use_broadcast
Definition: test-condvar.c:38
worker_config::signal_cond
signal_func signal_cond
Definition: test-condvar.c:41
condvar_wait
static int condvar_wait(worker_config *c, const int *flag)
Definition: test-condvar.c:106
task.h
memset
return memset(p, 0, total)
worker_config::sem_signaled
uv_sem_t sem_signaled
Definition: test-condvar.c:35
uv_mutex_init
UV_EXTERN int uv_mutex_init(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:281
worker_config::posted_1
int posted_1
Definition: test-condvar.c:39
string.h
uv_mutex_destroy
UV_EXTERN void uv_mutex_destroy(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:323
ASSERT
#define ASSERT(expr)
Definition: task.h:102
uv_thread_join
UV_EXTERN int uv_thread_join(uv_thread_t *tid)
Definition: libuv/src/unix/thread.c:271
uv_cond_wait
UV_EXTERN void uv_cond_wait(uv_cond_t *cond, uv_mutex_t *mutex)
Definition: libuv/src/unix/thread.c:780
wait_func
int(* wait_func)(struct worker_config *c, const int *flag)
Definition: test-condvar.c:31
uv_cond_t
Definition: win.h:249
before
IntBeforeRegisterTypedTestSuiteP before
Definition: googletest/googletest/test/gtest-typed-test_test.cc:376
worker_config
struct worker_config worker_config
condvar_signal
static void condvar_signal(worker_config *c, int *flag)
Definition: test-condvar.c:82
c
void c(T a)
Definition: miscompile_with_no_unique_address_test.cc:40
xds_interop_client.int
int
Definition: xds_interop_client.py:113
uv_cond_destroy
UV_EXTERN void uv_cond_destroy(uv_cond_t *cond)
Definition: libuv/src/unix/thread.c:736
worker
Definition: worker.py:1
worker_config_init
void worker_config_init(worker_config *wc, int use_broadcast, signal_func signal_f, wait_func wait_f)
Definition: test-condvar.c:45
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
arg
Definition: cmdline.cc:40
worker_config::sem_waiting
uv_sem_t sem_waiting
Definition: test-condvar.c:34
uv_mutex_t
pthread_mutex_t uv_mutex_t
Definition: unix.h:135
uv_cond_timedwait
UV_EXTERN int uv_cond_timedwait(uv_cond_t *cond, uv_mutex_t *mutex, uint64_t timeout)
Definition: libuv/src/unix/thread.c:786
worker
static void worker(void *arg)
Definition: test-condvar.c:74
uv_thread_create
UV_EXTERN int uv_thread_create(uv_thread_t *tid, uv_thread_cb entry, void *arg)
Definition: libuv/src/unix/thread.c:209
uv_mutex_unlock
UV_EXTERN void uv_mutex_unlock(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:349
uv_sem_t
UV_PLATFORM_SEM_T uv_sem_t
Definition: unix.h:137
signal_func
void(* signal_func)(struct worker_config *c, int *flag)
Definition: test-condvar.c:30
after
IntAfterTypedTestSuiteP after
Definition: googletest/googletest/test/gtest-typed-test_test.cc:375
uv_sem_post
UV_EXTERN void uv_sem_post(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:669
uv_cond_broadcast
UV_EXTERN void uv_cond_broadcast(uv_cond_t *cond)
Definition: libuv/src/unix/thread.c:775
uv_sem_init
UV_EXTERN int uv_sem_init(uv_sem_t *sem, unsigned int value)
Definition: libuv/src/unix/thread.c:649
uv.h
uv_sem_destroy
UV_EXTERN void uv_sem_destroy(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:661
uv_mutex_lock
UV_EXTERN void uv_mutex_lock(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:329
uv_hrtime
UV_EXTERN uint64_t uv_hrtime(void)
Definition: unix/core.c:107
fix_build_deps.r
r
Definition: fix_build_deps.py:491
worker_config::wait_cond
wait_func wait_cond
Definition: test-condvar.c:42
condvar_timedwait
static int condvar_timedwait(worker_config *c, const int *flag)
Definition: test-condvar.c:166
arg
struct arg arg
uv_cond_init
UV_EXTERN int uv_cond_init(uv_cond_t *cond)
Definition: libuv/src/unix/thread.c:703
TEST_IMPL
TEST_IMPL(condvar_1)
Definition: test-condvar.c:127
uv_cond_signal
UV_EXTERN void uv_cond_signal(uv_cond_t *cond)
Definition: libuv/src/unix/thread.c:770
uv_thread_t
pthread_t uv_thread_t
Definition: unix.h:134
uv_sem_wait
UV_EXTERN void uv_sem_wait(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:677
worker_config_destroy
void worker_config_destroy(worker_config *wc)
Definition: test-condvar.c:64
worker_config
Definition: test-barrier.c:28
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
worker_config::posted_2
int posted_2
Definition: test-condvar.c:40
timeout
uv_timer_t timeout
Definition: libuv/docs/code/uvwget/main.c:9
errno.h
worker_config::mutex
uv_mutex_t mutex
Definition: test-condvar.c:36


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:26