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 <sys/eventfd.h>
20 #include <sys/epoll.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <cstdint>
24 #include "c/executor_task.h"
25 #include "ffrt_inner.h"
26 #include "eu/cpu_monitor.h"
27 #include "sched/scheduler.h"
28 #include "../common.h"
29 
30 using namespace std;
31 using namespace ffrt;
32 using namespace testing;
33 #ifdef HWTEST_TESTING_EXT_ENABLE
34 using namespace testing::ext;
35 #endif
36 #ifdef APP_USE_ARM
37 #define SIZEOF_BYTES sizeof(uint32_t)
38 #else
39 #define SIZEOF_BYTES sizeof(uint64_t)
40 #endif
41 class CoroutineTest : public testing::Test {
42 protected:
SetUpTestCase()43     static void SetUpTestCase()
44     {
45     }
46 
TearDownTestCase()47     static void TearDownTestCase()
48     {
49     }
50 
SetUp()51     virtual void SetUp()
52     {
53     }
54 
TearDown()55     virtual void TearDown()
56     {
57     }
58 };
59 constexpr int BLOCKED_COUNT = 3;
60 
61 typedef struct {
62     int count;
63     std::mutex lock;
64 } StacklessCoroutine1;
65 
stackless_coroutine(void* co)66 ffrt_coroutine_ret_t stackless_coroutine(void* co)
67 {
68     StacklessCoroutine1* stacklesscoroutine = reinterpret_cast<StacklessCoroutine1*>(co);
69     std::lock_guard lg(stacklesscoroutine->lock);
70     printf("stacklesscoroutine %d\n", stacklesscoroutine->count);
71     stacklesscoroutine->count++;
72     if (stacklesscoroutine->count < BLOCKED_COUNT) {
73         ffrt_wake_coroutine(ffrt_get_current_task());
74         return ffrt_coroutine_pending;
75     } else if (stacklesscoroutine->count == BLOCKED_COUNT) {
76         ffrt_wake_coroutine(ffrt_get_current_task());
77         return ffrt_coroutine_pending;
78     } else {
79         return ffrt_coroutine_ready;
80     }
81     return ffrt_coroutine_pending;
82 }
83 
exec_stackless_coroutine(void *co)84 ffrt_coroutine_ret_t exec_stackless_coroutine(void *co)
85 {
86     return stackless_coroutine(co);
87 }
88 
destroy_stackless_coroutine(void *co)89 void destroy_stackless_coroutine(void *co)
90 {
91 }
92 
HWTEST_F(CoroutineTest, coroutine_submit_succ, TestSize.Level1)93 HWTEST_F(CoroutineTest, coroutine_submit_succ, TestSize.Level1)
94 {
95     // coroutine_submit_004
96     StacklessCoroutine1 co1 = {0};
97     StacklessCoroutine1 co2 = {0};
98     ffrt_task_attr_t attr;
99     ffrt_task_attr_init(&attr);
100     ffrt_submit_coroutine((void *)&co1, exec_stackless_coroutine, destroy_stackless_coroutine, NULL, NULL, &attr);
101     ffrt_submit_coroutine((void *)&co2, exec_stackless_coroutine, destroy_stackless_coroutine, NULL, NULL, &attr);
102     // ffrt_poller_wakeup_001
103     ffrt_poller_wakeup(ffrt_qos_default);
104     usleep(100000);
105     EXPECT_EQ(co1.count, 4);
106     EXPECT_EQ(co2.count, 4);
107 }
108 
HWTEST_F(CoroutineTest, coroutine_submit_fail, TestSize.Level1)109 HWTEST_F(CoroutineTest, coroutine_submit_fail, TestSize.Level1)
110 {
111     // get_task_001
112     EXPECT_EQ(ffrt_get_current_task(), nullptr);
113 
114     ffrt_task_attr_t attr;
115     ffrt_task_attr_init(&attr);
116 
117     // coroutine_submit_001
118     ffrt_submit_coroutine(nullptr, nullptr, nullptr, NULL, NULL, &attr);
119     ffrt_submit_coroutine(nullptr, nullptr, nullptr, NULL, NULL, &attr);
120 }
121 
122 struct TestData {
123     int fd;
124     uint64_t expected;
125 };
126 
testCallBack(void* token, uint32_t event)127 static void testCallBack(void* token, uint32_t event)
128 {
129     struct TestData* testData = reinterpret_cast<TestData*>(token);
130     uint64_t value = 0;
131     ssize_t n = read(testData->fd, &value, sizeof(uint64_t));
132     EXPECT_EQ(n, sizeof(value));
133     EXPECT_EQ(value, testData->expected);
134     printf("cb done\n");
135 }
136 
HWTEST_F(CoroutineTest, ffrt_epoll_ctl_add_del, TestSize.Level1)137 HWTEST_F(CoroutineTest, ffrt_epoll_ctl_add_del, TestSize.Level1)
138 {
139     uint64_t expected = 0xabacadae;
140     int testFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
141 
142     ffrt::submit([&]() {
143         ssize_t n = write(testFd, &expected, sizeof(uint64_t));
144         EXPECT_EQ(sizeof(n), SIZEOF_BYTES);
145         }, {}, {});
146 
147     struct TestData testData {.fd = testFd, .expected = expected};
148     // poller_register_001
149     ffrt_epoll_ctl(ffrt_qos_default, EPOLL_CTL_ADD, testFd, EPOLLIN, reinterpret_cast<void*>(&testData), testCallBack);
150 
151     usleep(100);
152 
153     // poller_deregister_001
154     ffrt_epoll_ctl(ffrt_qos_default, EPOLL_CTL_DEL, testFd, 0, nullptr, nullptr);
155     close(testFd);
156 }
157