From 1269ce0c35fdeeb27d797f878c82d12877add874 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sun, 12 Jun 2022 12:30:37 +0200 Subject: [PATCH] Tests: Add tests for `pthread_setcancel{state,type}` We likely won't be able to test `pthread_cancel` itself, but this at least makes sure that we use the correct values by default and that we correctly reject invalid values. --- Tests/LibC/CMakeLists.txt | 1 + Tests/LibC/TestPthreadCancel.cpp | 88 ++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 Tests/LibC/TestPthreadCancel.cpp diff --git a/Tests/LibC/CMakeLists.txt b/Tests/LibC/CMakeLists.txt index 0669a656ba..28c27e9892 100644 --- a/Tests/LibC/CMakeLists.txt +++ b/Tests/LibC/CMakeLists.txt @@ -14,6 +14,7 @@ set(TEST_SOURCES TestMemalign.cpp TestMemmem.cpp TestMkDir.cpp + TestPthreadCancel.cpp TestPthreadCleanup.cpp TestPthreadSpinLocks.cpp TestPthreadRWLocks.cpp diff --git a/Tests/LibC/TestPthreadCancel.cpp b/Tests/LibC/TestPthreadCancel.cpp new file mode 100644 index 0000000000..b60d76c47a --- /dev/null +++ b/Tests/LibC/TestPthreadCancel.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022, Tim Schumacher + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#define TEST_CASE_IN_PTHREAD(x) \ + static void* __TESTCASE_FUNC(x##__inner)(void*); \ + TEST_CASE(x) \ + { \ + pthread_t thread; \ + pthread_create(&thread, nullptr, __TESTCASE_FUNC(x##__inner), nullptr); \ + pthread_join(thread, nullptr); \ + } \ + static void* __TESTCASE_FUNC(x##__inner)(void*) + +TEST_CASE_IN_PTHREAD(cancel_state_valid) +{ + int old_state = 0; + + // Ensure that we return the default state correctly. + EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state), 0); + EXPECT_EQ(old_state, PTHREAD_CANCEL_ENABLE); + + // Make sure that PTHREAD_CANCEL_DISABLE sticks. + EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state), 0); + EXPECT_EQ(old_state, PTHREAD_CANCEL_DISABLE); + + return nullptr; +} + +TEST_CASE_IN_PTHREAD(cancel_state_invalid) +{ + constexpr int lower_invalid_state = min(PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE) - 1; + constexpr int upper_invalid_state = max(PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE) + 1; + + int old_state = 0; + + // Check that both invalid states are rejected and don't change the old state. + EXPECT_EQ(pthread_setcancelstate(lower_invalid_state, &old_state), EINVAL); + EXPECT_EQ(old_state, 0); + EXPECT_EQ(pthread_setcancelstate(upper_invalid_state, &old_state), EINVAL); + EXPECT_EQ(old_state, 0); + + // Ensure that we are still in the default state afterwards. + EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state), 0); + EXPECT_EQ(old_state, PTHREAD_CANCEL_ENABLE); + + return nullptr; +} + +TEST_CASE_IN_PTHREAD(cancel_type_valid) +{ + int old_type = 0; + + // Ensure that we return the default type correctly. + EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type), 0); + EXPECT_EQ(old_type, PTHREAD_CANCEL_DEFERRED); + + // Make sure that PTHREAD_CANCEL_ASYNCHRONOUS sticks (not that it should ever be used). + EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_type), 0); + EXPECT_EQ(old_type, PTHREAD_CANCEL_ASYNCHRONOUS); + + return nullptr; +} + +TEST_CASE_IN_PTHREAD(cancel_type_invalid) +{ + constexpr int lower_invalid_type = min(PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS) - 1; + constexpr int upper_invalid_type = max(PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS) + 1; + + int old_type = 0; + + // Check that both invalid types are rejected and don't change the old type. + EXPECT_EQ(pthread_setcanceltype(lower_invalid_type, &old_type), EINVAL); + EXPECT_EQ(old_type, 0); + EXPECT_EQ(pthread_setcanceltype(upper_invalid_type, &old_type), EINVAL); + EXPECT_EQ(old_type, 0); + + // Ensure that we are still in the default state afterwards. + EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type), 0); + EXPECT_EQ(old_type, PTHREAD_CANCEL_DEFERRED); + + return nullptr; +}