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