• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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 #include "plugins/ets/runtime/ets_vm.h"
16 #include "plugins/ets/runtime/types/ets_sync_primitives.h"
17 
18 #include <atomic>
19 
20 namespace ark::ets {
21 
22 /*static*/
Create(EtsCoroutine * coro)23 EtsMutex *EtsMutex::Create(EtsCoroutine *coro)
24 {
25     auto *klass = coro->GetPandaVM()->GetClassLinker()->GetMutexClass();
26     auto hMutex = EtsHandle<EtsMutex>(coro, EtsMutex::FromEtsObject(EtsObject::Create(coro, klass)));
27     auto *waitersList = EtsWaitersList::Create(coro);
28     hMutex->SetWaitersList(coro, waitersList);
29     return hMutex.GetPtr();
30 }
31 
Lock()32 void EtsMutex::Lock()
33 {
34     // Atomic with acq_rel order reason: sync Lock/Unlock in other threads
35     if (waiters_.fetch_add(1, std::memory_order_acq_rel) == 0) {
36         return;
37     }
38     auto *coroManager = EtsCoroutine::GetCurrent()->GetCoroutineManager();
39     auto awaitee = EtsWaitersList::Node(coroManager);
40     SuspendCoroutine(&awaitee);
41 }
42 
Unlock()43 void EtsMutex::Unlock()
44 {
45     // Atomic with acq_rel order reason: sync Lock/Unlock in other threads
46     if (waiters_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
47         return;
48     }
49     ResumeCoroutine();
50 }
51 
IsHeld()52 bool EtsMutex::IsHeld()
53 {
54     // Atomic with relaxed order reason: sync is not needed here
55     // because it is expected that method is not called concurrently with Lock/Unlock
56     return waiters_.load(std::memory_order_relaxed) != 0;
57 }
58 
59 /*static*/
Create(EtsCoroutine * coro)60 EtsEvent *EtsEvent::Create(EtsCoroutine *coro)
61 {
62     auto *klass = coro->GetPandaVM()->GetClassLinker()->GetEventClass();
63     auto hEvent = EtsHandle<EtsEvent>(coro, EtsEvent::FromEtsObject(EtsObject::Create(coro, klass)));
64     auto *waitersList = EtsWaitersList::Create(coro);
65     hEvent->SetWaitersList(coro, waitersList);
66     return hEvent.GetPtr();
67 }
68 
Wait()69 void EtsEvent::Wait()
70 {
71     // Atomic with acq_rel order reason: sync Wait/Fire in other threads
72     auto state = state_.fetch_add(ONE_WAITER, std::memory_order_acq_rel);
73     if (IsFireState(state)) {
74         return;
75     }
76     auto *coroManager = EtsCoroutine::GetCurrent()->GetCoroutineManager();
77     auto awaitee = EtsWaitersList::Node(coroManager);
78     SuspendCoroutine(&awaitee);
79 }
80 
Fire()81 void EtsEvent::Fire()
82 {
83     // Atomic with acq_rel order reason: sync Wait/Fire in other threads
84     auto state = state_.exchange(FIRE_STATE, std::memory_order_acq_rel);
85     if (IsFireState(state)) {
86         return;
87     }
88     for (auto waiters = GetNumberOfWaiters(state); waiters > 0; --waiters) {
89         ResumeCoroutine();
90     }
91 }
92 
93 /* static */
Create(EtsCoroutine * coro)94 EtsCondVar *EtsCondVar::Create(EtsCoroutine *coro)
95 {
96     auto *classLinker = coro->GetPandaVM()->GetClassLinker();
97     auto *klass = classLinker->GetCondVarClass();
98     auto hCondVar = EtsHandle<EtsCondVar>(coro, EtsCondVar::FromEtsObject(EtsObject::Create(klass)));
99     auto *waitersList = EtsWaitersList::Create(coro);
100     hCondVar->SetWaitersList(coro, waitersList);
101     return hCondVar.GetPtr();
102 }
103 
Wait(EtsHandle<EtsMutex> & mutex)104 void EtsCondVar::Wait(EtsHandle<EtsMutex> &mutex)
105 {
106     ASSERT(mutex->IsHeld());
107     waiters_++;
108     mutex->Unlock();
109     auto *coroManager = EtsCoroutine::GetCurrent()->GetCoroutineManager();
110     auto awaitee = EtsWaitersList::Node(coroManager);
111     SuspendCoroutine(&awaitee);
112     mutex->Lock();
113 }
114 
NotifyOne(EtsMutex * mutex)115 void EtsCondVar::NotifyOne([[maybe_unused]] EtsMutex *mutex)
116 {
117     ASSERT(mutex->IsHeld());
118     if (waiters_ != 0) {
119         ResumeCoroutine();
120         waiters_--;
121     }
122 }
123 
NotifyAll(EtsMutex * mutex)124 void EtsCondVar::NotifyAll([[maybe_unused]] EtsMutex *mutex)
125 {
126     ASSERT(mutex->IsHeld());
127     while (waiters_ != 0) {
128         ResumeCoroutine();
129         waiters_--;
130     }
131 }
132 
133 }  // namespace ark::ets
134