1484543d1Sopenharmony_ci/*
2484543d1Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3484543d1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4484543d1Sopenharmony_ci * you may not use this file except in compliance with the License.
5484543d1Sopenharmony_ci * You may obtain a copy of the License at
6484543d1Sopenharmony_ci *
7484543d1Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8484543d1Sopenharmony_ci *
9484543d1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10484543d1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11484543d1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12484543d1Sopenharmony_ci * See the License for the specific language governing permissions and
13484543d1Sopenharmony_ci * limitations under the License.
14484543d1Sopenharmony_ci */
15484543d1Sopenharmony_ci
16484543d1Sopenharmony_ci#ifndef __WAITQUEUE_H__
17484543d1Sopenharmony_ci#define __WAITQUEUE_H__
18484543d1Sopenharmony_ci#include "sync.h"
19484543d1Sopenharmony_ci#include "cpp/mutex.h"
20484543d1Sopenharmony_ci#include "sched/execute_ctx.h"
21484543d1Sopenharmony_ci#include "util/IntrusiveList.h"
22484543d1Sopenharmony_ci#include "sync/mutex_private.h"
23484543d1Sopenharmony_ci#include "dfx/log/ffrt_log_api.h"
24484543d1Sopenharmony_ci
25484543d1Sopenharmony_cinamespace ffrt {
26484543d1Sopenharmony_ciclass CPUEUTask;
27484543d1Sopenharmony_cistruct TaskWithNode;
28484543d1Sopenharmony_ciusing TaskListNode = ListNode;
29484543d1Sopenharmony_ciusing TaskList = List<TaskWithNode, TaskListNode>;
30484543d1Sopenharmony_ci
31484543d1Sopenharmony_cistruct TaskTimeOutStatus {
32484543d1Sopenharmony_ci    explicit TaskTimeOutStatus(TaskTimeoutState state) : status(state)
33484543d1Sopenharmony_ci    {
34484543d1Sopenharmony_ci    }
35484543d1Sopenharmony_ci    TaskTimeoutState status;
36484543d1Sopenharmony_ci    std::mutex lock;
37484543d1Sopenharmony_ci};
38484543d1Sopenharmony_ci
39484543d1Sopenharmony_cienum class TimeoutState {
40484543d1Sopenharmony_ci    IDLE,
41484543d1Sopenharmony_ci    WAITING,
42484543d1Sopenharmony_ci    TIMEOUTING,
43484543d1Sopenharmony_ci    DONE,
44484543d1Sopenharmony_ci};
45484543d1Sopenharmony_ci
46484543d1Sopenharmony_cistruct TimeoutStatus {
47484543d1Sopenharmony_ci    explicit TimeoutStatus(TimeoutState state) : status(state)
48484543d1Sopenharmony_ci    {
49484543d1Sopenharmony_ci    }
50484543d1Sopenharmony_ci    TimeoutState status;
51484543d1Sopenharmony_ci    mutex lock;
52484543d1Sopenharmony_ci};
53484543d1Sopenharmony_ci
54484543d1Sopenharmony_cistruct TaskWithNode : public TaskListNode {
55484543d1Sopenharmony_ci    TaskWithNode();
56484543d1Sopenharmony_ci    CPUEUTask* task = nullptr;
57484543d1Sopenharmony_ci    std::mutex lk;
58484543d1Sopenharmony_ci    std::condition_variable cv;
59484543d1Sopenharmony_ci};
60484543d1Sopenharmony_ci
61484543d1Sopenharmony_ciclass WaitQueue {
62484543d1Sopenharmony_ciprivate:
63484543d1Sopenharmony_ci    spin_mutex wqlock;
64484543d1Sopenharmony_ci    WaitUntilEntry* whead;
65484543d1Sopenharmony_ci
66484543d1Sopenharmony_cipublic:
67484543d1Sopenharmony_ci    using TimePoint = std::chrono::steady_clock::time_point;
68484543d1Sopenharmony_ci    void SuspendAndWait(mutexPrivate* lk);
69484543d1Sopenharmony_ci    bool SuspendAndWaitUntil(mutexPrivate* lk, const TimePoint& tp) noexcept;
70484543d1Sopenharmony_ci    void NotifyAll() noexcept { Notify(false); }
71484543d1Sopenharmony_ci    void NotifyOne() noexcept { Notify(true); }
72484543d1Sopenharmony_ci
73484543d1Sopenharmony_ci    WaitQueue()
74484543d1Sopenharmony_ci    {
75484543d1Sopenharmony_ci        whead = new WaitUntilEntry();
76484543d1Sopenharmony_ci        whead->next = whead;
77484543d1Sopenharmony_ci        whead->prev = whead;
78484543d1Sopenharmony_ci    }
79484543d1Sopenharmony_ci    WaitQueue(WaitQueue const&) = delete;
80484543d1Sopenharmony_ci    void operator=(WaitQueue const&) = delete;
81484543d1Sopenharmony_ci
82484543d1Sopenharmony_ci    ~WaitQueue()
83484543d1Sopenharmony_ci    {
84484543d1Sopenharmony_ci        wqlock.lock();
85484543d1Sopenharmony_ci        ReleaseAll();
86484543d1Sopenharmony_ci        delete whead;
87484543d1Sopenharmony_ci        whead = nullptr;
88484543d1Sopenharmony_ci        wqlock.unlock();
89484543d1Sopenharmony_ci    }
90484543d1Sopenharmony_ci
91484543d1Sopenharmony_ciprivate:
92484543d1Sopenharmony_ci    bool WeNotifyProc(WaitUntilEntry* we);
93484543d1Sopenharmony_ci    void ThreadWait(WaitUntilEntry* wn, mutexPrivate* lk, bool legacyMode, CPUEUTask* task);
94484543d1Sopenharmony_ci    bool ThreadWaitUntil(WaitUntilEntry* wn, mutexPrivate* lk, const TimePoint& tp, bool legacyMode, CPUEUTask* task);
95484543d1Sopenharmony_ci    void Notify(bool one) noexcept;
96484543d1Sopenharmony_ci
97484543d1Sopenharmony_ci    inline bool empty() const
98484543d1Sopenharmony_ci    {
99484543d1Sopenharmony_ci        if (whead == nullptr) {
100484543d1Sopenharmony_ci            return true;
101484543d1Sopenharmony_ci        }
102484543d1Sopenharmony_ci        return (whead->next == whead);
103484543d1Sopenharmony_ci    }
104484543d1Sopenharmony_ci
105484543d1Sopenharmony_ci    void ReleaseAll()
106484543d1Sopenharmony_ci    {
107484543d1Sopenharmony_ci        while (!empty()) {
108484543d1Sopenharmony_ci            FFRT_LOGE("There are still tasks in cv that have not been awakened");
109484543d1Sopenharmony_ci            WaitUntilEntry *wue = pop_front();
110484543d1Sopenharmony_ci            (void)WeNotifyProc(wue);
111484543d1Sopenharmony_ci        }
112484543d1Sopenharmony_ci    }
113484543d1Sopenharmony_ci
114484543d1Sopenharmony_ci    inline void push_back(WaitUntilEntry* we)
115484543d1Sopenharmony_ci    {
116484543d1Sopenharmony_ci        if ((we == nullptr) || (whead == nullptr) || (whead->prev == nullptr)) {
117484543d1Sopenharmony_ci            FFRT_LOGE("we or whead or whead->prev is nullptr");
118484543d1Sopenharmony_ci            return;
119484543d1Sopenharmony_ci        }
120484543d1Sopenharmony_ci        we->next = whead;
121484543d1Sopenharmony_ci        we->prev = whead->prev;
122484543d1Sopenharmony_ci        whead->prev->next = we;
123484543d1Sopenharmony_ci        whead->prev = we;
124484543d1Sopenharmony_ci    }
125484543d1Sopenharmony_ci
126484543d1Sopenharmony_ci    inline WaitUntilEntry* pop_front()
127484543d1Sopenharmony_ci    {
128484543d1Sopenharmony_ci        if ((whead->next == nullptr) || (whead->next->next == nullptr)) {
129484543d1Sopenharmony_ci            FFRT_LOGE("whead->next or whead->next->next is nullptr");
130484543d1Sopenharmony_ci            return nullptr;
131484543d1Sopenharmony_ci        }
132484543d1Sopenharmony_ci        WaitEntry *we = whead->next;
133484543d1Sopenharmony_ci        whead->next = we->next;
134484543d1Sopenharmony_ci        we->next->prev = whead;
135484543d1Sopenharmony_ci        we->next = nullptr;
136484543d1Sopenharmony_ci        we->prev = nullptr;
137484543d1Sopenharmony_ci        return static_cast<WaitUntilEntry*>(we);
138484543d1Sopenharmony_ci    }
139484543d1Sopenharmony_ci
140484543d1Sopenharmony_ci    inline void remove(WaitUntilEntry* we)
141484543d1Sopenharmony_ci    {
142484543d1Sopenharmony_ci        if ((we->next == nullptr) || (we->prev == nullptr)) {
143484543d1Sopenharmony_ci            return;
144484543d1Sopenharmony_ci        }
145484543d1Sopenharmony_ci        we->prev->next = we->next;
146484543d1Sopenharmony_ci        we->next->prev = we->prev;
147484543d1Sopenharmony_ci        we->next = nullptr;
148484543d1Sopenharmony_ci        we->prev = nullptr;
149484543d1Sopenharmony_ci        return;
150484543d1Sopenharmony_ci    }
151484543d1Sopenharmony_ci    friend bool WeTimeoutProc(WaitQueue* wq, WaitUntilEntry* wue);
152484543d1Sopenharmony_ci};
153484543d1Sopenharmony_ci} // namespace ffrt
154484543d1Sopenharmony_ci#endif // _WAITQUEUE_H_
155