Serenity Operating System
at master 126 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2022, Tim Schumacher <timschumi@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibTest/TestCase.h> 8#include <pthread.h> 9#include <unistd.h> 10 11#define TEST_CASE_IN_PTHREAD(x) \ 12 static void* __TESTCASE_FUNC(x##__inner)(void*); \ 13 TEST_CASE(x) \ 14 { \ 15 pthread_t thread; \ 16 pthread_create(&thread, nullptr, __TESTCASE_FUNC(x##__inner), nullptr); \ 17 pthread_join(thread, nullptr); \ 18 } \ 19 static void* __TESTCASE_FUNC(x##__inner)(void*) 20 21TEST_CASE_IN_PTHREAD(cancel_state_valid) 22{ 23 int old_state = 0; 24 25 // Ensure that we return the default state correctly. 26 EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state), 0); 27 EXPECT_EQ(old_state, PTHREAD_CANCEL_ENABLE); 28 29 // Make sure that PTHREAD_CANCEL_DISABLE sticks. 30 EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state), 0); 31 EXPECT_EQ(old_state, PTHREAD_CANCEL_DISABLE); 32 33 return nullptr; 34} 35 36TEST_CASE_IN_PTHREAD(cancel_state_invalid) 37{ 38 constexpr int lower_invalid_state = min(PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE) - 1; 39 constexpr int upper_invalid_state = max(PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE) + 1; 40 41 int old_state = 0; 42 43 // Check that both invalid states are rejected and don't change the old state. 44 EXPECT_EQ(pthread_setcancelstate(lower_invalid_state, &old_state), EINVAL); 45 EXPECT_EQ(old_state, 0); 46 EXPECT_EQ(pthread_setcancelstate(upper_invalid_state, &old_state), EINVAL); 47 EXPECT_EQ(old_state, 0); 48 49 // Ensure that we are still in the default state afterwards. 50 EXPECT_EQ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state), 0); 51 EXPECT_EQ(old_state, PTHREAD_CANCEL_ENABLE); 52 53 return nullptr; 54} 55 56TEST_CASE_IN_PTHREAD(cancel_type_valid) 57{ 58 int old_type = 0; 59 60 // Ensure that we return the default type correctly. 61 EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type), 0); 62 EXPECT_EQ(old_type, PTHREAD_CANCEL_DEFERRED); 63 64 // Make sure that PTHREAD_CANCEL_ASYNCHRONOUS sticks (not that it should ever be used). 65 EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_type), 0); 66 EXPECT_EQ(old_type, PTHREAD_CANCEL_ASYNCHRONOUS); 67 68 return nullptr; 69} 70 71TEST_CASE_IN_PTHREAD(cancel_type_invalid) 72{ 73 constexpr int lower_invalid_type = min(PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS) - 1; 74 constexpr int upper_invalid_type = max(PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS) + 1; 75 76 int old_type = 0; 77 78 // Check that both invalid types are rejected and don't change the old type. 79 EXPECT_EQ(pthread_setcanceltype(lower_invalid_type, &old_type), EINVAL); 80 EXPECT_EQ(old_type, 0); 81 EXPECT_EQ(pthread_setcanceltype(upper_invalid_type, &old_type), EINVAL); 82 EXPECT_EQ(old_type, 0); 83 84 // Ensure that we are still in the default state afterwards. 85 EXPECT_EQ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type), 0); 86 EXPECT_EQ(old_type, PTHREAD_CANCEL_DEFERRED); 87 88 return nullptr; 89} 90 91static void cancel_clenaup_handler(void* data) 92{ 93 (*static_cast<bool*>(data)) = true; 94} 95 96static void* cancel_inner(void* data) 97{ 98 pthread_cleanup_push(cancel_clenaup_handler, data); 99 100 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); 101 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, nullptr); 102 103 // Sleep for a second until the other side sets up their end of the check, 104 // then do a call to write, which should be a cancellation point. 105 sleep(1); 106 write(STDOUT_FILENO, nullptr, 0); 107 108 pthread_exit(nullptr); 109} 110 111TEST_CASE(cancel) 112{ 113 pthread_t thread; 114 115 bool called_cleanup_handler = false; 116 pthread_create(&thread, nullptr, cancel_inner, &called_cleanup_handler); 117 118 int rc = pthread_cancel(thread); 119 120 void* exit_code; 121 pthread_join(thread, &exit_code); 122 123 EXPECT_EQ(rc, 0); 124 EXPECT_EQ(called_cleanup_handler, true); 125 EXPECT_EQ(exit_code, PTHREAD_CANCELED); 126}