• 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 "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