1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "it_pthread_test.h"
32
33 static volatile int g_count = 0;
34 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
35 static int g_testAtforkCount = 0;
36 static int g_testAtforkPrepare = 0;
37 static int g_testAtforkParent = 0;
38 static int g_testAtforkChild = 0;
39 static const int SLEEP_TIME = 2;
40
Prepare()41 static void Prepare()
42 {
43 int err;
44 ICUNIT_ASSERT_EQUAL_VOID(g_testAtforkCount, 1, g_testAtforkCount);
45 err = pthread_mutex_lock(&g_lock);
46 ICUNIT_ASSERT_EQUAL_VOID(err, 0, err);
47 g_testAtforkPrepare++;
48 }
49
Parent()50 static void Parent()
51 {
52 int err;
53 ICUNIT_ASSERT_EQUAL_VOID(g_testAtforkCount, 1, g_testAtforkCount);
54
55 err = pthread_mutex_unlock(&g_lock);
56 ICUNIT_ASSERT_EQUAL_VOID(err, 0, err);
57 g_testAtforkParent++;
58 }
59
child()60 static void child()
61 {
62 int err;
63 ICUNIT_ASSERT_EQUAL_VOID(g_testAtforkCount, 1, g_testAtforkCount);
64
65 err = pthread_mutex_unlock(&g_lock);
66 ICUNIT_ASSERT_EQUAL_VOID(err, 0, err);
67 g_testAtforkChild++;
68 }
69
ThreadProc(void * arg)70 static void *ThreadProc(void *arg)
71 {
72 int err;
73
74 while (g_count < 5) { // 5, wait until g_count == 5.
75 err = pthread_mutex_lock(&g_lock);
76 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
77 g_count++;
78 SLEEP_AND_YIELD(SLEEP_TIME);
79 err = pthread_mutex_unlock(&g_lock);
80 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
81 SLEEP_AND_YIELD(SLEEP_TIME);
82 }
83
84 EXIT:
85 return NULL;
86 }
87
PthreadAtforkTest(void * arg)88 static void *PthreadAtforkTest(void *arg)
89 {
90 int err;
91 pid_t pid;
92 pthread_t tid;
93 int status = 0;
94
95 g_count = 0;
96 g_testAtforkCount = 0;
97 g_testAtforkPrepare = 0;
98 g_testAtforkParent = 0;
99 g_testAtforkChild = 0;
100
101 err = pthread_create(&tid, NULL, ThreadProc, NULL);
102 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
103 err = pthread_atfork(Prepare, Parent, child);
104 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
105
106 g_testAtforkCount++;
107
108 SLEEP_AND_YIELD(SLEEP_TIME);
109
110 pid = fork();
111 ICUNIT_GOTO_WITHIN_EQUAL(pid, 0, 100000, pid, EXIT); // 100000, The pid will never exceed 100000.
112 ICUNIT_GOTO_EQUAL(g_testAtforkPrepare, 1, g_testAtforkPrepare, EXIT);
113
114 if (pid == 0) {
115 ICUNIT_GOTO_EQUAL(g_testAtforkChild, 1, g_testAtforkChild, EXIT);
116 int status;
117 while (g_count < 5) { // 5, wait until g_count == 5.
118 err = pthread_mutex_lock(&g_lock);
119 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
120 g_count++;
121 SLEEP_AND_YIELD(SLEEP_TIME);
122 err = pthread_mutex_unlock(&g_lock);
123 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT);
124 SLEEP_AND_YIELD(SLEEP_TIME);
125 }
126 exit(15); // 15, set exit status
127 }
128
129 ICUNIT_GOTO_EQUAL(g_testAtforkParent, 1, g_testAtforkParent, EXIT_WAIT);
130 err = pthread_join(tid, NULL);
131 ICUNIT_GOTO_EQUAL(err, 0, err, EXIT_WAIT);
132
133 err = waitpid(pid, &status, 0);
134 status = WEXITSTATUS(status);
135 ICUNIT_GOTO_EQUAL(err, pid, err, EXIT);
136 ICUNIT_GOTO_EQUAL(status, 15, status, EXIT); // 15, get exit status.
137
138 EXIT:
139 return NULL;
140
141 EXIT_WAIT:
142 (void)waitpid(pid, &status, 0);
143 return NULL;
144 }
145
Testcase()146 static int Testcase()
147 {
148 int ret;
149 pthread_t newPthread;
150 int curThreadPri, curThreadPolicy;
151 pthread_attr_t a = { 0 };
152 struct sched_param param = { 0 };
153
154 ret = pthread_getschedparam(pthread_self(), &curThreadPolicy, ¶m);
155 ICUNIT_ASSERT_EQUAL(ret, 0, -ret);
156
157 curThreadPri = param.sched_priority;
158
159 ret = pthread_attr_init(&a);
160 pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
161 param.sched_priority = curThreadPri + 2; // 2, adjust the priority.
162 pthread_attr_setschedparam(&a, ¶m);
163 ret = pthread_create(&newPthread, &a, PthreadAtforkTest, 0);
164 ICUNIT_ASSERT_EQUAL(ret, 0, ret);
165
166 ret = pthread_join(newPthread, NULL);
167 ICUNIT_ASSERT_EQUAL(ret, 0, ret);
168
169 return 0;
170 }
171
ItTestPthreadAtfork001(void)172 void ItTestPthreadAtfork001(void)
173 {
174 TEST_ADD_CASE("IT_PTHREAD_ATFORK_001", Testcase, TEST_POSIX, TEST_MEM, TEST_LEVEL0, TEST_FUNCTION);
175 }
176