]> git.saurik.com Git - apple/libpthread.git/blobdiff - tests/once_cancel.c
libpthread-218.1.3.tar.gz
[apple/libpthread.git] / tests / once_cancel.c
diff --git a/tests/once_cancel.c b/tests/once_cancel.c
new file mode 100644 (file)
index 0000000..4daa1db
--- /dev/null
@@ -0,0 +1,64 @@
+#include <pthread.h>
+
+#include <darwintest.h>
+
+static volatile int once_invoked = 0;
+
+static void
+cancelation_handler(void * __unused arg)
+{
+       T_LOG("cancelled");
+}
+
+__attribute__((noreturn))
+static void
+await_cancelation(void)
+{
+       pthread_cleanup_push(cancelation_handler, NULL);
+       T_LOG("waiting for cancellation");
+
+       // can't use darwintest once cancellation is enabled
+       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+       while (true) {
+               pthread_testcancel();
+               sched_yield();
+       }
+
+       pthread_cleanup_pop(0);
+}
+
+static void *
+await_cancelation_in_once(void *arg)
+{
+       // disable cancellation until pthread_once to protect darwintest
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+       T_LOG("starting the thread");
+       pthread_once_t *once = (pthread_once_t *)arg;
+       pthread_once(once, await_cancelation);
+       return NULL;
+}
+
+static void
+oncef(void)
+{
+       T_LOG("once invoked");
+       once_invoked++;
+}
+
+T_DECL(once_cancel, "pthread_once is re-executed if cancelled")
+{
+       pthread_once_t once = PTHREAD_ONCE_INIT;
+       pthread_t t;
+       void *join_result = NULL;
+
+       T_ASSERT_POSIX_ZERO(
+                       pthread_create(&t, NULL, await_cancelation_in_once, &once), NULL);
+       T_ASSERT_POSIX_ZERO(pthread_cancel(t), NULL);
+       T_ASSERT_POSIX_ZERO(pthread_join(t, &join_result), NULL);
+       T_ASSERT_EQ(join_result, PTHREAD_CANCELED, NULL);
+
+       T_ASSERT_POSIX_ZERO(pthread_once(&once, oncef), NULL);
+       T_ASSERT_EQ(once_invoked, 1, NULL);
+}