1 /*
2 * Copyright (c) 2023 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<thread>
17 #include<chrono>
18 #include<gtest/gtest.h>
19 #include"ffrt.h"
20
21 using namespace std;
22 using namespace ffrt;
23 using namespace testing;
24
25 class CoroutineTest : public testing::Test {
26 protected:
SetUpTestCase()27 static void SetUpTestCase()
28 {
29 }
30
TearDownTestCase()31 static void TearDownTestCase()
32 {
33 }
34
SetUp()35 virtual void SetUp()
36 {
37 }
38
TeadDown()39 virtual void TeadDown()
40 {
41 }
42 };
43
44 const int BLOCKED_COUNT = 3;
45
46 typedef struct {
47 int count;
48 }StacklessCoroutine1;
49
stackless_coroutine(void * co)50 ffrt_coroutine_ret_t stackless_coroutine(void *co)
51 {
52 ((StacklessCoroutine1*)(co))->count++;
53
54 if (((StacklessCoroutine1*)(co))->count < BLOCKED_COUNT) {
55 ffrt_wake_coroutine(ffrt_task_get());
56 return ffrt_coroutine_pending;
57 } else if (((StacklessCoroutine1*)(co))->count == BLOCKED_COUNT) {
58 ffrt_wake_coroutine(ffrt_task_get());
59 return ffrt_coroutine_pending;
60 } else {
61 ffrt_wake_coroutine(ffrt_task_get());
62 return ffrt_coroutine_ready;
63 }
64 return ffrt_coroutine_pending;
65 }
66
exec_stackless_coroutine(void * co)67 ffrt_coroutine_ret_t exec_stackless_coroutine(void *co)
68 {
69 return stackless_coroutine(co);
70 }
71
destroy_stackless_coroutine(void * co)72 void destroy_stackless_coroutine(void *co)
73 {
74 }
75
TEST_F(CoroutineTest,coroutine_submit_succ)76 TEST_F(CoroutineTest, coroutine_submit_succ)
77 {
78 StacklessCoroutine1 co1 = {0};
79 StacklessCoroutine1 co2 = {0};
80 ffrt_task_attr_t attr;
81 ffrt_task_attr_init(&attr);
82 ffrt_task_attr_set_name(&attr, "stackless_coroutine");
83 ffrt_task_attr_set_coroutine_type(&attr, ffrt_coroutine_stackless);
84 int coroutine_type_ = ffrt_task_attr_get_coroutine_type(&attr);
85 ffrt_submit_coroutine((void *)co1, exec_stackless_coroutine, destroy_stackless_coroutine, NULL, NULL, &attr);
86 ffrt_task_handle_t task1 = ffrt_submit_h_coroutine((void *)co2, exec_stackless_coroutine,
87 destroy_stackless_coroutine, NULL, NULL, &attr);
88 ffrt_wait();
89 ffrt_task_handle_destroy(task1);
90 EXPECT_EQ(coroutine_type_, 0);
91 EXPECT_EQ(co1.count, 4);
92 EXPECT_EQ(co2.count, 4);
93 }
94
TEST_F(CoroutineTest,coroutine_submit_fail)95 TEST_F(CoroutineTest, coroutine_submit_fail)
96 {
97 ffrt_task_get();
98 ffrt_task_handle_destroy(nullptr);
99
100 StacklessCoroutine1 co1 = {0};
101 StacklessCoroutine1 co2 = {0};
102 StacklessCoroutine1 co3 = {0};
103 StacklessCoroutine1 co4 = {0};
104 StacklessCoroutine1 co5 = {0};
105 ffrt_task_attr_t attr;
106 ffrt_task_attr_init(&attr);
107 ffrt_task_attr_set_name(&attr, "stackless_coroutine");
108 ffrt_task_attr_set_coroutine_type(&attr, ffrt_coroutine_stackless);
109
110 ffrt_submit_coroutine(nullptr, nullptr, nullptr, NULL, NULL, &attr);
111 ffrt_task_handle_t task1 = ffrt_submit_h_coroutine(nullptr, nullptr, nullptr, NULL, NULL, &attr);
112 ffrt_task_handle_destroy(task1);
113
114 ffrt_submit_coroutine((void *)&co1, nullptr, nullptr, NULL, NULL, &attr);
115 ffrt_task_handle_t task2 = ffrt_submit_h_coroutine((void *)&co2, nullptr, nullptr, NULL, NULL, &attr);
116 ffrt_task_handle_destroy(task2);
117
118 ffrt_submit_coroutine((void *)&co3, exec_stackless_coroutine, nullptr, NULL, NULL, &attr);
119 ffrt_task_handle_t task3 = ffrt_submit_h_coroutine((void *)&co4, exec_stackless_coroutine,
120 nullptr, NULL, NULL, &attr);
121 ffrt_task_handle_destroy(task3);
122
123 ffrt_task_attr_t attr_stackfull;
124 ffrt_task_attr_init(&attr_stackfull);
125 ffrt_task_attr_set_name(&attr_stackfull, "stackfull_coroutine");
126 ffrt_task_attr_set_coroutine_type(&attr_stackfull, ffrt_coroutine_stackfull);
127 ffrt_submit_coroutine((void *)&co5, nullptr, nullptr, NULL, NULL, &attr_stackfull);
128 ffrt_task_handle_t task_stackfull = ffrt_submit_h_coroutine((void *)&co6, nullptr, nullptr,
129 NULL, NULL, &attr_stackfull);
130 ffrt_task_attr_destroy(task_stackfull);
131 }
132
133 StacklessCoroutine1 g_col = {0};
134 struct Waker {
135 void *phandle;
136 void *handle;
137 } waker;
138
wake_stackless_coroutine(void * arg)139 void wake_stackless_coroutine(void *arg)
140 {
141 ffrt_wake_coroutine(((Waker *)arg)->phandle);
142 }
143
destroy_wake_of_stackless_coroutine(void * arg)144 void destroy_wake_of_stackless_coroutine(void *arg)
145 {
146 ffrt_task_handle_destroy(((Waker *)arg)->handle);
147 }
148
maintask_stackless_coroutine(void * co)149 ffrt_coroutine_ret_t maintask_stackless_coroutine(void *co)
150 {
151 ((StacklessCoroutine1*)(co))->count++;
152
153 if (((StacklessCoroutine1*)(co))->count < BLOCKED_COUNT) {
154 if (((StacklessCoroutine1*)(co))->count == 1) {
155 ffrt_task_attr_t attr;
156 ffrt_task_attr_init(&attr);
157 ffrt_task_attr_set_name(&attr, "stackless_coroutine");
158 ffrt_task_attr_set_coroutine_type(&attr, ffrt_coroutine_stackless);
159 ffrt_set_wake_flag(true);
160 ffrt_task_handle_t h = ffrt_submit_h_coroutine((void *)&g_col, exec_stackless_coroutine,
161 destroy_stackless_coroutine, NULL, NULL, &attr);
162 waker.phandle = ffrt_task_get();
163 waker.handle = h;
164 ffrt_wake_by_handle(&waker, wake_stackless_coroutine, destroy_wake_of_stackless_coroutine, h);
165 ffrt_wake_coroutine(ffrt_task_get());
166 return ffrt_coroutine_pending;
167 }
168 ffrt_wake_coroutine(ffrt_task_get());
169 return ffrt_coroutine_pending;
170 } else if (((StacklessCoroutine1*)(co))->count == BLOCKED_COUNT) {
171 ffrt_wake_coroutine(ffrt_task_get());
172 return ffrt_coroutine_pending;
173 } else {
174 ffrt_wake_coroutine(ffrt_task_get());
175 return ffrt_coroutine_ready;
176 }
177 return ffrt_coroutine_pending;
178 }
179
maintask_exec_stackless_coroutine(void * co)180 ffrt_coroutine_ret_t maintask_exec_stackless_coroutine(void *co)
181 {
182 return maintask_stackless_coroutine(co);
183 }
184
maintask_destroy_stackless_coroutine(void * co)185 void maintask_destroy_stackless_coroutine(void *co)
186 {
187 }
188
TEST_F(CoroutineTest,coroutine_wake_by_handle_succ)189 TEST_F(CoroutineTest, coroutine_wake_by_handle_succ)
190 {
191 StacklessCoroutine1 co1 = {0};
192 ffrt_task_attr_t maintask_attr;
193 ffrt_task_attr_init(&maintask_attrr);
194 ffrt_task_attr_set_name(&maintask_attr, "stackless_coroutine_maintask");
195 ffrt_task_attr_set_coroutine_type(&maintask_attr, ffrt_coroutine_stackless);
196 ffrt_task_handle_t maintask = ffrt_submit_h_coroutine((void *)&co1, maintask_exec_stackless_coroutine,
197 maintask_destroy_stackless_coroutine, NULL, NULL, &maintask_attr);
198 ffrt_wait();
199 ffrt_task_handle_destroy(maintask);
200 EXPECT_EQ(co1.count, 4);
201 }
202
maintask_stackless_coroutine_fail(void * co)203 ffrt_coroutine_ret_t maintask_stackless_coroutine_fail(void *co)
204 {
205 ((StacklessCoroutine1*)(co))->count++;
206
207 if (((StacklessCoroutine1*)(co))->count < BLOCKED_COUNT) {
208 if (((StacklessCoroutine1*)(co))->count == 1) {
209 ffrt_task_attr_t attr;
210 ffrt_task_attr_init(&attr);
211 ffrt_task_attr_set_name(&attr, "stackless_coroutine");
212 ffrt_task_attr_set_coroutine_type(&attr, ffrt_coroutine_stackless);
213 ffrt_task_handle_t h = ffrt_submit_h_coroutine((void *)&g_col, exec_stackless_coroutine,
214 destroy_stackless_coroutine, NULL, NULL, &attr);
215 waker.phandle = ffrt_task_get();
216 waker.handle = h;
217
218 ffrt_wake_by_handle(nullptr, nullptr, nullptr, nullptr);
219 ffrt_wake_by_handle(&waker, nullptr, nullptr, h);
220 ffrt_wake_by_handle(nullptr, nullptr, nullptr, nullptr);
221 ffrt_wake_by_handle(&waker, nullptr, nullptr, h);
222 ffrt_wake_by_handle(&waker, wake_stackless_coroutine, nullptr, h);
223 ffrt_wake_by_handle(&waker, wake_stackless_coroutine, destroy_wake_of_stackless_coroutine, h);
224 ffrt_wake_coroutine(ffrt_task_get());
225 return ffrt_coroutine_pending;
226 }
227 ffrt_wake_coroutine(ffrt_task_get());
228 return ffrt_coroutine_pending;
229 } else if (((StacklessCoroutine1*)(co))->count == BLOCKED_COUNT) {
230 ffrt_wake_coroutine(ffrt_task_get());
231 return ffrt_coroutine_pending;
232 } else {
233 ffrt_wake_coroutine(ffrt_task_get());
234 return ffrt_coroutine_ready;
235 }
236 return ffrt_coroutine_pending;
237 }
238
maintask_exec_stackless_coroutine_fail(void * co)239 ffrt_coroutine_ret_t maintask_exec_stackless_coroutine_fail(void *co)
240 {
241 return maintask_stackless_coroutine_fail(co);
242 }
243
maintask_destroy_stackless_coroutine_fail(void * co)244 void maintask_destroy_stackless_coroutine_fail(void *co)
245 {
246 }
247
TEST_F(CoroutineTest,coroutine_wake_by_handle_fail)248 TEST_F(CoroutineTest, coroutine_wake_by_handle_fail)
249 {
250 StacklessCoroutine1 co1 = {0};
251 ffrt_task_attr_t maintask_attr;
252 ffrt_task_attr_init(&maintask_attrr);
253 ffrt_task_attr_set_name(&maintask_attr, "stackless_coroutine_maintask");
254 ffrt_task_attr_set_coroutine_type(&maintask_attr, ffrt_coroutine_stackless);
255 ffrt_task_handle_t maintask = ffrt_submit_h_coroutine((void *)&co1, maintask_exec_stackless_coroutine_fail,
256 maintask_destroy_stackless_coroutine_fail, NULL, NULL, &maintask_attr);
257 ffrt_wait();
258 ffrt_task_handle_destroy(maintask);
259 }
260
TEST_F(CoroutineTest,set_get_coroutine_type_fail)261 TEST_F(CoroutineTest, set_get_coroutine_type_fail)
262 {
263 ffrt_task_attr_t attr;
264 ffrt_task_attr_init(&attr);
265 ffrt_task_attr_set_name(&attr, "stackless_coroutine");
266 ffrt_task_attr_set_coroutine_type(nullptr, ffrt_coroutine_stackless);
267 ffrt_task_attr_get_coroutine_type(nullptr);
268 }