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