1c29fa5a6Sopenharmony_ci/*
2c29fa5a6Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License.
5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at
6c29fa5a6Sopenharmony_ci *
7c29fa5a6Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8c29fa5a6Sopenharmony_ci *
9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and
13c29fa5a6Sopenharmony_ci * limitations under the License.
14c29fa5a6Sopenharmony_ci */
15c29fa5a6Sopenharmony_ci
16c29fa5a6Sopenharmony_ci#include "delegate_tasks.h"
17c29fa5a6Sopenharmony_ci
18c29fa5a6Sopenharmony_ci#include <fcntl.h>
19c29fa5a6Sopenharmony_ci#include <sys/syscall.h>
20c29fa5a6Sopenharmony_ci#include <unistd.h>
21c29fa5a6Sopenharmony_ci
22c29fa5a6Sopenharmony_ci#include "error_multimodal.h"
23c29fa5a6Sopenharmony_ci#include "util.h"
24c29fa5a6Sopenharmony_ci
25c29fa5a6Sopenharmony_ci#undef MMI_LOG_DOMAIN
26c29fa5a6Sopenharmony_ci#define MMI_LOG_DOMAIN MMI_LOG_SERVER
27c29fa5a6Sopenharmony_ci#undef MMI_LOG_TAG
28c29fa5a6Sopenharmony_ci#define MMI_LOG_TAG "DelegateTasks"
29c29fa5a6Sopenharmony_ci
30c29fa5a6Sopenharmony_cinamespace OHOS {
31c29fa5a6Sopenharmony_cinamespace MMI {
32c29fa5a6Sopenharmony_civoid DelegateTasks::Task::ProcessTask()
33c29fa5a6Sopenharmony_ci{
34c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
35c29fa5a6Sopenharmony_ci    if (hasWaited_) {
36c29fa5a6Sopenharmony_ci        MMI_HILOGE("Expired tasks will be discarded. id:%{public}d", id_);
37c29fa5a6Sopenharmony_ci        return;
38c29fa5a6Sopenharmony_ci    }
39c29fa5a6Sopenharmony_ci    int32_t ret = fun_();
40c29fa5a6Sopenharmony_ci    std::string taskType = ((promise_ == nullptr) ? "Async" : "Sync");
41c29fa5a6Sopenharmony_ci    MMI_HILOGD("Process taskType:%{public}s, taskId:%{public}d, ret:%{public}d", taskType.c_str(), id_, ret);
42c29fa5a6Sopenharmony_ci    if (!hasWaited_ && promise_ != nullptr) {
43c29fa5a6Sopenharmony_ci        promise_->set_value(ret);
44c29fa5a6Sopenharmony_ci    }
45c29fa5a6Sopenharmony_ci}
46c29fa5a6Sopenharmony_ci
47c29fa5a6Sopenharmony_ciDelegateTasks::~DelegateTasks()
48c29fa5a6Sopenharmony_ci{
49c29fa5a6Sopenharmony_ci    if (fds_[0] >= 0) {
50c29fa5a6Sopenharmony_ci        close(fds_[0]);
51c29fa5a6Sopenharmony_ci        fds_[0] = -1;
52c29fa5a6Sopenharmony_ci    }
53c29fa5a6Sopenharmony_ci    if (fds_[1] >= 0) {
54c29fa5a6Sopenharmony_ci        close(fds_[1]);
55c29fa5a6Sopenharmony_ci        fds_[1] = -1;
56c29fa5a6Sopenharmony_ci    }
57c29fa5a6Sopenharmony_ci}
58c29fa5a6Sopenharmony_ci
59c29fa5a6Sopenharmony_cibool DelegateTasks::Init()
60c29fa5a6Sopenharmony_ci{
61c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
62c29fa5a6Sopenharmony_ci    if (pipe(fds_) == -1) {
63c29fa5a6Sopenharmony_ci        MMI_HILOGE("The pipe create failed, errno:%{public}d", errno);
64c29fa5a6Sopenharmony_ci        return false;
65c29fa5a6Sopenharmony_ci    }
66c29fa5a6Sopenharmony_ci    if (fcntl(fds_[0], F_SETFL, O_NONBLOCK) == -1) {
67c29fa5a6Sopenharmony_ci        MMI_HILOGE("The fcntl read failed, errno:%{public}d", errno);
68c29fa5a6Sopenharmony_ci        close(fds_[0]);
69c29fa5a6Sopenharmony_ci        return false;
70c29fa5a6Sopenharmony_ci    }
71c29fa5a6Sopenharmony_ci    if (fcntl(fds_[1], F_SETFL, O_NONBLOCK) == -1) {
72c29fa5a6Sopenharmony_ci        MMI_HILOGE("The fcntl write failed, errno:%{public}d", errno);
73c29fa5a6Sopenharmony_ci        close(fds_[1]);
74c29fa5a6Sopenharmony_ci        return false;
75c29fa5a6Sopenharmony_ci    }
76c29fa5a6Sopenharmony_ci    return true;
77c29fa5a6Sopenharmony_ci}
78c29fa5a6Sopenharmony_ci
79c29fa5a6Sopenharmony_civoid DelegateTasks::ProcessTasks()
80c29fa5a6Sopenharmony_ci{
81c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
82c29fa5a6Sopenharmony_ci    std::vector<TaskPtr> tasks;
83c29fa5a6Sopenharmony_ci    PopPendingTaskList(tasks);
84c29fa5a6Sopenharmony_ci    for (const auto &it : tasks) {
85c29fa5a6Sopenharmony_ci        it->ProcessTask();
86c29fa5a6Sopenharmony_ci    }
87c29fa5a6Sopenharmony_ci}
88c29fa5a6Sopenharmony_ci
89c29fa5a6Sopenharmony_ciint32_t DelegateTasks::PostSyncTask(DTaskCallback callback)
90c29fa5a6Sopenharmony_ci{
91c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
92c29fa5a6Sopenharmony_ci    CHKPR(callback, ERROR_NULL_POINTER);
93c29fa5a6Sopenharmony_ci    if (IsCallFromWorkerThread()) {
94c29fa5a6Sopenharmony_ci        return callback();
95c29fa5a6Sopenharmony_ci    }
96c29fa5a6Sopenharmony_ci    Promise promise;
97c29fa5a6Sopenharmony_ci    Future future = promise.get_future();
98c29fa5a6Sopenharmony_ci    auto task = PostTask(callback, &promise);
99c29fa5a6Sopenharmony_ci    CHKPR(task, ETASKS_POST_SYNCTASK_FAIL);
100c29fa5a6Sopenharmony_ci
101c29fa5a6Sopenharmony_ci    static constexpr int32_t timeout = 3000;
102c29fa5a6Sopenharmony_ci    std::chrono::milliseconds span(timeout);
103c29fa5a6Sopenharmony_ci    auto res = future.wait_for(span);
104c29fa5a6Sopenharmony_ci    task->SetWaited();
105c29fa5a6Sopenharmony_ci    if (res == std::future_status::timeout) {
106c29fa5a6Sopenharmony_ci        MMI_HILOGE("Task timeout");
107c29fa5a6Sopenharmony_ci        return ETASKS_WAIT_TIMEOUT;
108c29fa5a6Sopenharmony_ci    } else if (res == std::future_status::deferred) {
109c29fa5a6Sopenharmony_ci        MMI_HILOGE("Task deferred");
110c29fa5a6Sopenharmony_ci        return ETASKS_WAIT_DEFERRED;
111c29fa5a6Sopenharmony_ci    }
112c29fa5a6Sopenharmony_ci    return future.get();
113c29fa5a6Sopenharmony_ci}
114c29fa5a6Sopenharmony_ci
115c29fa5a6Sopenharmony_ciint32_t DelegateTasks::PostAsyncTask(DTaskCallback callback)
116c29fa5a6Sopenharmony_ci{
117c29fa5a6Sopenharmony_ci    CHKPR(callback, ERROR_NULL_POINTER);
118c29fa5a6Sopenharmony_ci    if (IsCallFromWorkerThread()) {
119c29fa5a6Sopenharmony_ci        return callback();
120c29fa5a6Sopenharmony_ci    }
121c29fa5a6Sopenharmony_ci    CHKPR(PostTask(callback), ETASKS_POST_ASYNCTASK_FAIL);
122c29fa5a6Sopenharmony_ci    return RET_OK;
123c29fa5a6Sopenharmony_ci}
124c29fa5a6Sopenharmony_ci
125c29fa5a6Sopenharmony_civoid DelegateTasks::PopPendingTaskList(std::vector<TaskPtr> &tasks)
126c29fa5a6Sopenharmony_ci{
127c29fa5a6Sopenharmony_ci    std::lock_guard<std::mutex> guard(mux_);
128c29fa5a6Sopenharmony_ci    static constexpr int32_t onceProcessTaskLimit = 10;
129c29fa5a6Sopenharmony_ci    for (int32_t count = 0; count < onceProcessTaskLimit; count++) {
130c29fa5a6Sopenharmony_ci        if (tasks_.empty()) {
131c29fa5a6Sopenharmony_ci            break;
132c29fa5a6Sopenharmony_ci        }
133c29fa5a6Sopenharmony_ci        auto task = tasks_.front();
134c29fa5a6Sopenharmony_ci        CHKPB(task);
135c29fa5a6Sopenharmony_ci        RecoveryId(task->GetId());
136c29fa5a6Sopenharmony_ci        tasks.push_back(task->GetSharedPtr());
137c29fa5a6Sopenharmony_ci        tasks_.pop();
138c29fa5a6Sopenharmony_ci    }
139c29fa5a6Sopenharmony_ci}
140c29fa5a6Sopenharmony_ci
141c29fa5a6Sopenharmony_ciDelegateTasks::TaskPtr DelegateTasks::PostTask(DTaskCallback callback, Promise *promise)
142c29fa5a6Sopenharmony_ci{
143c29fa5a6Sopenharmony_ci    if (IsCallFromWorkerThread()) {
144c29fa5a6Sopenharmony_ci        MMI_HILOGE("This interface cannot be called from a worker thread");
145c29fa5a6Sopenharmony_ci        return nullptr;
146c29fa5a6Sopenharmony_ci    }
147c29fa5a6Sopenharmony_ci    std::lock_guard<std::mutex> guard(mux_);
148c29fa5a6Sopenharmony_ci    MMI_HILOGD("tasks_ size:%{public}d", static_cast<int32_t>(tasks_.size()));
149c29fa5a6Sopenharmony_ci    static constexpr int32_t maxTasksLimit = 1000;
150c29fa5a6Sopenharmony_ci    auto tsize = tasks_.size();
151c29fa5a6Sopenharmony_ci    if (tsize > maxTasksLimit) {
152c29fa5a6Sopenharmony_ci        MMI_HILOGE("The task queue is full. size:%{public}zu, maxTasksLimit:%{public}d", tsize, maxTasksLimit);
153c29fa5a6Sopenharmony_ci        return nullptr;
154c29fa5a6Sopenharmony_ci    }
155c29fa5a6Sopenharmony_ci    int32_t id = GenerateId();
156c29fa5a6Sopenharmony_ci    TaskData data = { GetThisThreadId(), id };
157c29fa5a6Sopenharmony_ci    auto res = write(fds_[1], &data, sizeof(data));
158c29fa5a6Sopenharmony_ci    if (res == -1) {
159c29fa5a6Sopenharmony_ci        RecoveryId(id);
160c29fa5a6Sopenharmony_ci        MMI_HILOGE("Pipe write failed, errno:%{public}d", errno);
161c29fa5a6Sopenharmony_ci        return nullptr;
162c29fa5a6Sopenharmony_ci    }
163c29fa5a6Sopenharmony_ci    TaskPtr task = std::make_shared<Task>(id, callback, promise);
164c29fa5a6Sopenharmony_ci    tasks_.push(task);
165c29fa5a6Sopenharmony_ci    std::string taskType = ((promise == nullptr) ? "Async" : "Sync");
166c29fa5a6Sopenharmony_ci    MMI_HILOGD("Post taskType:%{public}s", taskType.c_str());
167c29fa5a6Sopenharmony_ci    return task->GetSharedPtr();
168c29fa5a6Sopenharmony_ci}
169c29fa5a6Sopenharmony_ci} // namespace MMI
170c29fa5a6Sopenharmony_ci} // namespace OHOS