parlib: Implement uthread mutexes with semaphores
[akaros.git] / user / utest / cv.c
index a95a525..6a159f8 100644 (file)
@@ -11,8 +11,8 @@ TEST_SUITE("CV");
 /* <--- Begin definition of test cases ---> */
 
 struct common_args {
-       uth_cond_var_t                          cv;
-       uth_mutex_t                                     mtx;
+       uth_cond_var_t                          *cv;
+       uth_mutex_t                                     *mtx;
        bool                                            flag;
        unsigned int                            wait_sleep;
        unsigned int                            sig_sleep;
@@ -22,12 +22,13 @@ struct common_args {
 
 bool test_signal_no_wait(void)
 {
-       uth_cond_var_t cv = uth_cond_var_alloc();
+       uth_cond_var_t *cv = uth_cond_var_alloc();
 
        uth_cond_var_broadcast(cv);
        uth_cond_var_signal(cv);
        pthread_yield();
        uth_cond_var_free(cv);
+       return TRUE;
 }
 
 void *__cv_signaller(void *arg)
@@ -86,9 +87,12 @@ bool test_signal(void)
        pthread_t signaller, waiter;
        void *sig_join, *wait_join;
        int ret;
+       static uth_mutex_t static_mtx = UTH_MUTEX_INIT;
+       static uth_cond_var_t static_cv = UTH_COND_VAR_INIT;
 
-       args->cv = uth_cond_var_alloc();
-       args->mtx = uth_mutex_alloc();
+       /* Also testing the static initializers.  Note we never free these. */
+       args->cv = &static_cv;
+       args->mtx = &static_mtx;
 
        for (int i = 0; i < 1000; i += 10) {
                args->flag = FALSE;
@@ -107,8 +111,7 @@ bool test_signal(void)
                UT_ASSERT_M("Signaller Failed", sig_join == PTH_TEST_TRUE);
        }
 
-       uth_cond_var_free(args->cv);
-       uth_mutex_free(args->mtx);
+       return TRUE;
 }
 
 bool test_broadcast(void)
@@ -143,13 +146,128 @@ bool test_broadcast(void)
 
        uth_cond_var_free(args->cv);
        uth_mutex_free(args->mtx);
+       return TRUE;
+}
+
+static bool __test_recurse(struct uth_recurse_mutex *r_mtx)
+{
+       bool test;
+
+       uth_recurse_mutex_lock(r_mtx);
+       /* should be one lock deep */
+       UT_ASSERT(r_mtx->count == 1);
+       UT_ASSERT(r_mtx->lockholder == current_uthread);
+
+       test = uth_recurse_mutex_trylock(r_mtx);
+       UT_ASSERT_M("Failed to re(try)lock our owned mutex!", test);
+       /* should be two locks deep */
+       UT_ASSERT(r_mtx->count == 2);
+       UT_ASSERT(r_mtx->lockholder == current_uthread);
+
+       uth_recurse_mutex_lock(r_mtx);
+       /* should be three locks deep */
+       UT_ASSERT(r_mtx->count == 3);
+       UT_ASSERT(r_mtx->lockholder == current_uthread);
+
+       uth_recurse_mutex_unlock(r_mtx);
+       /* should be two locks deep */
+       UT_ASSERT(r_mtx->count == 2);
+       UT_ASSERT(r_mtx->lockholder == current_uthread);
+
+       uth_recurse_mutex_unlock(r_mtx);
+       /* should be one lock deep */
+       UT_ASSERT(r_mtx->count == 1);
+       UT_ASSERT(r_mtx->lockholder == current_uthread);
+
+       uth_recurse_mutex_unlock(r_mtx);
+       /* should be unlocked */
+       UT_ASSERT(r_mtx->count == 0);
+       UT_ASSERT(!r_mtx->lockholder);
+
+       return TRUE;
 }
+
+bool test_recurse(void)
+{
+       uth_recurse_mutex_t *r_mtx;
+
+       r_mtx = uth_recurse_mutex_alloc();
+       UT_ASSERT(r_mtx);
+       if (!__test_recurse(r_mtx))
+               return FALSE;
+       uth_recurse_mutex_free(r_mtx);
+
+       return TRUE;
+}
+
+bool test_recurse_static(void)
+{
+       static uth_recurse_mutex_t static_recurse_mtx = UTH_RECURSE_MUTEX_INIT;
+
+       return __test_recurse(&static_recurse_mtx);
+}
+
+static bool __test_semaphore(struct uth_semaphore *sem, int count)
+{
+       bool can_down;
+
+       UT_ASSERT(count > 2);   /* for our own use */
+       UT_ASSERT(sem->count == count);
+       /* should be able to down it count times without blocking */
+       for (int i = 0; i < count; i++) {
+               uth_semaphore_down(sem);
+               UT_ASSERT(sem->count == count - (i + 1));
+       }
+
+       /* shouldn't be able to down, since we grabbed them all */
+       can_down = uth_semaphore_trydown(sem);
+       UT_ASSERT(!can_down);
+       UT_ASSERT(sem->count == 0);
+
+       uth_semaphore_up(sem);
+       UT_ASSERT(sem->count == 1);
+       can_down = uth_semaphore_trydown(sem);
+       UT_ASSERT(can_down);
+       UT_ASSERT(sem->count == 0);
+
+       for (int i = 0; i < count; i++) {
+               uth_semaphore_up(sem);
+               UT_ASSERT(sem->count == i + 1);
+       }
+
+       return TRUE;
+}
+
+bool test_semaphore(void)
+{
+       uth_semaphore_t *sem;
+
+       sem = uth_semaphore_alloc(5);
+       UT_ASSERT(sem);
+       if (!__test_semaphore(sem, 5))
+               return FALSE;
+       uth_semaphore_free(sem);
+
+       return TRUE;
+}
+
+bool test_semaphore_static(void)
+{
+       static uth_semaphore_t static_semaphore = UTH_SEMAPHORE_INIT(5);
+
+       return __test_semaphore(&static_semaphore, 5);
+}
+
 /* <--- End definition of test cases ---> */
 
 struct utest utests[] = {
        UTEST_REG(signal_no_wait),
        UTEST_REG(signal),
        UTEST_REG(broadcast),
+       UTEST_REG(recurse),
+       UTEST_REG(recurse_static),
+       UTEST_REG(semaphore),
+       UTEST_REG(semaphore_static),
 };
 int num_utests = sizeof(utests) / sizeof(struct utest);