1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17 #include "platforms/unix/libpandabase/signal.h"
18
19 namespace panda::os::unix {
20
operator ==(const::panda::os::unix::SignalCtl & l,const::panda::os::unix::SignalCtl & r)21 bool operator==(const ::panda::os::unix::SignalCtl &l, const ::panda::os::unix::SignalCtl &r)
22 {
23 return 0U == memcmp(&l, &r, sizeof(l));
24 }
25
operator !=(const::panda::os::unix::SignalCtl & l,const::panda::os::unix::SignalCtl & r)26 bool operator!=(const ::panda::os::unix::SignalCtl &l, const ::panda::os::unix::SignalCtl &r)
27 {
28 return !(l == r);
29 }
30
31 } // namespace panda::os::unix
32
33 namespace panda::test {
34
35 class UnixSignal : public ::testing::Test {
36 protected:
SetUpTestSuite()37 static void SetUpTestSuite() {}
38
SetUp()39 void SetUp() override
40 {
41 os::unix::SignalCtl::GetCurrent(signalCtl_);
42 sigActionCount_ = 0;
43 }
44
TearDown()45 void TearDown() override
46 {
47 os::unix::SignalCtl signalCtl;
48 os::unix::SignalCtl::GetCurrent(signalCtl);
49 }
50
SigAction(int sig,UnixSignal * self)51 static void SigAction(int sig, UnixSignal *self)
52 {
53 self->sigActionCount_ += sig;
54 }
55
Delay()56 static void Delay()
57 {
58 usleep(TIME_TO_WAIT);
59 }
60
CheckSignalsInsideCycle(int signals)61 void CheckSignalsInsideCycle(int signals)
62 {
63 uint32_t timeoutCounter = 0;
64 while (true) {
65 if (sigActionCount_ == signals) {
66 break;
67 }
68
69 ++timeoutCounter;
70 Delay();
71
72 ASSERT_NE(timeoutCounter, maxTimeoutCounterWait_) << "Timeout error: Signals not got in time";
73 }
74 }
75
76 static const uint32_t TIME_TO_WAIT = 100U * 1000U; // 0.1 second
77 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
78 const uint32_t maxTimeoutCounterWait_ = 5U * 60U * 1000U * 1000U / TIME_TO_WAIT; // 5 minutes
79
80 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
81 os::unix::SignalCtl signalCtl_ {};
82 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
83 std::atomic_int sigActionCount_ {0U};
84 };
85
TEST_F(UnixSignal,CheckRestoringSigSet)86 TEST_F(UnixSignal, CheckRestoringSigSet)
87 {
88 // This check is performed by UnixSignal.TearDown()
89 }
90
TEST_F(UnixSignal,CheckRestoringSigSet2)91 TEST_F(UnixSignal, CheckRestoringSigSet2)
92 {
93 sigset_t sigset;
94 sigemptyset(&sigset);
95 sigaddset(&sigset, SIGUSR1);
96 pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
97
98 os::unix::SignalCtl signalCtl;
99 os::unix::SignalCtl::GetCurrent(signalCtl);
100 ASSERT_NE(signalCtl_, signalCtl);
101
102 pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
103 }
104
TEST_F(UnixSignal,StartStopThread)105 TEST_F(UnixSignal, StartStopThread)
106 {
107 os::unix::SignalCatcherThread catcherThread;
108
109 catcherThread.StartThread(&UnixSignal::SigAction, this);
110 catcherThread.StopThread();
111 }
112
TEST_F(UnixSignal,StartStopThreadCatchOnlyCatcherThread)113 TEST_F(UnixSignal, StartStopThreadCatchOnlyCatcherThread)
114 {
115 os::unix::SignalCatcherThread catcherThread;
116 catcherThread.CatchOnlyCatcherThread();
117
118 catcherThread.StartThread(&UnixSignal::SigAction, this);
119 catcherThread.StopThread();
120 }
121
TEST_F(UnixSignal,SendSignalsToMainThread)122 TEST_F(UnixSignal, SendSignalsToMainThread)
123 {
124 os::unix::SignalCatcherThread catcherThread({SIGUSR1, SIGUSR2});
125 catcherThread.StartThread(&UnixSignal::SigAction, this);
126
127 // Send signals to main thread
128 kill(getpid(), SIGUSR1);
129 kill(getpid(), SIGUSR2);
130
131 // Wait for the signals inside the cycle
132 CheckSignalsInsideCycle(SIGUSR1 + SIGUSR2);
133 catcherThread.StopThread();
134
135 ASSERT_EQ(sigActionCount_, SIGUSR1 + SIGUSR2);
136 }
137
138 // The test fails on WSL
139 #ifndef PANDA_TARGET_WSL
TEST_F(UnixSignal,SendSignalsToMainThread2)140 TEST_F(UnixSignal, SendSignalsToMainThread2)
141 {
142 EXPECT_DEATH(
143 {
144 os::unix::SignalCatcherThread catcherThread({SIGUSR1});
145 catcherThread.CatchOnlyCatcherThread();
146
147 catcherThread.StartThread(&UnixSignal::SigAction, this);
148
149 // Send signals to main thread
150 catcherThread.SendSignal(SIGUSR1);
151 CheckSignalsInsideCycle(SIGUSR1);
152
153 // After kill process must die
154 kill(getpid(), SIGUSR1);
155 CheckSignalsInsideCycle(SIGUSR1 + SIGUSR1);
156 catcherThread.StopThread();
157
158 ASSERT_EQ(true, false) << "Error: Thread must die before this assert";
159 },
160 "");
161 }
162 #endif // PANDA_TARGET_WSL
163
TEST_F(UnixSignal,SendSignalsToCatcherThread)164 TEST_F(UnixSignal, SendSignalsToCatcherThread)
165 {
166 os::unix::SignalCatcherThread catcherThread({SIGUSR1, SIGUSR2});
167 catcherThread.CatchOnlyCatcherThread();
168
169 catcherThread.StartThread(&UnixSignal::SigAction, this);
170
171 // Send signals to catcher thread
172 catcherThread.SendSignal(SIGUSR1);
173 catcherThread.SendSignal(SIGUSR2);
174
175 // Wait for the signals inside the cycle
176 CheckSignalsInsideCycle(SIGUSR1 + SIGUSR2);
177 catcherThread.StopThread();
178
179 ASSERT_EQ(sigActionCount_, SIGUSR1 + SIGUSR2);
180 }
181
TEST_F(UnixSignal,SendUnhandledSignal)182 TEST_F(UnixSignal, SendUnhandledSignal)
183 {
184 EXPECT_DEATH(
185 {
186 os::unix::SignalCatcherThread catcherThread({SIGUSR1});
187 catcherThread.StartThread(&UnixSignal::SigAction, this);
188
189 // Send signals to catcher thread
190 catcherThread.SendSignal(SIGUSR1);
191 catcherThread.SendSignal(SIGUSR2);
192
193 // Wait for the signals inside the cycle
194 CheckSignalsInsideCycle(SIGUSR1 + SIGUSR2);
195 catcherThread.StopThread();
196
197 ASSERT_EQ(sigActionCount_, SIGUSR1 + SIGUSR2);
198 },
199 "");
200 }
201
TEST_F(UnixSignal,SendSomeSignalsToCatcherThread)202 TEST_F(UnixSignal, SendSomeSignalsToCatcherThread)
203 {
204 os::unix::SignalCatcherThread catcherThread({SIGQUIT, SIGUSR1, SIGUSR2});
205 catcherThread.CatchOnlyCatcherThread();
206
207 catcherThread.StartThread(&UnixSignal::SigAction, this);
208
209 // Send signals to catcher thread
210 catcherThread.SendSignal(SIGQUIT);
211 catcherThread.SendSignal(SIGUSR1);
212 catcherThread.SendSignal(SIGUSR2);
213
214 // Wait for the signals inside the cycle
215 CheckSignalsInsideCycle(SIGQUIT + SIGUSR1 + SIGUSR2);
216 catcherThread.StopThread();
217
218 ASSERT_EQ(sigActionCount_, SIGQUIT + SIGUSR1 + SIGUSR2);
219 }
220
TEST_F(UnixSignal,AfterThreadStartCallback)221 TEST_F(UnixSignal, AfterThreadStartCallback)
222 {
223 os::unix::SignalCatcherThread catcherThread({SIGQUIT});
224
225 // NOLINTNEXTLINE(readability-magic-numbers)
226 catcherThread.SetupCallbacks([this]() { sigActionCount_ += 1000U; }, nullptr);
227
228 catcherThread.StartThread(&UnixSignal::SigAction, this);
229
230 // Send signals to catcher thread
231 catcherThread.SendSignal(SIGQUIT);
232
233 // Wait for the signals inside the cycle
234 // NOLINTNEXTLINE(readability-magic-numbers)
235 CheckSignalsInsideCycle(SIGQUIT + 1000U);
236 catcherThread.StopThread();
237
238 ASSERT_EQ(sigActionCount_, SIGQUIT + 1000U);
239 }
240
TEST_F(UnixSignal,BeforeThreadStopCallback)241 TEST_F(UnixSignal, BeforeThreadStopCallback)
242 {
243 os::unix::SignalCatcherThread catcherThread({SIGQUIT});
244
245 // NOLINTNEXTLINE(readability-magic-numbers)
246 catcherThread.SetupCallbacks(nullptr, [this]() { sigActionCount_ += 2000U; });
247
248 catcherThread.StartThread(&UnixSignal::SigAction, this);
249
250 // Send signals to catcher thread
251 catcherThread.SendSignal(SIGQUIT);
252
253 // Wait for the signals inside the cycle
254 CheckSignalsInsideCycle(SIGQUIT);
255 catcherThread.StopThread();
256
257 ASSERT_EQ(sigActionCount_, SIGQUIT + 2000U);
258 }
259
TEST_F(UnixSignal,ThreadCallbacks)260 TEST_F(UnixSignal, ThreadCallbacks)
261 {
262 os::unix::SignalCatcherThread catcherThread({SIGQUIT});
263
264 // NOLINTNEXTLINE(readability-magic-numbers)
265 catcherThread.SetupCallbacks([this]() { sigActionCount_ += 1000U; }, [this]() { sigActionCount_ += 2000U; });
266
267 catcherThread.StartThread(&UnixSignal::SigAction, this);
268
269 // Send signals to catcher thread
270 catcherThread.SendSignal(SIGQUIT);
271
272 // Wait for the signals inside the cycle
273 // NOLINTNEXTLINE(readability-magic-numbers)
274 CheckSignalsInsideCycle(1000U + SIGQUIT);
275 catcherThread.StopThread();
276
277 ASSERT_EQ(sigActionCount_, 1000U + SIGQUIT + 2000U);
278 }
279
280 } // namespace panda::test
281