aboutsummaryrefslogtreecommitdiff
path: root/libiot/pthread/test
diff options
context:
space:
mode:
authorbhgv <bhgv.empire@gmail.com>2020-05-12 12:50:49 +0300
committerbhgv <bhgv.empire@gmail.com>2020-05-12 12:50:49 +0300
commit9b5d5f8a4640dbecdc87e5b6e7e95f71018632cf (patch)
treed3135c3861ef93ed2523642d3c5f64c7819b7def /libiot/pthread/test
parent73c13e732072c17f3e584e11a51d1f7dc8d88e32 (diff)
parent31b4edc67b75658ce5e2d41f2fc87331f4b26d49 (diff)
Merge branch 'master' of https://github.com/bhgv/Inferno-OS-bhgv
Diffstat (limited to 'libiot/pthread/test')
-rw-r--r--libiot/pthread/test/pthread-cleanup.c200
-rw-r--r--libiot/pthread/test/pthread-cond.c107
-rw-r--r--libiot/pthread/test/pthread-join.c85
-rw-r--r--libiot/pthread/test/pthread-once.c68
4 files changed, 460 insertions, 0 deletions
diff --git a/libiot/pthread/test/pthread-cleanup.c b/libiot/pthread/test/pthread-cleanup.c
new file mode 100644
index 0000000..c11aeb4
--- /dev/null
+++ b/libiot/pthread/test/pthread-cleanup.c
@@ -0,0 +1,200 @@
+#include "unity.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <sys/delay.h>
+
+#define NUM_TERMS 4
+
+static int term[NUM_TERMS];
+
+void term_0(void *args) {
+ term[0] = 0;
+}
+
+void term_1(void *args) {
+ term[1] = 1;
+}
+
+void term_2(void *args) {
+ term[2] = 2;
+}
+
+void term_3(void *args) {
+ term[3] = 3;
+}
+
+// Test that handlers are called in reverse order
+static void *thread1(void *args) {
+ int count = 0;
+
+ memset(term, -1, sizeof(term));
+
+ pthread_cleanup_push(term_0, NULL);
+ pthread_cleanup_push(term_1, NULL);
+ pthread_cleanup_push(term_2, NULL);
+ pthread_cleanup_push(term_3, NULL);
+
+ for (count = 0; count < 100; count++) {
+ // Simulate some work
+ usleep(1000);
+ }
+
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ TEST_ASSERT(term[0] == 0);
+ TEST_ASSERT(term[1] == 1);
+ TEST_ASSERT(term[2] == 2);
+ TEST_ASSERT(term[3] == 3);
+
+ return NULL;
+}
+
+// Test that only handlers poped with execute argument set to true are
+// executed
+static void *thread2(void *args) {
+ int count = 0;
+
+ memset(term, -1, sizeof(term));
+
+ pthread_cleanup_push(term_0, NULL);
+ pthread_cleanup_push(term_1, NULL);
+ pthread_cleanup_push(term_2, NULL);
+ pthread_cleanup_push(term_3, NULL);
+
+ for (count = 0; count < 100; count++) {
+ // Simulate some work
+ usleep(1000);
+ }
+
+ pthread_cleanup_pop(0);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(0);
+ pthread_cleanup_pop(1);
+
+ TEST_ASSERT(term[0] == 0);
+ TEST_ASSERT(term[1] == -1);
+ TEST_ASSERT(term[2] == 2);
+ TEST_ASSERT(term[3] == -1);
+
+ pthread_exit(NULL);
+}
+
+// Test that pthread_exit execute the cleanups
+static void *thread3(void *args) {
+ int count = 0;
+
+ memset(term, -1, sizeof(term));
+
+ pthread_cleanup_push(term_0, NULL);
+ pthread_cleanup_push(term_1, NULL);
+ pthread_cleanup_push(term_2, NULL);
+ pthread_cleanup_push(term_3, NULL);
+
+ for (count = 0; count < 100; count++) {
+ // Simulate some work
+ usleep(1000);
+
+ if (count == 50) {
+ pthread_exit(NULL);
+ }
+ }
+
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ // This point is never reached
+ TEST_ASSERT(0);
+
+ pthread_exit(NULL);
+}
+
+// Test that when exit from thread with return don't execute the cleanups
+static void *thread4(void *args) {
+ int count = 0;
+
+ memset(term, -1, sizeof(term));
+
+ pthread_cleanup_push(term_0, NULL);
+ pthread_cleanup_push(term_1, NULL);
+ pthread_cleanup_push(term_2, NULL);
+ pthread_cleanup_push(term_3, NULL);
+
+ for (count = 0; count < 100; count++) {
+ // Simulate some work
+ usleep(1000);
+
+ if (count == 50) {
+ return NULL;
+ }
+ }
+
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ // This point is never reached
+ TEST_ASSERT(0);
+
+ return NULL;
+}
+
+TEST_CASE("pthread cleanup", "[pthread]") {
+ pthread_attr_t attr;
+ pthread_t th;
+ int ret;
+
+ pthread_attr_init(&attr);
+
+ // Test that handlers are called in reverse order
+ ret = pthread_create(&th, &attr, thread1, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_join(th, NULL);
+ TEST_ASSERT(ret == 0);
+
+ // Test that only handlers poped with execute argument set to true are
+ // executed
+ ret = pthread_create(&th, &attr, thread2, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_join(th, NULL);
+ TEST_ASSERT(ret == 0);
+
+ // Test that pthread_exit execute the cleanups
+ ret = pthread_create(&th, &attr, thread3, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_join(th, NULL);
+ TEST_ASSERT(ret == 0);
+
+ TEST_ASSERT(term[0] == 0);
+ TEST_ASSERT(term[1] == 1);
+ TEST_ASSERT(term[2] == 2);
+ TEST_ASSERT(term[3] == 3);
+
+ // Test that when exit from thread with return don't execute the cleanups
+ ret = pthread_create(&th, &attr, thread4, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_join(th, NULL);
+ TEST_ASSERT(ret == 0);
+
+ TEST_ASSERT(term[0] == -1);
+ TEST_ASSERT(term[1] == -1);
+ TEST_ASSERT(term[2] == -1);
+ TEST_ASSERT(term[3] == -1);
+
+ ret = pthread_attr_destroy(&attr);
+ TEST_ASSERT(ret == 0);
+}
diff --git a/libiot/pthread/test/pthread-cond.c b/libiot/pthread/test/pthread-cond.c
new file mode 100644
index 0000000..8e1ce41
--- /dev/null
+++ b/libiot/pthread/test/pthread-cond.c
@@ -0,0 +1,107 @@
+#include "unity.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+
+#include <sys/delay.h>
+
+#define NUM_THREADS 3
+#define COUNT_LIMIT 12
+#define TCOUNT 10
+
+static int count = 0;
+static pthread_t threads[NUM_THREADS];
+static pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t count_threshold_cv = PTHREAD_COND_INITIALIZER;
+
+static void *inc_count(void *args) {
+ int i;
+ int ret;
+
+ for (i=0; i< TCOUNT; i++) {
+ ret = pthread_mutex_lock(&count_mutex);
+ TEST_ASSERT(ret == 0);
+
+ count++;
+
+ // If condition is reached signal condition
+ if (count == COUNT_LIMIT) {
+ ret = pthread_cond_signal(&count_threshold_cv);
+ TEST_ASSERT(ret == 0);
+ }
+
+ ret = pthread_mutex_unlock(&count_mutex);
+ TEST_ASSERT(ret == 0);
+
+ // Simulate some work
+ usleep(1000);
+ }
+
+ return NULL;
+ }
+
+static void *watch_count(void *args) {
+ int ret;
+
+ ret = pthread_mutex_lock(&count_mutex);
+ TEST_ASSERT(ret == 0);
+
+ while (count < COUNT_LIMIT) {
+ ret = pthread_cond_wait(&count_threshold_cv, &count_mutex);
+ TEST_ASSERT(ret == 0);
+ }
+
+ count += 125;
+ TEST_ASSERT (count == 125 + COUNT_LIMIT);
+
+ ret = pthread_mutex_unlock(&count_mutex);
+ TEST_ASSERT(ret == 0);
+
+ return NULL;
+}
+
+TEST_CASE("pthread conditions", "[pthread]") {
+ pthread_attr_t attr;
+ int i, ret;
+
+ // Initialize mutex and condition variable objects
+ ret = pthread_mutex_init(&count_mutex, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_cond_init(&count_threshold_cv, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_attr_init(&attr);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_attr_setstacksize(&attr, 10240);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[0], &attr, watch_count, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[1], &attr, inc_count, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[2], &attr, inc_count, NULL);
+ TEST_ASSERT(ret == 0);
+
+ // Wait for all threads completion
+ for (i=0; i< NUM_THREADS; i++) {
+ ret = pthread_join(threads[i], NULL);
+ TEST_ASSERT(ret == 0);
+ }
+
+ // Clean up
+ ret = pthread_attr_destroy(&attr);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_mutex_destroy(&count_mutex);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_cond_destroy(&count_threshold_cv);
+ TEST_ASSERT(ret == 0);
+}
diff --git a/libiot/pthread/test/pthread-join.c b/libiot/pthread/test/pthread-join.c
new file mode 100644
index 0000000..ba5f976
--- /dev/null
+++ b/libiot/pthread/test/pthread-join.c
@@ -0,0 +1,85 @@
+#include "unity.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+
+#include <sys/delay.h>
+
+#define NUM_THREADS 2
+
+static pthread_t threads[NUM_THREADS];
+
+static void *thread1(void *args) {
+ int count = 0;
+
+ for (count = 0; count < 100; count++) {
+ // Simulate some work
+ usleep(1000);
+ }
+
+ int *ret = malloc(sizeof(int));
+ *ret = count;
+
+ pthread_exit(ret);
+ }
+
+static void *thread2(void *args) {
+ int count;
+
+ for (count = 0; count < 50; count++) {
+ // Simulate some work
+ usleep(1000);
+ }
+
+ int *ret = malloc(sizeof(int));
+ *ret = count;
+
+ pthread_exit(ret);
+ }
+
+
+TEST_CASE("pthread join", "[pthread]") {
+ pthread_attr_t attr;
+ int i, ret;
+ int *res;
+
+ ret = pthread_attr_init(&attr);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[0], &attr, thread1, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[1], &attr, thread2, NULL);
+ TEST_ASSERT(ret == 0);
+
+ // Wait for all threads completion
+ for (i=0; i< NUM_THREADS; i++) {
+ ret = pthread_join(threads[i], (void **)&res);
+ TEST_ASSERT(ret == 0);
+
+ if (i == 0) {
+ TEST_ASSERT(*res == 100);
+ } else if (i == 1) {
+ TEST_ASSERT(*res == 50);
+ }
+
+ free(res);
+ }
+
+ // Check that a detached thread is not joinable
+ ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[0], &attr, thread1, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_join(threads[0], (void **)&res);
+ TEST_ASSERT(ret == EINVAL);
+
+ // Clean up
+ ret = pthread_attr_destroy(&attr);
+ TEST_ASSERT(ret == 0);
+}
diff --git a/libiot/pthread/test/pthread-once.c b/libiot/pthread/test/pthread-once.c
new file mode 100644
index 0000000..d3a3db6
--- /dev/null
+++ b/libiot/pthread/test/pthread-once.c
@@ -0,0 +1,68 @@
+#include "unity.h"
+
+#include <pthread.h>
+#include <sys/delay.h>
+
+#define NUM_THREADS 2
+
+static pthread_t threads[NUM_THREADS];
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static int execs;
+
+static void init() {
+ int ret;
+
+ ret = pthread_mutex_lock(&mutex);
+ TEST_ASSERT(ret == 0);
+
+ execs++;
+
+ ret = pthread_mutex_unlock(&mutex);
+ TEST_ASSERT(ret == 0);
+}
+
+static void *thread1(void *args) {
+ int ret;
+
+ ret = pthread_once(&once, init);
+ TEST_ASSERT(ret == 0);
+
+ // Simulate some work
+ usleep(1000);
+
+ pthread_exit(NULL);
+ }
+
+TEST_CASE("pthread once", "[pthread]") {
+ pthread_attr_t attr;
+ int i, ret;
+
+ ret = pthread_attr_init(&attr);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_mutex_init(&mutex, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[0], &attr, thread1, NULL);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_create(&threads[1], &attr, thread1, NULL);
+ TEST_ASSERT(ret == 0);
+
+ // Wait for all threads completion
+ for (i=0; i< NUM_THREADS; i++) {
+ ret = pthread_join(threads[i], NULL);
+ TEST_ASSERT(ret == 0);
+ }
+
+ TEST_ASSERT(execs == 1);
+
+ // Clean up
+ ret = pthread_attr_destroy(&attr);
+ TEST_ASSERT(ret == 0);
+
+ ret = pthread_mutex_destroy(&mutex);
+ TEST_ASSERT(ret == 0);
+}