blob: 3b4296d8fedbaa585e5da1b4ec15d11add93bc0d [file] [log] [blame] [edit]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdio.h>
#include <sync/sem.h>
#include <sync/bin_sem.h>
#include <sync/condition_var.h>
#include <stdbool.h>
#include "../test.h"
#include "../helpers.h"
static volatile int shared = 0;
sync_bin_sem_t bin_sem = {{0}};
sync_sem_t sem = {{0}};
sync_bin_sem_t monitor_lock = {{0}};
sync_cv_t consumer_cv = {{0}};
sync_cv_t producer_cv = {{0}};
sync_cv_t broadcaster_cv = {{0}};
static int bin_sem_func(env_t env, int threadid)
{
/* Take the semaphore */
sync_bin_sem_wait(&bin_sem);
/* Grab the value of the shared variable */
int value = shared;
/* Yield to give the other thread a chance to test the semaphore */
seL4_Yield();
/* Write back to the shared variable */
value += 1;
shared = value;
/* Signal the semaphore */
sync_bin_sem_post(&bin_sem);
return 0;
}
static int test_bin_sem(struct env *env)
{
int error;
helper_thread_t thread1, thread2;
/* Create a binary semaphore */
error = sync_bin_sem_new(&(env->vka), &bin_sem, 1);
test_eq(error, 0);
/* Reset the shared variable */
shared = 0;
/* Create some threads that need mutual exclusion */
create_helper_thread(env, &thread1);
create_helper_thread(env, &thread2);
start_helper(env, &thread1, (helper_fn_t) bin_sem_func, (seL4_Word) env, 1, 0, 0);
start_helper(env, &thread2, (helper_fn_t) bin_sem_func, (seL4_Word) env, 2, 0, 0);
/* Wait for them to do their thing */
wait_for_helper(&thread1);
wait_for_helper(&thread2);
cleanup_helper(env, &thread1);
cleanup_helper(env, &thread2);
/* If the semaphore worked then this will be 2 */
test_eq(shared, 2);
/* Clean up */
sync_bin_sem_destroy(&env->vka, &bin_sem);
return sel4test_get_result();
}
DEFINE_TEST(SYNC001, "libsel4sync Test binary semaphores", test_bin_sem, true)
static int
sem_func(env_t env, int threadid)
{
/* Take the semaphore */
sync_sem_wait(&sem);
/* Grab the value of the shared variable */
int value = shared;
/* Yield to give the other thread a chance to test the semaphore */
seL4_Yield();
/* Write back to the shared variable */
value += 1;
shared = value;
/* Signal the semaphore */
sync_sem_post(&sem);
return 0;
}
static int test_sem(struct env *env)
{
int error;
helper_thread_t thread1, thread2;
/* Reset the shared variable */
shared = 0;
/* Create a binary semaphore */
error = sync_sem_new(&(env->vka), &sem, 1);
test_eq(error, 0);
/* Create some threads that need mutual exclusion */
create_helper_thread(env, &thread1);
create_helper_thread(env, &thread2);
start_helper(env, &thread1, (helper_fn_t) sem_func, (seL4_Word) env, 1, 0, 0);
start_helper(env, &thread2, (helper_fn_t) sem_func, (seL4_Word) env, 2, 0, 0);
/* Wait for them to do their thing */
wait_for_helper(&thread1);
wait_for_helper(&thread2);
cleanup_helper(env, &thread1);
cleanup_helper(env, &thread2);
/* If the semaphore worked then this will be 2 */
test_eq(shared, 2);
/* Clean up */
sync_sem_destroy(&(env->vka), &sem);
return sel4test_get_result();
}
DEFINE_TEST(SYNC002, "libsel4sync Test semaphores", test_sem, true)
static int
consumer_func(env_t env, int threadid)
{
/* Take the monitor */
sync_bin_sem_wait(&monitor_lock);
/* Wait for a condition to be true */
while (shared == 0) {
sync_cv_wait(&monitor_lock, &consumer_cv);
}
/* Grab the value of the shared variable */
int value = shared;
seL4_Yield();
/* Write back to the shared variable */
value -= 1;
shared = value;
/* Signal the condition variable */
sync_cv_signal(&producer_cv);
/* Release the monitor */
sync_bin_sem_post(&monitor_lock);
return 0;
}
static int producer_func(env_t env, int threadid)
{
/* Take the monitor */
sync_bin_sem_wait(&monitor_lock);
/* Wait for a condition to be true */
while (shared == 2) {
sync_cv_wait(&monitor_lock, &producer_cv);
}
/* Grab the value of the shared variable */
int value = shared;
seL4_Yield();
/* Write back to the shared variable */
value += 1;
shared = value;
/* Signal the condition variable */
sync_cv_signal(&consumer_cv);
/* Release the monitor */
sync_bin_sem_post(&monitor_lock);
return 0;
}
static int test_monitor(struct env *env)
{
int error;
helper_thread_t consumer_thread1, consumer_thread2;
helper_thread_t producer_thread1, producer_thread2;
/* Create a lock for the monitor */
error = sync_bin_sem_new(&(env->vka), &monitor_lock, 1);
test_eq(error, 0);
/* Create a condition variable for consumers */
error = sync_cv_new(&(env->vka), &consumer_cv);
test_eq(error, 0);
/* Create a condition variable for producers */
error = sync_cv_new(&(env->vka), &producer_cv);
test_eq(error, 0);
/* Create the producer/consumer threads */
create_helper_thread(env, &consumer_thread1);
create_helper_thread(env, &consumer_thread2);
create_helper_thread(env, &producer_thread1);
create_helper_thread(env, &producer_thread2);
shared = 1;
start_helper(env, &consumer_thread1, (helper_fn_t) consumer_func, (seL4_Word) env, 1, 0, 0);
start_helper(env, &consumer_thread2, (helper_fn_t) consumer_func, (seL4_Word) env, 2, 0, 0);
start_helper(env, &producer_thread1, (helper_fn_t) producer_func, (seL4_Word) env, 3, 0, 0);
start_helper(env, &producer_thread2, (helper_fn_t) producer_func, (seL4_Word) env, 4, 0, 0);
/* Wait for them to do their thing */
wait_for_helper(&consumer_thread1);
wait_for_helper(&consumer_thread2);
wait_for_helper(&producer_thread1);
wait_for_helper(&producer_thread2);
cleanup_helper(env, &consumer_thread1);
cleanup_helper(env, &consumer_thread2);
cleanup_helper(env, &producer_thread1);
cleanup_helper(env, &producer_thread2);
/* If the monitor worked then this will be 1 */
test_eq(shared, 1);
/* Clean up */
sync_cv_destroy(&(env->vka), &consumer_cv);
sync_cv_destroy(&(env->vka), &producer_cv);
sync_bin_sem_destroy(&(env->vka), &monitor_lock);
return sel4test_get_result();
}
DEFINE_TEST(SYNC003, "libsel4sync Test monitors", test_monitor, true)
static int
broadcaster_func(env_t env, int threadid)
{
/* Take the monitor */
sync_bin_sem_wait(&monitor_lock);
/* Wait for a condition to be true */
while (shared == 2) {
sync_cv_wait(&monitor_lock, &broadcaster_cv);
}
/* Grab the value of the shared variable */
int value = shared;
seL4_Yield();
/* Write back to the shared variable */
value += 3;
shared = value;
/* Signal the condition variable */
sync_cv_broadcast_release(&monitor_lock, &consumer_cv);
return 0;
}
static int test_monitor_broadcast(struct env *env)
{
int error;
helper_thread_t broadcaster_thread;
helper_thread_t consumer_thread1, consumer_thread2, consumer_thread3;
/* Create a lock for the monitor */
error = sync_bin_sem_new(&(env->vka), &monitor_lock, 1);
test_eq(error, 0);
/* Create a condition variable for consumers */
error = sync_cv_new(&(env->vka), &consumer_cv);
test_eq(error, 0);
/* Create a condition variable for the broadcaster */
error = sync_cv_new(&(env->vka), &broadcaster_cv);
test_eq(error, 0);
/* Create the broadcaster/consumer threads */
create_helper_thread(env, &consumer_thread1);
create_helper_thread(env, &consumer_thread2);
create_helper_thread(env, &consumer_thread3);
create_helper_thread(env, &broadcaster_thread);
shared = 0;
start_helper(env, &broadcaster_thread, (helper_fn_t) broadcaster_func, (seL4_Word) env, 1, 0, 0);
start_helper(env, &consumer_thread1, (helper_fn_t) consumer_func, (seL4_Word) env, 2, 0, 0);
start_helper(env, &consumer_thread2, (helper_fn_t) consumer_func, (seL4_Word) env, 3, 0, 0);
start_helper(env, &consumer_thread3, (helper_fn_t) consumer_func, (seL4_Word) env, 4, 0, 0);
/* Wait for them to do their thing */
wait_for_helper(&broadcaster_thread);
wait_for_helper(&consumer_thread1);
wait_for_helper(&consumer_thread2);
wait_for_helper(&consumer_thread3);
cleanup_helper(env, &consumer_thread1);
cleanup_helper(env, &consumer_thread2);
cleanup_helper(env, &consumer_thread3);
cleanup_helper(env, &broadcaster_thread);
/* If the monitor worked then this will be 0 */
test_eq(shared, 0);
/* Check that the broadcast is over */
test_assert(!consumer_cv.broadcasting);
/* Clean up */
sync_cv_destroy(&(env->vka), &consumer_cv);
sync_cv_destroy(&(env->vka), &broadcaster_cv);
sync_bin_sem_destroy(&(env->vka), &monitor_lock);
return sel4test_get_result();
}
DEFINE_TEST(SYNC004, "libsel4sync Test monitors - broadcast", test_monitor_broadcast, true)