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#include <pthread.h> 16#include <random> 17#include "core/task_io.h" 18#ifdef FFRT_CO_BACKTRACE_OH_ENABLE 19#include <dlfcn.h> 20#endif 21#include "util/slab.h" 22#include "util/ffrt_facade.h" 23#include "util/spmc_queue.h" 24 25#define ENABLE_LOCAL_QUEUE 26 27namespace { 28const int INSERT_GLOBAL_QUEUE_FREQ = 5; 29} 30 31namespace ffrt { 32static void work_finish_callable(IOTaskExecutor* task) 33{ 34 task->status = ExecTaskStatus::ET_FINISH; 35 task->work.destroy(task->work.data); 36 delete task; 37} 38 39static void ExecuteIOTask(ffrt_executor_task_t* data, ffrt_qos_t qos) 40{ 41 IOTaskExecutor* task = static_cast<IOTaskExecutor*>(data); 42 task->status = ExecTaskStatus::ET_EXECUTING; 43 (void)qos; 44 ffrt_coroutine_ptr_t coroutine = task->work.exec; 45 ffrt_coroutine_ret_t ret = coroutine(task->work.data); 46 if (ret == ffrt_coroutine_ready) { 47 FFRT_EXECUTOR_TASK_FINISH_MARKER(task); 48 work_finish_callable(task); 49 return; 50 } 51 52 FFRT_EXECUTOR_TASK_BLOCK_MARKER(task); 53 task->status = ffrt::ExecTaskStatus::ET_PENDING; 54#ifdef FFRT_BBOX_ENABLE 55 TaskPendingCounterInc(); 56#endif 57} 58 59static pthread_once_t once = PTHREAD_ONCE_INIT; 60 61static void InitIOTaskExecutor() 62{ 63 ffrt_executor_task_register_func(ExecuteIOTask, ffrt_io_task); 64} 65} /* namespace ffrt */ 66 67#ifdef __cplusplus 68extern "C" { 69#endif 70API_ATTRIBUTE((visibility("default"))) 71void ffrt_submit_coroutine(void* co, ffrt_coroutine_ptr_t exec, ffrt_function_t destroy, const ffrt_deps_t* in_deps, 72 const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 73{ 74 FFRT_COND_DO_ERR((exec == nullptr), return, "input invalid, exec == nullptr"); 75 pthread_once(&ffrt::once, ffrt::InitIOTaskExecutor); 76 77 ffrt::task_attr_private *p = reinterpret_cast<ffrt::task_attr_private *>(const_cast<ffrt_task_attr_t *>(attr)); 78 ffrt::QoS qos = (p == nullptr ? ffrt::QoS() : ffrt::QoS(p->qos_)); 79 80 (void)in_deps; 81 (void)out_deps; 82 ffrt::IOTaskExecutor* task = new ffrt::IOTaskExecutor(qos); 83 task->work.exec = exec; 84 task->work.destroy = destroy; 85 task->work.data = co; 86 task->status = ffrt::ExecTaskStatus::ET_READY; 87 88 ffrt_executor_task_submit(dynamic_cast<ffrt_executor_task_t*>(task), attr); 89} 90 91API_ATTRIBUTE((visibility("default"))) 92void* ffrt_get_current_task() 93{ 94 return reinterpret_cast<void*>(ffrt::ExecuteCtx::Cur()->exec_task); 95} 96 97// API used to schedule stackless coroutine task 98API_ATTRIBUTE((visibility("default"))) 99void ffrt_wake_coroutine(void* task) 100{ 101 if (task == nullptr) { 102 FFRT_LOGE("Task is nullptr."); 103 return; 104 } 105 106#ifdef FFRT_BBOX_ENABLE 107 TaskWakeCounterInc(); 108#endif 109 110 ffrt::IOTaskExecutor* wakedTask = static_cast<ffrt::IOTaskExecutor*>(task); 111 wakedTask->status = ffrt::ExecTaskStatus::ET_READY; 112 113 // in self-wakeup scenario, tasks are placed in local fifo to delay scheduling, implementing the yeild function 114 bool selfWakeup = (ffrt::ExecuteCtx::Cur()->exec_task == task); 115 if (!selfWakeup) { 116 if (ffrt::ExecuteCtx::Cur()->PushTaskToPriorityStack(wakedTask)) { 117 return; 118 } 119 120 if (rand() % INSERT_GLOBAL_QUEUE_FREQ) { 121 if (ffrt::ExecuteCtx::Cur()->localFifo != nullptr && 122 ffrt::ExecuteCtx::Cur()->localFifo->PushTail(task) == 0) { 123 ffrt::FFRTFacade::GetEUInstance().NotifyLocalTaskAdded(wakedTask->qos); 124 return; 125 } 126 } 127 } 128 129 ffrt::LinkedList* node = reinterpret_cast<ffrt::LinkedList *>(&wakedTask->wq); 130 if (!ffrt::FFRTFacade::GetSchedInstance()->InsertNode(node, wakedTask->qos)) { 131 FFRT_LOGE("Submit io task failed!"); 132 } 133} 134#ifdef __cplusplus 135} 136#endif 137 138