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 <stdio.h> 26#include <stdlib.h> 27 28static uv_cond_t condvar; 29static uv_mutex_t mutex; 30static uv_rwlock_t rwlock; 31static int step; 32 33/* The mutex and rwlock tests are really poor. 34 * They're very basic sanity checks and nothing more. 35 * Apologies if that rhymes. 36 */ 37 38TEST_IMPL(thread_mutex) { 39 uv_mutex_t mutex; 40 int r; 41 42 r = uv_mutex_init(&mutex); 43 ASSERT(r == 0); 44 45 uv_mutex_lock(&mutex); 46 uv_mutex_unlock(&mutex); 47 uv_mutex_destroy(&mutex); 48 49 return 0; 50} 51 52 53TEST_IMPL(thread_mutex_recursive) { 54 uv_mutex_t mutex; 55 int r; 56 57 r = uv_mutex_init_recursive(&mutex); 58 ASSERT(r == 0); 59 60 uv_mutex_lock(&mutex); 61 uv_mutex_lock(&mutex); 62 ASSERT(0 == uv_mutex_trylock(&mutex)); 63 64 uv_mutex_unlock(&mutex); 65 uv_mutex_unlock(&mutex); 66 uv_mutex_unlock(&mutex); 67 uv_mutex_destroy(&mutex); 68 69 return 0; 70} 71 72 73TEST_IMPL(thread_rwlock) { 74 uv_rwlock_t rwlock; 75 int r; 76 77 r = uv_rwlock_init(&rwlock); 78 ASSERT(r == 0); 79 80 uv_rwlock_rdlock(&rwlock); 81 uv_rwlock_rdunlock(&rwlock); 82 uv_rwlock_wrlock(&rwlock); 83 uv_rwlock_wrunlock(&rwlock); 84 uv_rwlock_destroy(&rwlock); 85 86 return 0; 87} 88 89 90/* Call when holding |mutex|. */ 91static void synchronize_nowait(void) { 92 step += 1; 93 uv_cond_signal(&condvar); 94} 95 96 97/* Call when holding |mutex|. */ 98static void synchronize(void) { 99 int current; 100 101 synchronize_nowait(); 102 /* Wait for the other thread. Guard against spurious wakeups. */ 103 for (current = step; current == step; uv_cond_wait(&condvar, &mutex)); 104 ASSERT(step == current + 1); 105} 106 107 108static void thread_rwlock_trylock_peer(void* unused) { 109 (void) &unused; 110 111 uv_mutex_lock(&mutex); 112 113 /* Write lock held by other thread. */ 114 ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); 115 ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); 116 synchronize(); 117 118 /* Read lock held by other thread. */ 119 ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); 120 uv_rwlock_rdunlock(&rwlock); 121 ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); 122 synchronize(); 123 124 /* Acquire write lock. */ 125 ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); 126 synchronize(); 127 128 /* Release write lock and acquire read lock. */ 129 uv_rwlock_wrunlock(&rwlock); 130 ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); 131 synchronize(); 132 133 uv_rwlock_rdunlock(&rwlock); 134 synchronize_nowait(); /* Signal main thread we're going away. */ 135 uv_mutex_unlock(&mutex); 136} 137 138 139TEST_IMPL(thread_rwlock_trylock) { 140 uv_thread_t thread; 141 142 ASSERT(0 == uv_cond_init(&condvar)); 143 ASSERT(0 == uv_mutex_init(&mutex)); 144 ASSERT(0 == uv_rwlock_init(&rwlock)); 145 146 uv_mutex_lock(&mutex); 147 ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); 148 149 /* Hold write lock. */ 150 ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); 151 synchronize(); /* Releases the mutex to the other thread. */ 152 153 /* Release write lock and acquire read lock. Pthreads doesn't support 154 * the notion of upgrading or downgrading rwlocks, so neither do we. 155 */ 156 uv_rwlock_wrunlock(&rwlock); 157 ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); 158 synchronize(); 159 160 /* Release read lock. */ 161 uv_rwlock_rdunlock(&rwlock); 162 synchronize(); 163 164 /* Write lock held by other thread. */ 165 ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); 166 ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); 167 synchronize(); 168 169 /* Read lock held by other thread. */ 170 ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); 171 uv_rwlock_rdunlock(&rwlock); 172 ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); 173 synchronize(); 174 175 ASSERT(0 == uv_thread_join(&thread)); 176 uv_rwlock_destroy(&rwlock); 177 uv_mutex_unlock(&mutex); 178 uv_mutex_destroy(&mutex); 179 uv_cond_destroy(&condvar); 180 181 return 0; 182} 183