1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdio.h> 14#include <sync/sem.h> 15#include <sync/bin_sem.h> 16#include <sync/condition_var.h> 17#include <stdbool.h> 18 19#include "../test.h" 20#include "../helpers.h" 21 22static volatile int shared = 0; 23sync_bin_sem_t bin_sem = {{0}}; 24 25sync_sem_t sem = {{0}}; 26 27sync_bin_sem_t monitor_lock = {{0}}; 28sync_cv_t consumer_cv = {{0}}; 29sync_cv_t producer_cv = {{0}}; 30sync_cv_t broadcaster_cv = {{0}}; 31 32static int bin_sem_func(env_t env, int threadid) 33{ 34 /* Take the semaphore */ 35 sync_bin_sem_wait(&bin_sem); 36 37 /* Grab the value of the shared variable */ 38 int value = shared; 39 40 /* Yield to give the other thread a chance to test the semaphore */ 41 seL4_Yield(); 42 43 /* Write back to the shared variable */ 44 value += 1; 45 shared = value; 46 47 /* Signal the semaphore */ 48 sync_bin_sem_post(&bin_sem); 49 50 return 0; 51} 52 53static int test_bin_sem(struct env *env) 54{ 55 int error; 56 helper_thread_t thread1, thread2; 57 58 /* Create a binary semaphore */ 59 error = sync_bin_sem_new(&(env->vka), &bin_sem, 1); 60 test_eq(error, 0); 61 62 /* Reset the shared variable */ 63 shared = 0; 64 65 /* Create some threads that need mutual exclusion */ 66 create_helper_thread(env, &thread1); 67 create_helper_thread(env, &thread2); 68 start_helper(env, &thread1, (helper_fn_t) bin_sem_func, (seL4_Word) env, 1, 0, 0); 69 start_helper(env, &thread2, (helper_fn_t) bin_sem_func, (seL4_Word) env, 2, 0, 0); 70 71 /* Wait for them to do their thing */ 72 wait_for_helper(&thread1); 73 wait_for_helper(&thread2); 74 cleanup_helper(env, &thread1); 75 cleanup_helper(env, &thread2); 76 77 /* If the semaphore worked then this will be 2 */ 78 test_eq(shared, 2); 79 80 /* Clean up */ 81 sync_bin_sem_destroy(&env->vka, &bin_sem); 82 83 return sel4test_get_result(); 84} 85DEFINE_TEST(SYNC001, "libsel4sync Test binary semaphores", test_bin_sem, true) 86 87static int 88sem_func(env_t env, int threadid) 89{ 90 /* Take the semaphore */ 91 sync_sem_wait(&sem); 92 93 /* Grab the value of the shared variable */ 94 int value = shared; 95 96 /* Yield to give the other thread a chance to test the semaphore */ 97 seL4_Yield(); 98 99 /* Write back to the shared variable */ 100 value += 1; 101 shared = value; 102 103 /* Signal the semaphore */ 104 sync_sem_post(&sem); 105 106 return 0; 107} 108 109static int test_sem(struct env *env) 110{ 111 int error; 112 helper_thread_t thread1, thread2; 113 114 /* Reset the shared variable */ 115 shared = 0; 116 117 /* Create a binary semaphore */ 118 error = sync_sem_new(&(env->vka), &sem, 1); 119 test_eq(error, 0); 120 121 /* Create some threads that need mutual exclusion */ 122 create_helper_thread(env, &thread1); 123 create_helper_thread(env, &thread2); 124 start_helper(env, &thread1, (helper_fn_t) sem_func, (seL4_Word) env, 1, 0, 0); 125 start_helper(env, &thread2, (helper_fn_t) sem_func, (seL4_Word) env, 2, 0, 0); 126 127 /* Wait for them to do their thing */ 128 wait_for_helper(&thread1); 129 wait_for_helper(&thread2); 130 cleanup_helper(env, &thread1); 131 cleanup_helper(env, &thread2); 132 133 /* If the semaphore worked then this will be 2 */ 134 test_eq(shared, 2); 135 136 /* Clean up */ 137 sync_sem_destroy(&(env->vka), &sem); 138 139 return sel4test_get_result(); 140} 141DEFINE_TEST(SYNC002, "libsel4sync Test semaphores", test_sem, true) 142 143static int 144consumer_func(env_t env, int threadid) 145{ 146 /* Take the monitor */ 147 sync_bin_sem_wait(&monitor_lock); 148 149 /* Wait for a condition to be true */ 150 while (shared == 0) { 151 sync_cv_wait(&monitor_lock, &consumer_cv); 152 } 153 154 /* Grab the value of the shared variable */ 155 int value = shared; 156 157 seL4_Yield(); 158 159 /* Write back to the shared variable */ 160 value -= 1; 161 shared = value; 162 163 /* Signal the condition variable */ 164 sync_cv_signal(&producer_cv); 165 166 /* Release the monitor */ 167 sync_bin_sem_post(&monitor_lock); 168 169 return 0; 170} 171 172static int producer_func(env_t env, int threadid) 173{ 174 /* Take the monitor */ 175 sync_bin_sem_wait(&monitor_lock); 176 177 /* Wait for a condition to be true */ 178 while (shared == 2) { 179 sync_cv_wait(&monitor_lock, &producer_cv); 180 } 181 182 /* Grab the value of the shared variable */ 183 int value = shared; 184 185 seL4_Yield(); 186 187 /* Write back to the shared variable */ 188 value += 1; 189 shared = value; 190 191 /* Signal the condition variable */ 192 sync_cv_signal(&consumer_cv); 193 194 /* Release the monitor */ 195 sync_bin_sem_post(&monitor_lock); 196 197 return 0; 198} 199 200static int test_monitor(struct env *env) 201{ 202 int error; 203 helper_thread_t consumer_thread1, consumer_thread2; 204 helper_thread_t producer_thread1, producer_thread2; 205 206 /* Create a lock for the monitor */ 207 error = sync_bin_sem_new(&(env->vka), &monitor_lock, 1); 208 test_eq(error, 0); 209 210 /* Create a condition variable for consumers */ 211 error = sync_cv_new(&(env->vka), &consumer_cv); 212 test_eq(error, 0); 213 214 /* Create a condition variable for producers */ 215 error = sync_cv_new(&(env->vka), &producer_cv); 216 test_eq(error, 0); 217 218 /* Create the producer/consumer threads */ 219 create_helper_thread(env, &consumer_thread1); 220 create_helper_thread(env, &consumer_thread2); 221 create_helper_thread(env, &producer_thread1); 222 create_helper_thread(env, &producer_thread2); 223 224 shared = 1; 225 226 start_helper(env, &consumer_thread1, (helper_fn_t) consumer_func, (seL4_Word) env, 1, 0, 0); 227 start_helper(env, &consumer_thread2, (helper_fn_t) consumer_func, (seL4_Word) env, 2, 0, 0); 228 start_helper(env, &producer_thread1, (helper_fn_t) producer_func, (seL4_Word) env, 3, 0, 0); 229 start_helper(env, &producer_thread2, (helper_fn_t) producer_func, (seL4_Word) env, 4, 0, 0); 230 231 /* Wait for them to do their thing */ 232 wait_for_helper(&consumer_thread1); 233 wait_for_helper(&consumer_thread2); 234 wait_for_helper(&producer_thread1); 235 wait_for_helper(&producer_thread2); 236 237 cleanup_helper(env, &consumer_thread1); 238 cleanup_helper(env, &consumer_thread2); 239 cleanup_helper(env, &producer_thread1); 240 cleanup_helper(env, &producer_thread2); 241 242 /* If the monitor worked then this will be 1 */ 243 test_eq(shared, 1); 244 245 /* Clean up */ 246 sync_cv_destroy(&(env->vka), &consumer_cv); 247 sync_cv_destroy(&(env->vka), &producer_cv); 248 sync_bin_sem_destroy(&(env->vka), &monitor_lock); 249 250 return sel4test_get_result(); 251} 252DEFINE_TEST(SYNC003, "libsel4sync Test monitors", test_monitor, true) 253 254static int 255broadcaster_func(env_t env, int threadid) 256{ 257 /* Take the monitor */ 258 sync_bin_sem_wait(&monitor_lock); 259 260 /* Wait for a condition to be true */ 261 while (shared == 2) { 262 sync_cv_wait(&monitor_lock, &broadcaster_cv); 263 } 264 265 /* Grab the value of the shared variable */ 266 int value = shared; 267 268 seL4_Yield(); 269 270 /* Write back to the shared variable */ 271 value += 3; 272 shared = value; 273 274 /* Signal the condition variable */ 275 sync_cv_broadcast_release(&monitor_lock, &consumer_cv); 276 277 return 0; 278} 279 280static int test_monitor_broadcast(struct env *env) 281{ 282 int error; 283 helper_thread_t broadcaster_thread; 284 helper_thread_t consumer_thread1, consumer_thread2, consumer_thread3; 285 286 /* Create a lock for the monitor */ 287 error = sync_bin_sem_new(&(env->vka), &monitor_lock, 1); 288 test_eq(error, 0); 289 290 /* Create a condition variable for consumers */ 291 error = sync_cv_new(&(env->vka), &consumer_cv); 292 test_eq(error, 0); 293 294 /* Create a condition variable for the broadcaster */ 295 error = sync_cv_new(&(env->vka), &broadcaster_cv); 296 test_eq(error, 0); 297 298 /* Create the broadcaster/consumer threads */ 299 create_helper_thread(env, &consumer_thread1); 300 create_helper_thread(env, &consumer_thread2); 301 create_helper_thread(env, &consumer_thread3); 302 create_helper_thread(env, &broadcaster_thread); 303 304 shared = 0; 305 306 start_helper(env, &broadcaster_thread, (helper_fn_t) broadcaster_func, (seL4_Word) env, 1, 0, 0); 307 start_helper(env, &consumer_thread1, (helper_fn_t) consumer_func, (seL4_Word) env, 2, 0, 0); 308 start_helper(env, &consumer_thread2, (helper_fn_t) consumer_func, (seL4_Word) env, 3, 0, 0); 309 start_helper(env, &consumer_thread3, (helper_fn_t) consumer_func, (seL4_Word) env, 4, 0, 0); 310 311 /* Wait for them to do their thing */ 312 wait_for_helper(&broadcaster_thread); 313 wait_for_helper(&consumer_thread1); 314 wait_for_helper(&consumer_thread2); 315 wait_for_helper(&consumer_thread3); 316 317 cleanup_helper(env, &consumer_thread1); 318 cleanup_helper(env, &consumer_thread2); 319 cleanup_helper(env, &consumer_thread3); 320 cleanup_helper(env, &broadcaster_thread); 321 322 /* If the monitor worked then this will be 0 */ 323 test_eq(shared, 0); 324 325 /* Check that the broadcast is over */ 326 test_assert(!consumer_cv.broadcasting); 327 328 /* Clean up */ 329 sync_cv_destroy(&(env->vka), &consumer_cv); 330 sync_cv_destroy(&(env->vka), &broadcaster_cv); 331 sync_bin_sem_destroy(&(env->vka), &monitor_lock); 332 333 return sel4test_get_result(); 334} 335DEFINE_TEST(SYNC004, "libsel4sync Test monitors - broadcast", test_monitor_broadcast, true) 336