1*0e552da7Schristos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2*0e552da7Schristos *
3*0e552da7Schristos * Permission is hereby granted, free of charge, to any person obtaining a copy
4*0e552da7Schristos * of this software and associated documentation files (the "Software"), to
5*0e552da7Schristos * deal in the Software without restriction, including without limitation the
6*0e552da7Schristos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7*0e552da7Schristos * sell copies of the Software, and to permit persons to whom the Software is
8*0e552da7Schristos * furnished to do so, subject to the following conditions:
9*0e552da7Schristos *
10*0e552da7Schristos * The above copyright notice and this permission notice shall be included in
11*0e552da7Schristos * all copies or substantial portions of the Software.
12*0e552da7Schristos *
13*0e552da7Schristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14*0e552da7Schristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15*0e552da7Schristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16*0e552da7Schristos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17*0e552da7Schristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18*0e552da7Schristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19*0e552da7Schristos * IN THE SOFTWARE.
20*0e552da7Schristos */
21*0e552da7Schristos
22*0e552da7Schristos #include "uv.h"
23*0e552da7Schristos #include "task.h"
24*0e552da7Schristos
25*0e552da7Schristos #include <stdio.h>
26*0e552da7Schristos #include <stdlib.h>
27*0e552da7Schristos
28*0e552da7Schristos static uv_cond_t condvar;
29*0e552da7Schristos static uv_mutex_t mutex;
30*0e552da7Schristos static uv_rwlock_t rwlock;
31*0e552da7Schristos static int step;
32*0e552da7Schristos
33*0e552da7Schristos /* The mutex and rwlock tests are really poor.
34*0e552da7Schristos * They're very basic sanity checks and nothing more.
35*0e552da7Schristos * Apologies if that rhymes.
36*0e552da7Schristos */
37*0e552da7Schristos
TEST_IMPL(thread_mutex)38*0e552da7Schristos TEST_IMPL(thread_mutex) {
39*0e552da7Schristos uv_mutex_t mutex;
40*0e552da7Schristos int r;
41*0e552da7Schristos
42*0e552da7Schristos r = uv_mutex_init(&mutex);
43*0e552da7Schristos ASSERT(r == 0);
44*0e552da7Schristos
45*0e552da7Schristos uv_mutex_lock(&mutex);
46*0e552da7Schristos uv_mutex_unlock(&mutex);
47*0e552da7Schristos uv_mutex_destroy(&mutex);
48*0e552da7Schristos
49*0e552da7Schristos return 0;
50*0e552da7Schristos }
51*0e552da7Schristos
52*0e552da7Schristos
TEST_IMPL(thread_mutex_recursive)53*0e552da7Schristos TEST_IMPL(thread_mutex_recursive) {
54*0e552da7Schristos uv_mutex_t mutex;
55*0e552da7Schristos int r;
56*0e552da7Schristos
57*0e552da7Schristos r = uv_mutex_init_recursive(&mutex);
58*0e552da7Schristos ASSERT(r == 0);
59*0e552da7Schristos
60*0e552da7Schristos uv_mutex_lock(&mutex);
61*0e552da7Schristos uv_mutex_lock(&mutex);
62*0e552da7Schristos ASSERT(0 == uv_mutex_trylock(&mutex));
63*0e552da7Schristos
64*0e552da7Schristos uv_mutex_unlock(&mutex);
65*0e552da7Schristos uv_mutex_unlock(&mutex);
66*0e552da7Schristos uv_mutex_unlock(&mutex);
67*0e552da7Schristos uv_mutex_destroy(&mutex);
68*0e552da7Schristos
69*0e552da7Schristos return 0;
70*0e552da7Schristos }
71*0e552da7Schristos
72*0e552da7Schristos
TEST_IMPL(thread_rwlock)73*0e552da7Schristos TEST_IMPL(thread_rwlock) {
74*0e552da7Schristos uv_rwlock_t rwlock;
75*0e552da7Schristos int r;
76*0e552da7Schristos
77*0e552da7Schristos r = uv_rwlock_init(&rwlock);
78*0e552da7Schristos ASSERT(r == 0);
79*0e552da7Schristos
80*0e552da7Schristos uv_rwlock_rdlock(&rwlock);
81*0e552da7Schristos uv_rwlock_rdunlock(&rwlock);
82*0e552da7Schristos uv_rwlock_wrlock(&rwlock);
83*0e552da7Schristos uv_rwlock_wrunlock(&rwlock);
84*0e552da7Schristos uv_rwlock_destroy(&rwlock);
85*0e552da7Schristos
86*0e552da7Schristos return 0;
87*0e552da7Schristos }
88*0e552da7Schristos
89*0e552da7Schristos
90*0e552da7Schristos /* Call when holding |mutex|. */
synchronize_nowait(void)91*0e552da7Schristos static void synchronize_nowait(void) {
92*0e552da7Schristos step += 1;
93*0e552da7Schristos uv_cond_signal(&condvar);
94*0e552da7Schristos }
95*0e552da7Schristos
96*0e552da7Schristos
97*0e552da7Schristos /* Call when holding |mutex|. */
synchronize(void)98*0e552da7Schristos static void synchronize(void) {
99*0e552da7Schristos int current;
100*0e552da7Schristos
101*0e552da7Schristos synchronize_nowait();
102*0e552da7Schristos /* Wait for the other thread. Guard against spurious wakeups. */
103*0e552da7Schristos for (current = step; current == step; uv_cond_wait(&condvar, &mutex));
104*0e552da7Schristos ASSERT(step == current + 1);
105*0e552da7Schristos }
106*0e552da7Schristos
107*0e552da7Schristos
thread_rwlock_trylock_peer(void * unused)108*0e552da7Schristos static void thread_rwlock_trylock_peer(void* unused) {
109*0e552da7Schristos (void) &unused;
110*0e552da7Schristos
111*0e552da7Schristos uv_mutex_lock(&mutex);
112*0e552da7Schristos
113*0e552da7Schristos /* Write lock held by other thread. */
114*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
115*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
116*0e552da7Schristos synchronize();
117*0e552da7Schristos
118*0e552da7Schristos /* Read lock held by other thread. */
119*0e552da7Schristos ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
120*0e552da7Schristos uv_rwlock_rdunlock(&rwlock);
121*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
122*0e552da7Schristos synchronize();
123*0e552da7Schristos
124*0e552da7Schristos /* Acquire write lock. */
125*0e552da7Schristos ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
126*0e552da7Schristos synchronize();
127*0e552da7Schristos
128*0e552da7Schristos /* Release write lock and acquire read lock. */
129*0e552da7Schristos uv_rwlock_wrunlock(&rwlock);
130*0e552da7Schristos ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
131*0e552da7Schristos synchronize();
132*0e552da7Schristos
133*0e552da7Schristos uv_rwlock_rdunlock(&rwlock);
134*0e552da7Schristos synchronize_nowait(); /* Signal main thread we're going away. */
135*0e552da7Schristos uv_mutex_unlock(&mutex);
136*0e552da7Schristos }
137*0e552da7Schristos
138*0e552da7Schristos
TEST_IMPL(thread_rwlock_trylock)139*0e552da7Schristos TEST_IMPL(thread_rwlock_trylock) {
140*0e552da7Schristos uv_thread_t thread;
141*0e552da7Schristos
142*0e552da7Schristos ASSERT(0 == uv_cond_init(&condvar));
143*0e552da7Schristos ASSERT(0 == uv_mutex_init(&mutex));
144*0e552da7Schristos ASSERT(0 == uv_rwlock_init(&rwlock));
145*0e552da7Schristos
146*0e552da7Schristos uv_mutex_lock(&mutex);
147*0e552da7Schristos ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL));
148*0e552da7Schristos
149*0e552da7Schristos /* Hold write lock. */
150*0e552da7Schristos ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
151*0e552da7Schristos synchronize(); /* Releases the mutex to the other thread. */
152*0e552da7Schristos
153*0e552da7Schristos /* Release write lock and acquire read lock. Pthreads doesn't support
154*0e552da7Schristos * the notion of upgrading or downgrading rwlocks, so neither do we.
155*0e552da7Schristos */
156*0e552da7Schristos uv_rwlock_wrunlock(&rwlock);
157*0e552da7Schristos ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
158*0e552da7Schristos synchronize();
159*0e552da7Schristos
160*0e552da7Schristos /* Release read lock. */
161*0e552da7Schristos uv_rwlock_rdunlock(&rwlock);
162*0e552da7Schristos synchronize();
163*0e552da7Schristos
164*0e552da7Schristos /* Write lock held by other thread. */
165*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
166*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
167*0e552da7Schristos synchronize();
168*0e552da7Schristos
169*0e552da7Schristos /* Read lock held by other thread. */
170*0e552da7Schristos ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
171*0e552da7Schristos uv_rwlock_rdunlock(&rwlock);
172*0e552da7Schristos ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
173*0e552da7Schristos synchronize();
174*0e552da7Schristos
175*0e552da7Schristos ASSERT(0 == uv_thread_join(&thread));
176*0e552da7Schristos uv_rwlock_destroy(&rwlock);
177*0e552da7Schristos uv_mutex_unlock(&mutex);
178*0e552da7Schristos uv_mutex_destroy(&mutex);
179*0e552da7Schristos uv_cond_destroy(&condvar);
180*0e552da7Schristos
181*0e552da7Schristos return 0;
182*0e552da7Schristos }
183