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 <memory>
17#include <vector>
18
19#include "ffrt_inner.h"
20#include "internal_inc/osal.h"
21#include "sync/io_poller.h"
22#include "qos.h"
23#include "sched/task_scheduler.h"
24#include "task_attr_private.h"
25#include "internal_inc/config.h"
26#include "eu/osattr_manager.h"
27#include "eu/worker_thread.h"
28#include "eu/cpu_monitor.h"
29#include "dfx/log/ffrt_log_api.h"
30#include "dfx/trace_record/ffrt_trace_record.h"
31#include "dfx/watchdog/watchdog_util.h"
32#include "eu/func_manager.h"
33#include "util/ffrt_facade.h"
34#include "util/slab.h"
35#include "eu/sexecute_unit.h"
36#include "core/task_io.h"
37#include "sync/poller.h"
38#include "util/spmc_queue.h"
39#include "tm/task_factory.h"
40#include "tm/queue_task.h"
41
42namespace ffrt {
43inline void submit_impl(bool has_handle, ffrt_task_handle_t &handle, ffrt_function_header_t *f,
44    const ffrt_deps_t *ins, const ffrt_deps_t *outs, const task_attr_private *attr)
45{
46    FFRTFacade::GetDMInstance().onSubmit(has_handle, handle, f, ins, outs, attr);
47}
48
49API_ATTRIBUTE((visibility("default")))
50void sync_io(int fd)
51{
52    ffrt_wait_fd(fd);
53}
54
55API_ATTRIBUTE((visibility("default")))
56void set_trace_tag(const char* name)
57{
58    CPUEUTask* curTask = ffrt::ExecuteCtx::Cur()->task;
59    if (curTask != nullptr) {
60        curTask->SetTraceTag(name);
61    }
62}
63
64API_ATTRIBUTE((visibility("default")))
65void clear_trace_tag()
66{
67    CPUEUTask* curTask = ffrt::ExecuteCtx::Cur()->task;
68    if (curTask != nullptr) {
69        curTask->ClearTraceTag();
70    }
71}
72
73void CreateDelayDeps(
74    ffrt_task_handle_t &handle, const ffrt_deps_t *in_deps, const ffrt_deps_t *out_deps, task_attr_private *p)
75{
76    // setting dependences is not supportted for delayed task
77    if (unlikely(((in_deps != nullptr) && (in_deps->len != 0)) || ((out_deps != nullptr) && (out_deps->len != 0)))) {
78        FFRT_LOGE("delayed task do not support dependence, in_deps/out_deps ignored.");
79    }
80
81    // delay task
82    uint64_t delayUs = p->delay_;
83    std::function<void()> &&func = [delayUs]() {
84        this_task::sleep_for(std::chrono::microseconds(delayUs));
85        FFRT_LOGD("submit task delay time [%d us] has ended.", delayUs);
86    };
87    ffrt_function_header_t *delay_func = create_function_wrapper(std::move(func));
88    submit_impl(true, handle, delay_func, nullptr, nullptr, reinterpret_cast<task_attr_private *>(p));
89}
90} // namespace ffrt
91
92#ifdef __cplusplus
93extern "C" {
94#endif
95API_ATTRIBUTE((visibility("default")))
96int ffrt_task_attr_init(ffrt_task_attr_t *attr)
97{
98    if (unlikely(!attr)) {
99        FFRT_LOGE("attr should be a valid address");
100        return -1;
101    }
102    static_assert(sizeof(ffrt::task_attr_private) <= ffrt_task_attr_storage_size,
103        "size must be less than ffrt_task_attr_storage_size");
104
105    new (attr)ffrt::task_attr_private();
106    return 0;
107}
108
109API_ATTRIBUTE((visibility("default")))
110void ffrt_task_attr_destroy(ffrt_task_attr_t *attr)
111{
112    if (unlikely(!attr)) {
113        FFRT_LOGE("attr should be a valid address");
114        return;
115    }
116    auto p = reinterpret_cast<ffrt::task_attr_private *>(attr);
117    p->~task_attr_private();
118}
119
120API_ATTRIBUTE((visibility("default")))
121void ffrt_task_attr_set_name(ffrt_task_attr_t *attr, const char *name)
122{
123    if (unlikely(!attr || !name)) {
124        FFRT_LOGE("invalid attr or name");
125        return;
126    }
127    (reinterpret_cast<ffrt::task_attr_private *>(attr))->name_ = name;
128}
129
130API_ATTRIBUTE((visibility("default")))
131const char *ffrt_task_attr_get_name(const ffrt_task_attr_t *attr)
132{
133    if (unlikely(!attr)) {
134        FFRT_LOGE("attr should be a valid address");
135        return nullptr;
136    }
137    ffrt_task_attr_t *p = const_cast<ffrt_task_attr_t *>(attr);
138    return (reinterpret_cast<ffrt::task_attr_private *>(p))->name_.c_str();
139}
140
141API_ATTRIBUTE((visibility("default")))
142void ffrt_task_attr_set_qos(ffrt_task_attr_t *attr, ffrt_qos_t qos)
143{
144    if (unlikely(!attr)) {
145        FFRT_LOGE("attr should be a valid address");
146        return;
147    }
148    if (ffrt::GetFuncQosMap() == nullptr) {
149        FFRT_LOGE("FuncQosMap has not regist");
150        return;
151    }
152    (reinterpret_cast<ffrt::task_attr_private *>(attr))->qos_ = ffrt::GetFuncQosMap()(qos);
153}
154
155API_ATTRIBUTE((visibility("default")))
156ffrt_qos_t ffrt_task_attr_get_qos(const ffrt_task_attr_t *attr)
157{
158    if (unlikely(!attr)) {
159        FFRT_LOGE("attr should be a valid address");
160        return static_cast<int>(ffrt_qos_default);
161    }
162    ffrt_task_attr_t *p = const_cast<ffrt_task_attr_t *>(attr);
163    return (reinterpret_cast<ffrt::task_attr_private *>(p))->qos_;
164}
165
166API_ATTRIBUTE((visibility("default")))
167void ffrt_task_attr_set_delay(ffrt_task_attr_t *attr, uint64_t delay_us)
168{
169    if (unlikely(!attr)) {
170        FFRT_LOGE("attr should be a valid address");
171        return;
172    }
173    (reinterpret_cast<ffrt::task_attr_private *>(attr))->delay_ = delay_us;
174}
175
176API_ATTRIBUTE((visibility("default")))
177uint64_t ffrt_task_attr_get_delay(const ffrt_task_attr_t *attr)
178{
179    if (unlikely(!attr)) {
180        FFRT_LOGE("attr should be a valid address");
181        return 0;
182    }
183    ffrt_task_attr_t *p = const_cast<ffrt_task_attr_t *>(attr);
184    return (reinterpret_cast<ffrt::task_attr_private *>(p))->delay_;
185}
186
187API_ATTRIBUTE((visibility("default")))
188void ffrt_task_attr_set_timeout(ffrt_task_attr_t *attr, uint64_t timeout_ms)
189{
190    if (unlikely(!attr)) {
191        FFRT_LOGE("attr should be a valid address");
192        return;
193    }
194    (reinterpret_cast<ffrt::task_attr_private *>(attr))->timeout_ = timeout_ms;
195}
196
197API_ATTRIBUTE((visibility("default")))
198uint64_t ffrt_task_attr_get_timeout(const ffrt_task_attr_t *attr)
199{
200    if (unlikely(!attr)) {
201        FFRT_LOGE("attr should be a valid address");
202        return 0;
203    }
204    ffrt_task_attr_t *p = const_cast<ffrt_task_attr_t *>(attr);
205    return (reinterpret_cast<ffrt::task_attr_private *>(p))->timeout_;
206}
207
208
209API_ATTRIBUTE((visibility("default")))
210void ffrt_task_attr_set_notify_worker(ffrt_task_attr_t* attr, bool notify)
211{
212    if (unlikely(!attr)) {
213        FFRT_LOGE("attr should be a valid address");
214        return;
215    }
216    (reinterpret_cast<ffrt::task_attr_private *>(attr))->notifyWorker_ = notify;
217}
218
219API_ATTRIBUTE((visibility("default")))
220void ffrt_task_attr_set_queue_priority(ffrt_task_attr_t* attr, ffrt_queue_priority_t priority)
221{
222    if (unlikely(!attr)) {
223        FFRT_LOGE("attr should be a valid address");
224        return;
225    }
226
227    // eventhandler inner priority is one more than the kits priority
228    int prio = static_cast<int>(priority);
229    if (prio < static_cast<int>(ffrt_queue_priority_immediate) ||
230        prio > static_cast<int>(ffrt_queue_priority_idle) + 1) {
231        FFRT_LOGE("priority should be a valid priority");
232        return;
233    }
234
235    (reinterpret_cast<ffrt::task_attr_private *>(attr))->prio_ = priority;
236}
237
238API_ATTRIBUTE((visibility("default")))
239ffrt_queue_priority_t ffrt_task_attr_get_queue_priority(const ffrt_task_attr_t* attr)
240{
241    if (unlikely(!attr)) {
242        FFRT_LOGE("attr should be a valid address");
243        return ffrt_queue_priority_immediate;
244    }
245    ffrt_task_attr_t *p = const_cast<ffrt_task_attr_t *>(attr);
246    return static_cast<ffrt_queue_priority_t>((reinterpret_cast<ffrt::task_attr_private *>(p))->prio_);
247}
248
249API_ATTRIBUTE((visibility("default")))
250void ffrt_task_attr_set_stack_size(ffrt_task_attr_t* attr, uint64_t size)
251{
252    if (unlikely(!attr)) {
253        FFRT_LOGE("attr should be a valid address");
254        return;
255    }
256    (reinterpret_cast<ffrt::task_attr_private *>(attr))->stackSize_ = size;
257}
258
259API_ATTRIBUTE((visibility("default")))
260uint64_t ffrt_task_attr_get_stack_size(const ffrt_task_attr_t* attr)
261{
262    if (unlikely(!attr)) {
263        FFRT_LOGE("attr should be a valid address");
264        return 0;
265    }
266    return (reinterpret_cast<const ffrt::task_attr_private *>(attr))->stackSize_;
267}
268
269// submit
270API_ATTRIBUTE((visibility("default")))
271void *ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind)
272{
273    if (kind == ffrt_function_kind_general) {
274        return ffrt::TaskFactory::Alloc()->func_storage;
275    }
276    return ffrt::SimpleAllocator<ffrt::QueueTask>::AllocMem()->func_storage;
277}
278
279API_ATTRIBUTE((visibility("default")))
280void ffrt_submit_base(ffrt_function_header_t *f, const ffrt_deps_t *in_deps, const ffrt_deps_t *out_deps,
281    const ffrt_task_attr_t *attr)
282{
283    if (unlikely(!f)) {
284        FFRT_LOGE("function handler should not be empty");
285        return;
286    }
287    ffrt_task_handle_t handle;
288    ffrt::task_attr_private *p = reinterpret_cast<ffrt::task_attr_private *>(const_cast<ffrt_task_attr_t *>(attr));
289    if (likely(attr == nullptr || ffrt_task_attr_get_delay(attr) == 0)) {
290        ffrt::submit_impl(false, handle, f, in_deps, out_deps, p);
291        return;
292    }
293
294    // task after delay
295    ffrt_task_handle_t delay_handle;
296    uint64_t timeout = p->timeout_;
297    p->timeout_ = 0;
298    ffrt::CreateDelayDeps(delay_handle, in_deps, out_deps, p);
299    p->timeout_ = timeout;
300    std::vector<ffrt_dependence_t> deps = {{ffrt_dependence_task, delay_handle}};
301    ffrt_deps_t delay_deps {static_cast<uint32_t>(deps.size()), deps.data()};
302    ffrt::submit_impl(false, handle, f, &delay_deps, nullptr, p);
303    ffrt_task_handle_destroy(delay_handle);
304}
305
306API_ATTRIBUTE((visibility("default")))
307ffrt_task_handle_t ffrt_submit_h_base(ffrt_function_header_t *f, const ffrt_deps_t *in_deps,
308    const ffrt_deps_t *out_deps, const ffrt_task_attr_t *attr)
309{
310    if (unlikely(!f)) {
311        FFRT_LOGE("function handler should not be empty");
312        return nullptr;
313    }
314    ffrt_task_handle_t handle = nullptr;
315    ffrt::task_attr_private *p = reinterpret_cast<ffrt::task_attr_private *>(const_cast<ffrt_task_attr_t *>(attr));
316    if (likely(attr == nullptr || ffrt_task_attr_get_delay(attr) == 0)) {
317        ffrt::submit_impl(true, handle, f, in_deps, out_deps, p);
318        return handle;
319    }
320
321    // task after delay
322    ffrt_task_handle_t delay_handle = nullptr;
323    uint64_t timeout = p->timeout_;
324    p->timeout_ = 0;
325    ffrt::CreateDelayDeps(delay_handle, in_deps, out_deps, p);
326    p->timeout_ = timeout;
327    std::vector<ffrt_dependence_t> deps = {{ffrt_dependence_task, delay_handle}};
328    ffrt_deps_t delay_deps {static_cast<uint32_t>(deps.size()), deps.data()};
329    ffrt::submit_impl(true, handle, f, &delay_deps, nullptr, p);
330    ffrt_task_handle_destroy(delay_handle);
331    return handle;
332}
333
334API_ATTRIBUTE((visibility("default")))
335uint32_t ffrt_task_handle_inc_ref(ffrt_task_handle_t handle)
336{
337    if (handle == nullptr) {
338        FFRT_LOGE("input task handle is invalid");
339        return -1;
340    }
341    return static_cast<ffrt::CPUEUTask*>(handle)->IncDeleteRef();
342}
343
344API_ATTRIBUTE((visibility("default")))
345uint32_t ffrt_task_handle_dec_ref(ffrt_task_handle_t handle)
346{
347    if (handle == nullptr) {
348        FFRT_LOGE("input task handle is invalid");
349        return -1;
350    }
351    return static_cast<ffrt::CPUEUTask*>(handle)->DecDeleteRef();
352}
353
354API_ATTRIBUTE((visibility("default")))
355void ffrt_task_handle_destroy(ffrt_task_handle_t handle)
356{
357    ffrt_task_handle_dec_ref(handle);
358}
359
360// wait
361API_ATTRIBUTE((visibility("default")))
362void ffrt_wait_deps(const ffrt_deps_t *deps)
363{
364    if (unlikely(!deps)) {
365        FFRT_LOGE("deps should not be empty");
366        return;
367    }
368    std::vector<ffrt_dependence_t> v(deps->len);
369    for (uint64_t i = 0; i < deps->len; ++i) {
370        v[i] = deps->items[i];
371    }
372    ffrt_deps_t d = { deps->len, v.data() };
373    ffrt::FFRTFacade::GetDMInstance().onWait(&d);
374}
375
376API_ATTRIBUTE((visibility("default")))
377void ffrt_wait()
378{
379    ffrt::FFRTFacade::GetDMInstance().onWait();
380}
381
382API_ATTRIBUTE((visibility("default")))
383int ffrt_set_cgroup_attr(ffrt_qos_t qos, ffrt_os_sched_attr *attr)
384{
385    if (unlikely(!attr)) {
386        FFRT_LOGE("attr should not be empty");
387        return -1;
388    }
389    if (ffrt::GetFuncQosMap() == nullptr) {
390        FFRT_LOGE("FuncQosMap has not regist");
391        return -1;
392    }
393    ffrt::QoS _qos = ffrt::GetFuncQosMap()(qos);
394    return ffrt::OSAttrManager::Instance()->UpdateSchedAttr(_qos, attr);
395}
396
397API_ATTRIBUTE((visibility("default")))
398void ffrt_restore_qos_config()
399{
400    ffrt::WorkerGroupCtl *wgCtl = ffrt::FFRTFacade::GetEUInstance().GetGroupCtl();
401    for (auto qos = ffrt::QoS::Min(); qos < ffrt::QoS::Max(); ++qos) {
402        std::unique_lock<std::shared_mutex> lck(wgCtl[qos].tgMutex);
403        for (auto& thread : wgCtl[qos].threads) {
404            ffrt::SetThreadAttr(thread.first, qos);
405        }
406    }
407}
408
409API_ATTRIBUTE((visibility("default")))
410int ffrt_set_qos_worker_num(ffrt_worker_num_param *qosData)
411{
412    ffrt::CPUMonitor *monitor = ffrt::FFRTFacade::GetEUInstance().GetCPUMonitor();
413    return monitor->QosWorkerNumSegment(qosData);
414}
415
416API_ATTRIBUTE((visibility("default")))
417void ffrt_notify_workers(ffrt_qos_t qos, int number)
418{
419    if (qos < ffrt::QoS::Min() || qos >= ffrt::QoS::Max() || number <= 0) {
420        FFRT_LOGE("qos [%d] or number [%d] or is invalid.", qos, number);
421        return;
422    }
423
424    ffrt::FFRTFacade::GetEUInstance().NotifyWorkers(qos, number);
425}
426
427API_ATTRIBUTE((visibility("default")))
428ffrt_error_t ffrt_set_worker_stack_size(ffrt_qos_t qos, size_t stack_size)
429{
430    if (qos < ffrt::QoS::Min() || qos >= ffrt::QoS::Max() || stack_size < PTHREAD_STACK_MIN) {
431        FFRT_LOGE("qos [%d] or stack size [%d] is invalid.", qos, stack_size);
432        return ffrt_error_inval;
433    }
434
435    ffrt::WorkerGroupCtl* groupCtl = ffrt::FFRTFacade::GetEUInstance().GetGroupCtl();
436    std::unique_lock<std::shared_mutex> lck(groupCtl[qos].tgMutex);
437    if (!groupCtl[qos].threads.empty()) {
438        FFRT_LOGE("Stack size can be set only when there is no worker.");
439        return ffrt_error;
440    }
441
442    int pageSize = getpagesize();
443    if (pageSize < 0) {
444        FFRT_LOGE("Invalid pagesize : %d", pageSize);
445        return ffrt_error;
446    }
447
448    groupCtl[qos].workerStackSize = (stack_size - 1 + static_cast<size_t>(pageSize)) &
449        -(static_cast<size_t>(pageSize));
450
451    return ffrt_success;
452}
453
454API_ATTRIBUTE((visibility("default")))
455int ffrt_this_task_update_qos(ffrt_qos_t qos)
456{
457    if (ffrt::GetFuncQosMap() == nullptr) {
458        FFRT_LOGE("FuncQosMap has not regist");
459        return 1;
460    }
461    ffrt::QoS _qos = ffrt::GetFuncQosMap()(qos);
462    auto curTask = ffrt::ExecuteCtx::Cur()->task;
463    if (curTask == nullptr) {
464        FFRT_LOGW("task is nullptr");
465        return 1;
466    }
467
468    FFRT_COND_DO_ERR((curTask->type != ffrt_normal_task), return 1, "update qos task type invalid");
469    if (_qos() == curTask->qos) {
470        FFRT_LOGW("the target qos is equal to current qos, no need update");
471        return 0;
472    }
473
474    curTask->SetQos(_qos);
475    ffrt_yield();
476
477    return 0;
478}
479
480API_ATTRIBUTE((visibility("default")))
481ffrt_qos_t ffrt_this_task_get_qos()
482{
483    if (ffrt::ExecuteCtx::Cur()->task == nullptr) {
484        FFRT_LOGW("task is nullptr");
485        return static_cast<int>(ffrt_qos_default);
486    }
487    return ffrt::ExecuteCtx::Cur()->qos();
488}
489
490API_ATTRIBUTE((visibility("default")))
491uint64_t ffrt_this_task_get_id()
492{
493    auto curTask = ffrt::ExecuteCtx::Cur()->task;
494    if (curTask == nullptr) {
495        return 0;
496    }
497
498    if (curTask->type == ffrt_normal_task || curTask->type == ffrt_queue_task) {
499        return curTask->gid;
500    }
501
502    return 0;
503}
504
505API_ATTRIBUTE((visibility("default")))
506int64_t ffrt_this_queue_get_id()
507{
508    auto curTask = ffrt::ExecuteCtx::Cur()->task;
509    if (curTask == nullptr || curTask->type != ffrt_queue_task) {
510        // not serial queue task
511        return -1;
512    }
513
514    ffrt::QueueTask* task = reinterpret_cast<ffrt::QueueTask*>(curTask);
515    return task->GetQueueId();
516}
517
518API_ATTRIBUTE((visibility("default")))
519int ffrt_skip(ffrt_task_handle_t handle)
520{
521    return ffrt::FFRTFacade::GetDMInstance().onSkip(handle);
522}
523
524API_ATTRIBUTE((visibility("default")))
525void ffrt_executor_task_submit(ffrt_executor_task_t* task, const ffrt_task_attr_t* attr)
526{
527    if (task == nullptr) {
528        FFRT_LOGE("function handler should not be empty");
529        return;
530    }
531    ffrt::task_attr_private* p = reinterpret_cast<ffrt::task_attr_private *>(const_cast<ffrt_task_attr_t *>(attr));
532    if (likely(attr == nullptr || ffrt_task_attr_get_delay(attr) == 0)) {
533        ffrt::FFRTFacade::GetDMInstance().onSubmitUV(task, p);
534        return;
535    }
536    FFRT_LOGE("uv function does not support delay");
537}
538
539API_ATTRIBUTE((visibility("default")))
540void ffrt_executor_task_register_func(ffrt_executor_task_func func, ffrt_executor_task_type_t type)
541{
542    ffrt::FuncManager* func_mg = ffrt::FuncManager::Instance();
543    func_mg->insert(type, func);
544}
545
546API_ATTRIBUTE((visibility("default")))
547int ffrt_executor_task_cancel(ffrt_executor_task_t* task, const ffrt_qos_t qos)
548{
549    if (task == nullptr) {
550        FFRT_LOGE("function handler should not be empty");
551        return 0;
552    }
553    ffrt::QoS _qos = qos;
554
555    ffrt::LinkedList* node = reinterpret_cast<ffrt::LinkedList *>(&task->wq);
556    ffrt::FFRTScheduler* sch = ffrt::FFRTFacade::GetSchedInstance();
557    bool ret = sch->RemoveNode(node, _qos);
558    if (ret) {
559        ffrt::FFRTTraceRecord::TaskCancel<ffrt_uv_task>(qos);
560    }
561    return static_cast<int>(ret);
562}
563
564API_ATTRIBUTE((visibility("default")))
565void* ffrt_get_cur_task()
566{
567    return ffrt::ExecuteCtx::Cur()->task;
568}
569
570API_ATTRIBUTE((visibility("default")))
571bool ffrt_get_current_coroutine_stack(void** stack_addr, size_t* size)
572{
573    if (stack_addr == nullptr || size == nullptr) {
574        return false;
575    }
576
577    if (!ffrt::USE_COROUTINE) {
578        return false;
579    }
580    auto curTask = ffrt::ExecuteCtx::Cur()->task;
581    if (curTask != nullptr) {
582        auto co = curTask->coRoutine;
583        if (co) {
584            *size = co->stkMem.size;
585            *stack_addr = static_cast<void*>(reinterpret_cast<char*>(co) + sizeof(CoRoutine) - 8);
586            return true;
587        }
588    }
589    return false;
590}
591
592API_ATTRIBUTE((visibility("default")))
593void ffrt_task_attr_set_local(ffrt_task_attr_t* attr, bool task_local)
594{
595    if (unlikely(!attr)) {
596        FFRT_LOGE("attr should be a valid address");
597        return;
598    }
599    (reinterpret_cast<ffrt::task_attr_private *>(attr))->taskLocal_ = task_local;
600}
601
602API_ATTRIBUTE((visibility("default")))
603bool ffrt_task_attr_get_local(ffrt_task_attr_t* attr)
604{
605    if (unlikely(!attr)) {
606        FFRT_LOGE("attr should be a valid address");
607        return false;
608    }
609    return (reinterpret_cast<ffrt::task_attr_private *>(attr))->taskLocal_;
610}
611
612API_ATTRIBUTE((visibility("default")))
613pthread_t ffrt_task_get_tid(void* task_handle)
614{
615    if (task_handle == nullptr) {
616        FFRT_LOGE("invalid task handle");
617        return 0;
618    }
619
620    auto task = reinterpret_cast<ffrt::CPUEUTask*>(task_handle);
621    return task->runningTid.load();
622}
623
624API_ATTRIBUTE((visibility("default")))
625uint64_t ffrt_get_cur_cached_task_id()
626{
627    uint64_t gid = ffrt_this_task_get_id();
628    if (gid == 0) {
629        return ffrt::ExecuteCtx::Cur()->lastGid_;
630    }
631
632    return gid;
633}
634#ifdef __cplusplus
635}
636#endif
637