• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2025 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 #ifndef PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_JOB_H_
17 #define PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_JOB_H_
18 
19 #include "runtime/include/object_header.h"
20 #include "libpandabase/macros.h"
21 #include "plugins/ets/runtime/ets_vm.h"
22 #include "plugins/ets/runtime/types/ets_object.h"
23 #include "plugins/ets/runtime/types/ets_sync_primitives.h"
24 #include "plugins/ets/runtime/types/ets_primitives.h"
25 
26 namespace ark::ets {
27 
28 class EtsCoroutine;
29 
30 namespace test {
31 class EtsJobTest;
32 }  // namespace test
33 
34 class EtsJob : public ObjectHeader {
35 public:
36     static constexpr EtsInt STATE_RUNNING = 0;
37     static constexpr EtsInt STATE_FINISHED = 1;
38     static constexpr EtsInt STATE_FAILED = 2;
39 
40     EtsJob() = delete;
41     EtsJob(EtsJob &) = delete;
42     ~EtsJob() = default;
43 
44     NO_COPY_SEMANTIC(EtsJob);
45     NO_MOVE_SEMANTIC(EtsJob);
46 
47     PANDA_PUBLIC_API static EtsJob *Create(EtsCoroutine *etsCoroutine = EtsCoroutine::GetCurrent());
48 
49     static void EtsJobFinish(EtsJob *job, EtsObject *value);
50 
51     static void EtsJobFail(EtsJob *job, EtsObject *error);
52 
FromCoreType(ObjectHeader * job)53     static EtsJob *FromCoreType(ObjectHeader *job)
54     {
55         return reinterpret_cast<EtsJob *>(job);
56     }
57 
GetCoreType()58     ObjectHeader *GetCoreType() const
59     {
60         return static_cast<ObjectHeader *>(const_cast<EtsJob *>(this));
61     }
62 
AsObject()63     EtsObject *AsObject()
64     {
65         return EtsObject::FromCoreType(this);
66     }
67 
AsObject()68     const EtsObject *AsObject() const
69     {
70         return EtsObject::FromCoreType(this);
71     }
72 
FromEtsObject(EtsObject * job)73     static EtsJob *FromEtsObject(EtsObject *job)
74     {
75         return reinterpret_cast<EtsJob *>(job);
76     }
77 
GetMutex(EtsCoroutine * coro)78     EtsMutex *GetMutex(EtsCoroutine *coro)
79     {
80         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsJob, mutex_));
81         return EtsMutex::FromCoreType(obj);
82     }
83 
SetMutex(EtsCoroutine * coro,EtsMutex * mutex)84     void SetMutex(EtsCoroutine *coro, EtsMutex *mutex)
85     {
86         ASSERT(mutex != nullptr);
87         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsJob, mutex_), mutex->GetCoreType());
88     }
89 
GetEvent(EtsCoroutine * coro)90     EtsEvent *GetEvent(EtsCoroutine *coro)
91     {
92         auto *obj = ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsJob, event_));
93         return EtsEvent::FromCoreType(obj);
94     }
95 
SetEvent(EtsCoroutine * coro,EtsEvent * event)96     void SetEvent(EtsCoroutine *coro, EtsEvent *event)
97     {
98         ASSERT(event != nullptr);
99         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsJob, event_), event->GetCoreType());
100     }
101 
GetValue(EtsCoroutine * coro)102     EtsObject *GetValue(EtsCoroutine *coro)
103     {
104         return EtsObject::FromCoreType(ObjectAccessor::GetObject(coro, this, MEMBER_OFFSET(EtsJob, value_)));
105     }
106 
107     /// Allows to get exclusive access to the job state
Lock()108     void Lock()
109     {
110         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
111         ASSERT(mutex != nullptr);
112         mutex->Lock();
113     }
114 
Unlock()115     void Unlock()
116     {
117         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
118         ASSERT(mutex != nullptr);
119         ASSERT(mutex->IsHeld());
120         mutex->Unlock();
121     }
122 
IsLocked()123     bool IsLocked()
124     {
125         auto *mutex = GetMutex(EtsCoroutine::GetCurrent());
126         ASSERT(mutex != nullptr);
127         return mutex->IsHeld();
128     }
129 
130     /// Blocks current coroutine until job is resolved/rejected
Wait()131     void Wait()
132     {
133         auto *event = GetEvent(EtsCoroutine::GetCurrent());
134         ASSERT(event != nullptr);
135         event->Wait();
136     }
137 
IsRunning()138     bool IsRunning() const
139     {
140         return state_ == STATE_RUNNING;
141     }
142 
IsFinished()143     bool IsFinished() const
144     {
145         return state_ == STATE_FINISHED;
146     }
147 
IsFailed()148     bool IsFailed() const
149     {
150         return state_ == STATE_FAILED;
151     }
152 
Finish(EtsCoroutine * coro,EtsObject * value)153     void Finish(EtsCoroutine *coro, EtsObject *value)
154     {
155         ASSERT(state_ == STATE_RUNNING);
156         auto coreValue = (value == nullptr) ? nullptr : value->GetCoreType();
157         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsJob, value_), coreValue);
158         state_ = STATE_FINISHED;
159         // Unblock awaitee coros
160         GetEvent(coro)->Fire();
161     }
162 
Fail(EtsCoroutine * coro,EtsObject * error)163     void Fail(EtsCoroutine *coro, EtsObject *error)
164     {
165         ASSERT(error != nullptr);
166         ASSERT(state_ == STATE_RUNNING);
167         ASSERT(error != nullptr);
168         ObjectAccessor::SetObject(coro, this, MEMBER_OFFSET(EtsJob, value_), error->GetCoreType());
169         state_ = STATE_FAILED;
170 
171         if (Runtime::GetOptions().IsListUnhandledOnExitJobs(plugins::LangToRuntimeType(panda_file::SourceLang::ETS))) {
172             coro->GetPandaVM()->AddUnhandledFailedJob(this);
173         }
174 
175         // Unblock awaitee coros
176         GetEvent(coro)->Fire();
177     }
178 
179 private:
180     ObjectPointer<EtsObject> value_;  // the completion value of the Job
181     ObjectPointer<EtsMutex> mutex_;
182     ObjectPointer<EtsEvent> event_;
183     uint32_t state_;  // the Job state
184 
185     friend class test::EtsJobTest;
186 };
187 
188 }  // namespace ark::ets
189 
190 #endif  // PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_JOB_H_
191