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 "hc_thread_test.h"
17
18 #include <hctest.h>
19 #include <pthread.h>
20 #include <securec.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include "hc_thread_mutex_share.h"
25 #include "print_log.h"
26 #include "test_timer.h"
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #define REQUIRED_PTHREAD_ATTR_COUNT 20
33 #define TEST_STRING "hello"
34
35 typedef struct {
36 void *(*function)(void *);
37 size_t sz;
38 int i;
39 char *str;
40 } ThreadTestArgs;
41
ThreadRountine(void * args)42 static void *ThreadRountine(void *args)
43 {
44 TEST_ASSERT_NOT_NULL(args);
45
46 ThreadTestArgs *testArgs = (ThreadTestArgs *)args;
47 int sleepSeconds = rand() % (WAIT_IN_MUTEX_SECONDS_MAX - WAIT_IN_MUTEX_SECONDS_MIN) + WAIT_IN_MUTEX_SECONDS_MIN;
48
49 TEST_ASSERT_EQUAL((void *)ThreadRountine, (void *)testArgs->function);
50 TEST_ASSERT_EQUAL((size_t)MAX_THREAD_STACK_SIZE, testArgs->sz);
51 TEST_ASSERT_GREATER_OR_EQUAL(MIN_THREAD_STACK_SIZE, testArgs->i);
52 TEST_ASSERT_LESS_OR_EQUAL(MAX_THREAD_STACK_SIZE, testArgs->i);
53 TEST_ASSERT_EQUAL_STRING(TEST_STRING, testArgs->str);
54
55 LOGI("test thread begin wait for %d seconds", sleepSeconds);
56 sleep(sleepSeconds);
57 LOGI("test thread wait for %d seconds successfully", sleepSeconds);
58
59 LOGI("begin time consuming operation");
60 unsigned long long res;
61 RUN_AND_PRINT_ELAPSED_TIME(res, TimeConsumingOperation());
62 LOGI("end time consuming operation, res = %llu", res);
63 return args;
64 }
65
GetStackSize(void)66 static int GetStackSize(void)
67 {
68 // use macro instead of enum to avoid error: division by zero [-Werror=div-by-zero]
69 #if (MAX_THREAD_STACK_SIZE == MIN_THREAD_STACK_SIZE)
70 return MIN_THREAD_STACK_SIZE;
71 #else
72 int stackSize = rand() % (MAX_THREAD_STACK_SIZE - MIN_THREAD_STACK_SIZE) + MIN_THREAD_STACK_SIZE;
73 LOGI("rand stack size = %d", stackSize);
74 return stackSize;
75 #endif
76 }
77
TestSpecifiedCount(int count,int detachState)78 static void TestSpecifiedCount(int count, int detachState)
79 {
80 TEST_ASSERT_GREATER_THAN(0, count);
81 TEST_ASSERT_LESS_OR_EQUAL(REQUIRED_THREAD_COUNT, count);
82 TEST_ASSERT_TRUE_MESSAGE(detachState == PTHREAD_CREATE_JOINABLE || detachState == PTHREAD_CREATE_DETACHED,
83 "invalid detach state");
84
85 pthread_attr_t attr;
86 pthread_t threads[REQUIRED_THREAD_COUNT];
87 int res, stackSize;
88 static ThreadTestArgs args = {
89 .function = ThreadRountine,
90 .sz = MAX_THREAD_STACK_SIZE,
91 .i = -1,
92 .str = (char *)TEST_STRING,
93 };
94
95 res = memset_s(threads, sizeof(threads), 0, sizeof(threads));
96 TEST_ASSERT_EQUAL(0, res);
97
98 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_init(&attr));
99 TEST_ASSERT_EQUAL(0, res);
100
101 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_setdetachstate(&attr, detachState));
102 TEST_ASSERT_EQUAL(0, res);
103
104 for (int i = 0; i < count; ++i) {
105 LOGI("test thread %d/%d", i, count);
106 stackSize = GetStackSize();
107 LOGI("rand stack size = %d", stackSize);
108 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_setstacksize(&attr, stackSize));
109 TEST_ASSERT_EQUAL(0, res);
110
111 args.i = stackSize;
112 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_create(&threads[i], &attr, ThreadRountine, &args));
113 TEST_ASSERT_EQUAL(0, res);
114 }
115
116 if (detachState == PTHREAD_CREATE_JOINABLE) {
117 for (int i = 0; i < count; ++i) {
118 LOGI("test thread %d/%d", i, count);
119 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_join(threads[i], NULL));
120 LOGI("pthread_join result = %d", res);
121 TEST_ASSERT_EQUAL(0, res);
122 }
123 } else {
124 LOGI("detachState is PTHREAD_CREATE_DETACHED, do not test pthread_join");
125 }
126
127 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_destroy(&attr));
128 TEST_ASSERT_EQUAL(0, res);
129 }
130
TestPthreadAttr(int detachState)131 static void TestPthreadAttr(int detachState)
132 {
133 TEST_ASSERT_TRUE_MESSAGE(detachState == PTHREAD_CREATE_JOINABLE || detachState == PTHREAD_CREATE_DETACHED,
134 "invalid detach state");
135
136 int res, stackSize;
137 pthread_attr_t attr[REQUIRED_PTHREAD_ATTR_COUNT];
138 res = memset_s(attr, sizeof(attr), 0, sizeof(attr));
139 TEST_ASSERT_EQUAL(0, res);
140 for (int i = 0; i < REQUIRED_PTHREAD_ATTR_COUNT; ++i) {
141 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_init(&attr[i]));
142 TEST_ASSERT_EQUAL(0, res);
143 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_setdetachstate(&attr[i], detachState));
144 TEST_ASSERT_EQUAL(0, res);
145 stackSize = GetStackSize();
146 LOGI("rand stack size = %d", stackSize);
147 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_setstacksize(&attr[i], stackSize));
148 TEST_ASSERT_EQUAL(0, res);
149 }
150
151 for (int i = 0; i < REQUIRED_PTHREAD_ATTR_COUNT; ++i) {
152 RUN_AND_PRINT_ELAPSED_TIME(res, pthread_attr_destroy(&attr[i]));
153 TEST_ASSERT_EQUAL(0, res);
154 }
155 }
156
TestState(int detachState)157 static void TestState(int detachState)
158 {
159 TEST_ASSERT_TRUE_MESSAGE(detachState == PTHREAD_CREATE_JOINABLE || detachState == PTHREAD_CREATE_DETACHED,
160 "invalid detach state");
161
162 TestPthreadAttr(detachState);
163 LOGI("test one thread");
164 TestSpecifiedCount(1, detachState);
165
166 LOGI("test %d threads", REQUIRED_THREAD_COUNT);
167 TestSpecifiedCount(REQUIRED_THREAD_COUNT, detachState);
168 }
169
TestHcThread(void)170 void TestHcThread(void)
171 {
172 #if TEST_PTHREAD_CREATE_DETACHED
173 LOGI("test state PTHREAD_CREATE_DETACHED");
174 TestState(PTHREAD_CREATE_DETACHED);
175 #else // TEST_PTHREAD_CREATE_DETACHED
176 LOGI("test state PTHREAD_CREATE_JOINABLE");
177 TestState(PTHREAD_CREATE_JOINABLE);
178 #endif // TEST_PTHREAD_CREATE_DETACHED
179 }
180
181 #ifdef __cplusplus
182 }
183 #endif
184