Serenity Operating System
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
10static size_t exit_count = 0;
11
12static void exit_count_test_handler(void* data)
13{
14 EXPECT_EQ(exit_count, reinterpret_cast<size_t>(data));
15 exit_count++;
16}
17
18static void immediate_fail_handler(void*)
19{
20 FAIL("Called a cleanup handler");
21}
22
23static void* cleanup_pthread_exit_inner(void*)
24{
25 // Push handlers in reverse order as they are taken from the top of the stack on cleanup.
26 pthread_cleanup_push(exit_count_test_handler, reinterpret_cast<void*>(2));
27 pthread_cleanup_push(exit_count_test_handler, reinterpret_cast<void*>(1));
28 pthread_cleanup_push(exit_count_test_handler, reinterpret_cast<void*>(0));
29
30 pthread_exit(nullptr);
31}
32
33TEST_CASE(cleanup_pthread_exit)
34{
35 pthread_t thread;
36 exit_count = 0;
37
38 pthread_create(&thread, nullptr, cleanup_pthread_exit_inner, nullptr);
39
40 pthread_join(thread, nullptr);
41
42 // Ensure that all exit handlers have been called.
43 EXPECT_EQ(exit_count, 3ul);
44}
45
46static void* cleanup_return_inner(void*)
47{
48 // Returning from the main function should not call any cleanup handlers.
49 pthread_cleanup_push(immediate_fail_handler, nullptr);
50 return nullptr;
51}
52
53TEST_CASE(cleanup_return)
54{
55 pthread_t thread;
56 pthread_create(&thread, nullptr, cleanup_return_inner, nullptr);
57 pthread_join(thread, nullptr);
58}
59
60static void* cleanup_pop_inner(void*)
61{
62 pthread_cleanup_push(exit_count_test_handler, reinterpret_cast<void*>(1));
63 pthread_cleanup_push(immediate_fail_handler, nullptr);
64 pthread_cleanup_push(exit_count_test_handler, reinterpret_cast<void*>(0));
65 pthread_cleanup_push(immediate_fail_handler, nullptr);
66
67 // Popping a cleanup handler shouldn't run the callback unless `execute` is given.
68 pthread_cleanup_pop(0);
69 pthread_cleanup_pop(1);
70 pthread_cleanup_pop(0);
71 pthread_cleanup_pop(1);
72
73 return nullptr;
74}
75
76TEST_CASE(cleanup_pop)
77{
78 pthread_t thread;
79 exit_count = 0;
80
81 pthread_create(&thread, nullptr, cleanup_pop_inner, nullptr);
82 pthread_join(thread, nullptr);
83
84 // Ensure that all exit handlers have been called.
85 EXPECT_EQ(exit_count, 2ul);
86}