• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <unistd.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/shm.h>
20 #include <fcntl.h>
21 #include "log.h"
22 #include "utils.h"
23 #include "SignalTest.h"
24 
25 using namespace testing::ext;
26 
27 // static member must init before use.
28 int IpcSignalTest::mReceivedSignal = 0;
29 int IpcSignalTest::mShmid = 0;
30 siginfo_t IpcSignalTest::mSiginfo;
31 
32 
33 // special signal handler for function 'abort'
SigAbortHandler(int signum)34 void IpcSignalTest::SigAbortHandler(int signum)
35 {
36     LOG("handler: recv a signal: %d", signum);
37     int *shared = static_cast<int*>(shmat(mShmid, nullptr, 0));
38     if (shared == reinterpret_cast<int*>(-1)) {
39         LOG("SigAbortHandler: shmat fail, errno = %d", errno);
40     } else {
41         LOG("shared: %p", shared);
42         *shared = signum;
43         if (shmdt(shared) == -1) {
44             LOG("SigAbortHandler: shmdt errno = %d", errno);
45         }
46     }
47 }
48 
49 // special signal handler for function 'sigaction'
SigactionHandler(int signum,siginfo_t * si,void * ucontext)50 void IpcSignalTest::SigactionHandler(int signum, siginfo_t* si, void* ucontext)
51 {
52     LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
53     mReceivedSignal = signum;
54     // siginfo_t para is not supported yet
55 }
56 
57 // general signal handler. note: not thread-safe
SignalHandler(int signum)58 void IpcSignalTest::SignalHandler(int signum)
59 {
60     LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
61     mReceivedSignal = signum;
62 }
63 
64 SignalNameAction const ALL_SIGNALS[MAX_SIGNAL] = {
65     {"NA",      "Unknown signal",           TERMINATE},
66     {"SIGHUP",  "Hangup",                   TERMINATE}, //  1
67     {"SIGINT",  "Interrupt",                TERMINATE},
68     {"SIGQUIT", "Quit",                     COREDUMP},
69     {"SIGILL",  "Illegal instruction",      COREDUMP},
70     {"SIGTRAP", "Trace/breakpoint trap",    COREDUMP},
71     {"SIGABRT", "Aborted",                  COREDUMP},  //  alias:  SIGIOT
72     {"SIGBUS",  "Bus error",                COREDUMP},
73     {"SIGFPE",  "Arithmetic exception",     COREDUMP},
74     {"SIGKILL", "Killed",                   TERMINATE},
75     {"SIGUSR1", "User defined signal 1",    TERMINATE}, //  10
76     {"SIGSEGV", "Segmentation fault",       COREDUMP},
77     {"SIGUSR2", "User defined signal 2",    TERMINATE},
78     {"SIGPIPE", "Broken pipe",              TERMINATE},
79     {"SIGALRM", "Alarm clock",              TERMINATE},
80     {"SIGTERM", "Terminated",               TERMINATE},
81     {"SIGSTKFLT", "Stack fault",            TERMINATE},
82     {"SIGCHLD", "Child process status",     IGNORE},    //  alias:  SIGCLD
83     {"SIGCONT", "Continued",                CONTINUE},
84     {"SIGSTOP", "Stopped (signal)",         STOP},
85     {"SIGTSTP", "Stopped",                  STOP},      //  20
86     {"SIGTTIN", "Stopped (tty input)",      STOP},
87     {"SIGTTOU", "Stopped (tty output)",     STOP},
88     {"SIGURG",  "Urgent I/O condition",     IGNORE},
89     {"SIGXCPU", "CPU time limit exceeded",  COREDUMP},
90     {"SIGXFSZ", "File size limit exceeded", COREDUMP},
91     {"SIGVTALRM", "Virtual timer expired",  TERMINATE},
92     {"SIGPROF", "Profiling timer expired",  TERMINATE},
93     {"SIGWINCH",  "Window changed",         IGNORE},
94     {"SIGIO",   "I/O possible",             TERMINATE}, //  alias:  SIGPOLL
95     {"SIGPWR",  "Power failure",            TERMINATE}, //  alias:  SIGINFO,    30
96 };
97 
DefaultActionTest(const int signum,const bool expectStop,const bool coredump)98 void IpcSignalTest::DefaultActionTest(const int signum, const bool expectStop, const bool coredump)
99 {
100     pid_t pid = fork();
101     ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
102     if (pid > 0) { // parent
103         Msleep(20);
104         LOGD("before kill");
105         kill(pid, signum);
106         if (!expectStop) {
107             Msleep(20);
108             AssertProcAlive(pid);
109             Msleep(20);
110             WaitProcExitedOK(pid);
111         } else {
112             WaitProcKilled(pid, signum);
113             if (coredump) {
114                 // check codedump, liteos not support yet
115             }
116         }
117     } else { // child
118         LOGD("child start");
119         KeepRun(KEEP_RUN_TIME);
120         if (expectStop) {
121             LOG("Child should has been Terminated, but still alive.");
122             exit(1);
123         }
124         exit(0);
125     }
126 }
127 
SendAndRecvTest(const int signum)128 void IpcSignalTest::SendAndRecvTest(const int signum)
129 {
130     pid_t pid1, pid2;
131     bool useBrother = GetRandom(100) % 2; // if use brother to send the signal
132     pid1 = fork();
133     ASSERT_TRUE(pid1 >= 0) << "======== Fork1 Error! =========";
134     if (pid1 > 0) { // parent
135         LOGD("in parent...");
136         if (useBrother) {
137             pid2 = fork();
138             ASSERT_TRUE(pid2 >= 0) << "======== Fork2 Error! =========";
139             if (pid2 == 0) { // child 2
140                 Msleep(50);
141                 kill(pid1, signum);
142                 exit(0);
143             }
144             // parent
145             Msleep(20);
146             LOG("check if child2 exited OK");
147             WaitProcExitedOK(pid2);
148         } else {
149             Msleep(100);
150             kill(pid1, signum);
151         }
152         AssertProcAlive(pid1);
153 
154         Msleep(20); // child should exited now
155         LOG("check if child exited OK");
156         WaitProcExitedOK(pid1);
157     } else { // child 1, the receiver
158         LOGD("in child, pid=%d", getpid());
159         handler_type rt = signal(signum, SignalHandler);
160         if (rt == SIG_ERR) {
161             LOG("set %d signal handler failed, errno=%d", signum, errno);
162             exit(1);
163         }
164         Msleep(150);
165         if (mReceivedSignal != signum) {
166             LOG("SignalHandler check fail, expected=%d, received=%d", signum, mReceivedSignal);
167             exit(1);
168         }
169         LOGD("child sleeping....");
170         Msleep(20);
171         LOGD("child exit 0....");
172         exit(0);
173     }
174 }
175 
CheckSigString(const char * outfile,const char * expectStr)176 int IpcSignalTest::CheckSigString(const char* outfile, const char* expectStr)
177 {
178     const int bufLen = 64;
179     char buffer[bufLen];
180 
181     FILE *fp = fopen(outfile, "rb");
182     size_t bytes = fread(buffer, 1, bufLen, fp);
183     buffer[bytes] = 0;
184     LOGD("%d bytes read from logfile:%s", bytes, buffer);
185     fclose(fp);
186     size_t expectLen = strlen(expectStr);
187     LOGD("expect string len = %d", expectLen);
188     if (bytes != (expectLen + 1)) {
189         LOG("bytes number read from stderr file error, expect:%d, actual:%d",
190             expectLen + 1, bytes);
191         return 1;
192     }
193     return strncmp(expectStr, buffer, expectLen);
194 }
195 
SignalFailTest(int signum,handler_type h,int expectErrno)196 void IpcSignalTest::SignalFailTest(int signum, handler_type h, int expectErrno)
197 {
198     errno = 0;
199     handler_type rt = signal(signum, h);
200     ASSERT_EQ(rt, SIG_ERR) << "signal error for " << signum;
201     ASSERT_EQ(errno, expectErrno) << "signal error for " << signum;
202 }
SigpendingFailTest(sigset_t * pset)203 void IpcSignalTest::SigpendingFailTest(sigset_t* pset)
204 {
205     errno = 0;
206     int rt = sigpending(pset);
207     ASSERT_EQ(rt, -1);
208     ASSERT_EQ(errno, EFAULT);
209 }
SigtimedwaitFailTest(const sigset_t * set,siginfo_t * info,const timespec * timeout,int expectErrno)210 void IpcSignalTest::SigtimedwaitFailTest(const sigset_t *set, siginfo_t* info, const timespec* timeout, int expectErrno)
211 {
212     errno = 0;
213     int rt = sigtimedwait(set, info, timeout);
214     ASSERT_EQ(rt, -1);
215     ASSERT_EQ(errno, expectErrno);
216 }
217 
218 // thread function for testcase: 'testPthreadkill'
ThreadFunc1(void * arg)219 void* IpcSignalTest::ThreadFunc1(void* arg)
220 {
221     int sigNo = (int)((uintptr_t)arg);
222     signal(sigNo, SignalHandler);
223     Msleep(60);
224     return nullptr;
225 }
226 
227 // thread function for testcase: 'testPthreadkillMain'
ThreadFunc2(void * arg)228 void* IpcSignalTest::ThreadFunc2(void* arg)
229 {
230     pthread_t* tid = (pthread_t*)arg;
231     int ret = pthread_kill(*tid, SIGINT);
232     if (ret != 0) {
233         LOG("pthread_kill failed, errno=%d", ret);
234         return (void*)1;
235     }
236     LOG("pthread_kill send signal(%d) ok", SIGINT);
237     return nullptr;
238 }
239 
240 // thread function for testcase: 'testPthreadSigmask'
ThreadFuncForSigmask1(void * arg)241 void* IpcSignalTest::ThreadFuncForSigmask1(void* arg)
242 {
243     int rt;
244     int type = (int)((uintptr_t)arg);
245     if (type == 1) {
246         signal(SIGINT, SignalHandler);
247     }
248 
249     LOG("block SIGINT");
250     sigset_t sigmask, oldmask;
251     sigemptyset(&sigmask);
252     sigemptyset(&oldmask);
253     sigaddset(&sigmask, SIGINT);
254     sigaddset(&sigmask, SIGUSR1);
255     rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
256     EXPECT_EQ(rt, 0);
257     raise(SIGINT);
258     EXPECT_EQ(mReceivedSignal, 0) << "SignalHandler check fail, SIGINT should has blocked!";
259 
260     LOG("unblock SIGINT");
261     sigemptyset(&sigmask);
262     sigaddset(&sigmask, SIGINT);
263     rt = pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr);
264     EXPECT_EQ(rt, 0);
265 
266     LOG("check the new block set");
267     sigemptyset(&oldmask);
268     pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
269     EXPECT_EQ(sigismember(&oldmask, SIGINT), 0) << "SIGINT should has deleted from block set!";
270     EXPECT_EQ(sigismember(&oldmask, SIGUSR1), 1) << "SIGUSR1 should still in block set!";
271 
272     EXPECT_EQ(mReceivedSignal, SIGINT) << "SignalHandler check fail, SIGINT should deliver after unblock!";
273     return nullptr;
274 }
275 
276 // thread function for testcase: 'testPthreadSigmaskInherit'
ThreadFuncForSigmask2(void * arg)277 void* IpcSignalTest::ThreadFuncForSigmask2(void* arg)
278 {
279     sigset_t sigmask, oldmask;
280     sigemptyset(&sigmask);
281     sigemptyset(&oldmask);
282 
283     LOG("SubThread: check the block set is inherited");
284     pthread_sigmask(SIG_BLOCK, nullptr, &oldmask);
285     if (!sigismember(&oldmask, SIGUSR1)) {
286         LOG("initial block set should include SIGUSR1!");
287         return (void*)1;
288     }
289 
290     LOG("SubThread: add SIGINT to block set");
291     sigaddset(&sigmask, SIGINT);
292     int rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
293     EXPECT_EQ(rt, 0);
294 
295     LOG("SubThread: check the new block set");
296     sigemptyset(&oldmask);
297     pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
298     if (!sigismember(&oldmask, SIGINT)) {
299         LOG("failed to add SIGINT to block set!");
300         return (void*)1;
301     }
302     if (!sigismember(&oldmask, SIGUSR1)) {
303         LOG("SIGUSR1 should still in block set!");
304         return (void*)1;
305     }
306     return nullptr;
307 }