unit-tests: Test cancellability of some cancellation points we rely on
authorMartin Willi <martin@revosec.ch>
Thu, 6 Nov 2014 10:19:51 +0000 (11:19 +0100)
committerMartin Willi <martin@revosec.ch>
Fri, 21 Nov 2014 11:02:07 +0000 (12:02 +0100)
src/libstrongswan/tests/suites/test_threading.c

index 7f17a9c..55a4cd7 100644 (file)
@@ -1175,6 +1175,191 @@ START_TEST(test_cancel_point)
 }
 END_TEST
 
+static void close_fd_ptr(void *fd)
+{
+       close(*(int*)fd);
+}
+
+static void cancellation_recv()
+{
+       int sv[2];
+       char buf[1];
+
+       ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+
+       thread_cleanup_push(close_fd_ptr, &sv[0]);
+       thread_cleanup_push(close_fd_ptr, &sv[1]);
+
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               ck_assert(recv(sv[0], buf, sizeof(buf), 0) == 1);
+       }
+}
+
+static void cancellation_read()
+{
+       int sv[2];
+       char buf[1];
+
+       ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+
+       thread_cleanup_push(close_fd_ptr, &sv[0]);
+       thread_cleanup_push(close_fd_ptr, &sv[1]);
+
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               ck_assert(read(sv[0], buf, sizeof(buf)) == 1);
+       }
+}
+
+static void cancellation_select()
+{
+       int sv[2];
+       fd_set set;
+
+       ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+
+       thread_cleanup_push(close_fd_ptr, &sv[0]);
+       thread_cleanup_push(close_fd_ptr, &sv[1]);
+
+       FD_ZERO(&set);
+       FD_SET(sv[0], &set);
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               ck_assert(select(sv[0] + 1, &set, NULL, NULL, NULL) == 1);
+       }
+}
+
+static void cancellation_poll()
+{
+       int sv[2];
+       struct pollfd pfd;
+
+       ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+
+       thread_cleanup_push(close_fd_ptr, &sv[0]);
+       thread_cleanup_push(close_fd_ptr, &sv[1]);
+
+       pfd.fd = sv[0];
+       pfd.events = POLLIN;
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               ck_assert(poll(&pfd, 1, -1) == 1);
+       }
+}
+
+static void cancellation_accept()
+{
+       host_t *host;
+       int fd, c;
+
+       fd = socket(AF_INET, SOCK_STREAM, 0);
+       ck_assert(fd >= 0);
+       host = host_create_from_string("127.0.0.1", 0);
+       ck_assert_msg(bind(fd, host->get_sockaddr(host),
+                                          *host->get_sockaddr_len(host)) == 0, "%m");
+       host->destroy(host);
+       ck_assert(listen(fd, 5) == 0);
+
+       thread_cleanup_push(close_fd_ptr, &fd);
+
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               c = accept(fd, NULL, NULL);
+               ck_assert(c >= 0);
+               close(c);
+       }
+}
+
+static void cancellation_cond()
+{
+       mutex_t *mutex;
+       condvar_t *cond;
+
+       mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+       cond = condvar_create(CONDVAR_TYPE_DEFAULT);
+       mutex->lock(mutex);
+
+       thread_cleanup_push((void*)mutex->destroy, mutex);
+       thread_cleanup_push((void*)cond->destroy, cond);
+
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               cond->wait(cond, mutex);
+       }
+}
+
+static void cancellation_rwcond()
+{
+       rwlock_t *lock;
+       rwlock_condvar_t *cond;
+
+       lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+       cond = rwlock_condvar_create();
+       lock->write_lock(lock);
+
+       thread_cleanup_push((void*)lock->destroy, lock);
+       thread_cleanup_push((void*)cond->destroy, cond);
+
+       thread_cancelability(TRUE);
+       while (TRUE)
+       {
+               cond->wait(cond, lock);
+       }
+}
+
+static void (*cancellation_points[])() = {
+       cancellation_read,
+       cancellation_recv,
+       cancellation_select,
+       cancellation_poll,
+       cancellation_accept,
+       cancellation_cond,
+       cancellation_rwcond,
+};
+
+static void* run_cancellation_point(void (*fn)())
+{
+       fn();
+       return NULL;
+}
+
+static void* run_cancellation_point_pre(void (*fn)())
+{
+       usleep(5000);
+       fn();
+       return NULL;
+}
+
+START_TEST(test_cancellation_point)
+{
+       thread_t *thread;
+
+       thread = thread_create((void*)run_cancellation_point,
+                                                  cancellation_points[_i]);
+       usleep(5000);
+       thread->cancel(thread);
+       thread->join(thread);
+}
+END_TEST
+
+START_TEST(test_cancellation_point_pre)
+{
+       thread_t *thread;
+
+       thread = thread_create((void*)run_cancellation_point_pre,
+                                                  cancellation_points[_i]);
+       thread->cancel(thread);
+       thread->join(thread);
+}
+END_TEST
+
 static void cleanup1(void *data)
 {
        uintptr_t *value = (uintptr_t*)data;
@@ -1500,6 +1685,13 @@ Suite *threading_suite_create()
        tcase_add_test(tc, test_cancel_point);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("thread cancellation point");
+       tcase_add_loop_test(tc, test_cancellation_point,
+                                               0, countof(cancellation_points));
+       tcase_add_loop_test(tc, test_cancellation_point_pre,
+                                               0, countof(cancellation_points));
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("thread cleanup");
        tcase_add_test(tc, test_cleanup);
        tcase_add_test(tc, test_cleanup_exit);