• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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