#include "legacy_coroutines.h" #include #include #include #include #include struct TaskInfo { int id; std::thread thr; std::atomic resume_flag = {false}; std::chrono::system_clock::time_point _wake_up_after = {}; int wake_up_msg = -1; bool request_exit = false; bool exited = false; TaskInfo(int id):id(id) {} }; using TaskList = std::unordered_map >; static int next_task_id = 1; static TaskList task_list; static int get_new_task_id() { int id = next_task_id; next_task_id = (next_task_id + 1) & 0xFFFF; if (task_list.find(id) != task_list.end()) id = get_new_task_id(); return id; } static std::atomic resume_master_flag = {false}; static TaskInfo *current_task_inst = NULL; static EVENT_MSG *cur_message = NULL; struct MsgQueue { EVENT_MSG *msg; TaskInfo *sender; }; static std::queue msg_queue; static void flush_message_queue(); static void task_after_wakeup(TaskInfo *info) { info->wake_up_msg = -1; info->_wake_up_after = {}; } static void switch_to_task(TaskInfo *task) { if (task == current_task_inst) return; if (task == NULL) { TaskInfo *me = current_task_inst; current_task_inst = NULL; resume_master_flag = true; resume_master_flag.notify_all(); me->resume_flag.wait(false); me->resume_flag = false; task_after_wakeup(me); } else if (current_task_inst == NULL) { if (task->exited) return ; current_task_inst = task; task->resume_flag = true; task->resume_flag.notify_all(); resume_master_flag.wait(false); resume_master_flag = false; flush_message_queue(); } else { if (task->exited) return ; TaskInfo *me = current_task_inst; current_task_inst = task; task->resume_flag = true; task->resume_flag.notify_all(); me->resume_flag.wait(false); me->resume_flag = false; task_after_wakeup(me); } } static void clean_task_table() { for (auto iter = task_list.begin(); iter != task_list.end();) { if (iter->second->exited) { iter = task_list.erase(iter); } else { ++iter; } } } static void clean_up_current_task() { TaskInfo *me = current_task_inst; if (!me) return; me->thr.detach(); me->exited = true; current_task_inst = NULL; resume_master_flag = true; resume_master_flag.notify_all(); } static void flush_message_queue() { while (!msg_queue.empty()) { auto m = msg_queue.front(); msg_queue.pop(); for (auto &[id, task]: task_list) { if (task->wake_up_msg == m.msg->msg && task.get() != m.sender) { EVENT_MSG cpy; cpy.msg = m.msg->msg; va_copy(cpy.data, m.msg->data); cur_message = &cpy; switch_to_task(task.get()); va_end(cpy.data); cur_message = NULL; } } clean_task_table(); } } int add_task(int stack,TaskerFunctionName fcname,...) { int id = get_new_task_id(); auto st = task_list.emplace(id, std::make_unique(id)); TaskInfo *new_task = st.first->second.get(); va_list args; va_start(args, fcname); new_task->thr = std::thread([&]{ new_task->resume_flag.wait(false); new_task->resume_flag = false; fcname(args); clean_up_current_task(); }); switch_to_task(new_task); return id; } void term_task(int id_num) { auto iter = task_list.find(id_num); if (iter != task_list.end()) { iter->second->request_exit = true; switch_to_task(iter->second.get()); } } char is_running(int id_num) { if (id_num < 0) return false; auto iter = task_list.find(id_num); if (iter == task_list.end()) return false; return !iter->second->exited; } void unsuspend_task(EVENT_MSG *msg) { if (current_task_inst) return; msg_queue.push({msg, current_task_inst}); flush_message_queue(); } void task_sleep(void) { if (current_task_inst) { switch_to_task(NULL); } else { auto now = std::chrono::system_clock::now(); for (auto &[id, task]: task_list) { if (task->_wake_up_after < now && task->wake_up_msg == -1) { switch_to_task(task.get()); } } clean_task_table(); } } EVENT_MSG *task_wait_event(int32_t event_number) { if (current_task_inst == NULL || current_task_inst->request_exit || current_task_inst->exited) return NULL; current_task_inst->wake_up_msg = event_number; switch_to_task(NULL); return cur_message; } int q_any_task() { return task_list.size(); } char task_quitmsg() { if (current_task_inst == NULL) return 0; return current_task_inst->request_exit?1:0; } void term_task_wait(int id_num) { term_task(id_num); while (is_running(id_num)) { task_sleep(); } } char q_is_mastertask() { return current_task_inst == NULL; } int q_current_task() { return current_task_inst?current_task_inst->id:-1; } void task_sleep_for(unsigned int time_ms) { if (current_task_inst) { current_task_inst->_wake_up_after = std::chrono::system_clock::now() + std::chrono::milliseconds(time_ms); } }