1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // Signal stress test is in a separate source file because we disable it for static test version
18 // (see Android.bp). Also this way we isolate some extra includes from the main signal test source.
19
20 #include "gtest/gtest.h"
21
22 #include <errno.h>
23 #include <pthread.h>
24 #include <semaphore.h>
25 #include <signal.h>
26 #include <sys/epoll.h>
27
28 #include "berberis/ndk_program_tests/scoped_sigaction.h"
29
30 namespace {
31
32 volatile bool g_stress_finished;
33 sem_t g_stress_sem;
34
StressResumeHandler(int signal)35 void StressResumeHandler(int signal) {
36 ASSERT_EQ(signal, SIGXCPU);
37 ASSERT_EQ(0, sem_post(&g_stress_sem));
38
39 // Warning: next SIGPWR is blocked in sigaction, so that we don't have deep recursive handler
40 // calls.
41 }
42
StressSuspendHandler(int signal)43 void StressSuspendHandler(int signal) {
44 ASSERT_EQ(signal, SIGPWR);
45 ASSERT_EQ(0, sem_post(&g_stress_sem));
46
47 // Warning: SIGXCPU is blocked in sigaction, so that we don't receive it before sigsuspend.
48
49 sigset_t suspend_mask;
50 ASSERT_EQ(0, sigemptyset(&suspend_mask));
51 ASSERT_EQ(-1, sigsuspend(&suspend_mask));
52 ASSERT_EQ(errno, EINTR);
53 }
54
55 struct StressArg {
56 int epoll_fd;
57 };
58
StressWaitForSuspendRunner(void * a)59 void* StressWaitForSuspendRunner(void* a) {
60 StressArg* arg = reinterpret_cast<StressArg*>(a);
61 epoll_event events[1];
62
63 while (!g_stress_finished) {
64 // TODO: Add pthread_cond_wait here.
65
66 // Warning: cannot use ASSERT in the function returning non-void.
67 EXPECT_EQ(-1, epoll_wait(arg->epoll_fd, events, 1, -1));
68 EXPECT_EQ(errno, EINTR);
69 }
70 return NULL;
71 }
72
TEST(Signal,SignalStressTest)73 TEST(Signal, SignalStressTest) {
74 struct sigaction sa;
75 memset(&sa, 0, sizeof(sa));
76
77 // Set suspend sigaction.
78 // Block SIGXCPU to make sem_post / sigsuspend combination functional.
79 ASSERT_EQ(0, sigemptyset(&sa.sa_mask));
80 ASSERT_EQ(0, sigaddset(&sa.sa_mask, SIGXCPU));
81 sa.sa_handler = StressSuspendHandler;
82 ScopedSigaction scoped_pwr(SIGPWR, &sa);
83
84 // Set resume sigaction.
85 // Block SIGPWR to prevent deep stacks in recursive handler calls.
86 ASSERT_EQ(0, sigemptyset(&sa.sa_mask));
87 ASSERT_EQ(0, sigaddset(&sa.sa_mask, SIGPWR));
88 sa.sa_handler = StressResumeHandler;
89 ScopedSigaction scoped_xcpu(SIGXCPU, &sa);
90
91 g_stress_finished = false;
92 sem_init(&g_stress_sem, 0, 0);
93
94 StressArg arg;
95 arg.epoll_fd = epoll_create(1);
96 ASSERT_NE(-1, arg.epoll_fd);
97
98 // Start threads.
99 static int kStressNumChild = 32;
100 pthread_t child_id[kStressNumChild];
101 for (int i = 0; i < kStressNumChild; ++i) {
102 ASSERT_EQ(0, pthread_create(&child_id[i], NULL, StressWaitForSuspendRunner, &arg));
103 }
104
105 for (int stress_rep = 0; stress_rep < 1000; ++stress_rep) {
106 // Suspend and wait.
107 for (int i = 0; i < kStressNumChild; ++i) {
108 ASSERT_EQ(pthread_kill(child_id[i], SIGPWR), 0);
109 }
110
111 for (int i = 0; i < kStressNumChild; ++i) {
112 // After the first sem_post children wait on sigsuspend.
113 ASSERT_EQ(sem_wait(&g_stress_sem), 0);
114 }
115
116 // Resume and wait.
117 for (int i = 0; i < kStressNumChild; ++i) {
118 ASSERT_EQ(pthread_kill(child_id[i], SIGXCPU), 0);
119 }
120
121 for (int i = 0; i < kStressNumChild; ++i) {
122 // After the second sem_post children wait continue looping in
123 // StressWaitForSuspendRunner.
124 ASSERT_EQ(sem_wait(&g_stress_sem), 0);
125 }
126 }
127
128 g_stress_finished = true;
129
130 // Make sure child threads wake up.
131 for (int i = 0; i < kStressNumChild; ++i) {
132 // Do not check return status, as child may have already exited.
133 pthread_kill(child_id[i], SIGXCPU);
134 }
135
136 for (int i = 0; i < kStressNumChild; i++) {
137 ASSERT_EQ(0, pthread_join(child_id[i], NULL));
138 }
139
140 close(arg.epoll_fd);
141 }
142
143 } // namespace
144