/** * Tencent is pleased to support the open source community by making MSEC available. * * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the GNU General Public License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may * obtain a copy of the License at * * https://opensource.org/licenses/GPL-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ /** * @filename micro_thread.cpp * @info micro thread manager */ #include "mt_version.h" #include "micro_thread.h" #include "mt_net.h" #include "valgrind.h" #include #include "mt_sys_hook.h" #include "ff_hook.h" #include "ff_api.h" using namespace NS_MICRO_THREAD; #define ASSERT(statement) //#define ASSERT(statement) assert(statement) /** * @brief 汇编实现保存上下文函数 * @param jbf jmpbuff数组指针 */ extern "C" int save_context(jmp_buf jbf); /** * @brief 汇编实现恢复上下文函数 * @param jbf jmpbuff数组指针 * @param ret 切回的返回值, 默认1 */ extern "C" void restore_context(jmp_buf jbf, int ret); /** * @brief 汇编实现替换调用栈函数 * @param jbf jmpbuff数组指针 * @param esp 堆栈指针 */ extern "C" void replace_esp(jmp_buf jbf, void* esp); /** * @brief 构造函数, 默认参数栈大小 */ Thread::Thread(int stack_size) { _stack_size = stack_size ? stack_size : ThreadPool::default_stack_size; _wakeup_time = 0; _stack = NULL; memset(&_jmpbuf, 0, sizeof(_jmpbuf)); } /** * @brief LINUX x86/x86_64下的栈申请, 其它架构下需要注意差异 */ bool Thread::InitStack() { if (_stack) { return true; } ///< 栈索引与栈内存分离, 防越界 _stack = (MtStack*)calloc(1, sizeof(MtStack)); if (NULL == _stack) { MTLOG_ERROR("calloc stack failed, size %u", sizeof(MtStack)); return false; } int memsize = MEM_PAGE_SIZE*2 + _stack_size; memsize = (memsize + MEM_PAGE_SIZE - 1)/MEM_PAGE_SIZE*MEM_PAGE_SIZE; static int zero_fd = -1; int mmap_flags = MAP_PRIVATE | MAP_ANON; void* vaddr = mmap(NULL, memsize, PROT_READ | PROT_WRITE, mmap_flags, zero_fd, 0); if (vaddr == (void *)MAP_FAILED) { MTLOG_ERROR("mmap stack failed, size %d", memsize); free(_stack); _stack = NULL; return false; } _stack->_vaddr = (char*)vaddr; _stack->_vaddr_size = memsize; _stack->_stk_size = _stack_size; _stack->_stk_bottom = _stack->_vaddr + MEM_PAGE_SIZE; _stack->_stk_top = _stack->_stk_bottom + _stack->_stk_size; // valgrind support: register stack frame _stack->valgrind_id = VALGRIND_STACK_REGISTER(_stack->_stk_bottom, _stack->_stk_top); _stack->_esp = _stack->_stk_top - STACK_PAD_SIZE; mprotect(_stack->_vaddr, MEM_PAGE_SIZE, PROT_NONE); mprotect(_stack->_stk_top, MEM_PAGE_SIZE, PROT_NONE); return true; } /** * @brief 释放堆栈信息 */ void Thread::FreeStack() { if (!_stack) { return; } munmap(_stack->_vaddr, _stack->_vaddr_size); // valgrind support: deregister stack frame VALGRIND_STACK_DEREGISTER(_stack->valgrind_id); free(_stack); _stack = NULL; } /** * @brief 初始化上下文,设置寄存器,堆栈 */ void Thread::InitContext() { if (save_context(_jmpbuf) != 0) { ScheduleObj::Instance()->ScheduleStartRun(); // 直接调用 this->run? } if (_stack != NULL) { replace_esp(_jmpbuf, _stack->_esp); } } /** * @brief 主动切换, 保存状态, 触发调度 */ void Thread::SwitchContext() { if (save_context(_jmpbuf) == 0) { ScheduleObj::Instance()->ScheduleThread(); } } /** * @brief 恢复上下文, 切换回断点,继续运行 */ void Thread::RestoreContext() { restore_context(_jmpbuf, 1); } /** * @brief 初始化线程,如堆栈与上下文初始化 */ bool Thread::Initial() { if (!InitStack()) { MTLOG_ERROR("init stack failed"); return false; } InitContext(); return true; } /** * @brief 终止线程,如堆栈与上下文释放 */ void Thread::Destroy() { FreeStack(); memset(&_jmpbuf, 0, sizeof(_jmpbuf)); } /** * @brief 线程状态重置, 可复用状态 */ void Thread::Reset() { _wakeup_time = 0; SetPrivate(NULL); InitContext(); CleanState(); } /** * @brief 线程主动进入睡眠, 单位毫秒 * @param ms 睡眠毫秒数 */ void Thread::sleep(int ms) { utime64_t now = ScheduleObj::Instance()->ScheduleGetTime(); _wakeup_time = now + ms; if (save_context(_jmpbuf) == 0) { ScheduleObj::Instance()->ScheduleSleep(); } } /** * @brief 进入阻塞状态, 等待所有子线程结束 */ void Thread::Wait() { if (save_context(_jmpbuf) == 0) { ScheduleObj::Instance()->SchedulePend(); } } /** * @brief 初始化上下文,设置寄存器,堆栈 */ bool Thread::CheckStackHealth(char *esp) { if (!_stack) return false; if (esp > _stack->_stk_bottom && esp < _stack->_stk_top) return true; else return false; } /** * @brief 微线程构造, 默认是普通线程 * @param type 类型, 默认普通 */ MicroThread::MicroThread(ThreadType type) { memset(&_entry, 0, sizeof(_entry)); TAILQ_INIT(&_fdset); TAILQ_INIT(&_sub_list); _flag = NOT_INLIST; _type = type; _state = INITIAL; _start = NULL; _args = NULL; _parent = NULL; } /** * @breif 微线程复用状态清理 */ void MicroThread::CleanState() { TAILQ_INIT(&_fdset); TAILQ_INIT(&_sub_list); _flag = NOT_INLIST; _type = NORMAL; _state = INITIAL; _start = NULL; _args = NULL; _parent = NULL; } /** * @brief 线程的实际工作函数 */ void MicroThread::Run() { if (_start) { _start(_args); } // 二级线程, 触发父线程进入可运行态 if (this->IsSubThread()) { this->WakeupParent(); } ScheduleObj::Instance()->ScheduleReclaim(); ScheduleObj::Instance()->ScheduleThread(); } /** * @brief 二级子线程唤醒父线程处理 */ void MicroThread::WakeupParent() { MicroThread* parent = this->GetParent(); if (parent) { parent->RemoveSubThread(this); if (parent->HasNoSubThread()) { ScheduleObj::Instance()->ScheduleUnpend(parent); } } else { MTLOG_ERROR("Sub thread no parent, error"); } } /** * @brief 是否还有其它的二级子线程 */ bool MicroThread::HasNoSubThread() { return TAILQ_EMPTY(&_sub_list); } /** * @brief 将指定子线程加入二级线程列表 */ void MicroThread::AddSubThread(MicroThread* sub) { ASSERT(!sub->HasFlag(MicroThread::SUB_LIST)); if (!sub->HasFlag(MicroThread::SUB_LIST)) { TAILQ_INSERT_TAIL(&_sub_list, sub, _sub_entry); sub->_parent = this; } sub->SetFlag(MicroThread::SUB_LIST); } /** * @brief 将指定线程移出二级线程列表 */ void MicroThread::RemoveSubThread(MicroThread* sub) { ASSERT(sub->HasFlag(MicroThread::SUB_LIST)); if (sub->HasFlag(MicroThread::SUB_LIST)) { TAILQ_REMOVE(&_sub_list, sub, _sub_entry); sub->_parent = NULL; } sub->UnsetFlag(MicroThread::SUB_LIST); } /** * @brief 单例类访问句柄入口 */ ScheduleObj *ScheduleObj::_instance = NULL; ///< 静态句柄初始化 inline ScheduleObj* ScheduleObj::Instance() { if (NULL == _instance) { _instance = new ScheduleObj(); } return _instance; } /** * @brief 调度其它微线程来运行, 包裹接口 */ void ScheduleObj::ScheduleThread() { MtFrame* frame = MtFrame::Instance(); frame->ThreadSchdule(); } /** * @brief 获取全局的时间戳, 毫秒单位 */ utime64_t ScheduleObj::ScheduleGetTime() { MtFrame* frame = MtFrame::Instance(); if (frame) { return frame->GetLastClock(); } else { MTLOG_ERROR("frame time failed, maybe not init"); return 0; } } /** * @brief 线程调度主动进入sleep状态 */ void ScheduleObj::ScheduleSleep() { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = frame->GetActiveThread(); if ((!frame) || (!thread)) { MTLOG_ERROR("frame and act thread null, %p, %p", frame, thread); return; } frame->InsertSleep(thread); frame->ThreadSchdule(); } /** * @brief 线程调度主动进入pend状态 */ void ScheduleObj::SchedulePend() { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = frame->GetActiveThread(); if ((!frame) || (!thread)) { MTLOG_ERROR("frame and act thread null, %p, %p", frame, thread); return; } frame->InsertPend(thread); frame->ThreadSchdule(); } /** * @brief 线程调度取消pend状态, 外部调度取消 */ void ScheduleObj::ScheduleUnpend(void* pthread) { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = (MicroThread*)pthread; if ((!frame) || (!thread)) { MTLOG_ERROR("frame and act thread null, %p, %p", frame, thread); return; } frame->RemovePend(thread); frame->InsertRunable(thread); } /** * @brief 线程执行完毕后, 回收处理 */ void ScheduleObj::ScheduleReclaim() { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = frame->GetActiveThread(); if ((!frame) || (!thread)) { MTLOG_ERROR("frame and act thread null, %p, %p", frame, thread); return; } frame->FreeThread(thread); } /** * @brief 调度器调度初始执行 */ void ScheduleObj::ScheduleStartRun() { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = frame->GetActiveThread(); if ((!frame) || (!thread)) { MTLOG_ERROR("frame and act thread null, %p, %p", frame, thread); return; } thread->Run(); } /** * @brief 微线程池全局参数初始化 */ unsigned int ThreadPool::default_thread_num = DEFAULT_THREAD_NUM; ///< 默认2000微线程待命 unsigned int ThreadPool::default_stack_size = DEFAULT_STACK_SIZE; ///< 默认128K栈大小 /** * @brief 微线程池初始化 */ bool ThreadPool::InitialPool(int max_num) { MicroThread *thread = NULL; for (unsigned int i = 0; i < default_thread_num; i++) { thread = new MicroThread(); if ((NULL == thread) || (false == thread->Initial())) { MTLOG_ERROR("init pool, thread %p init failed", thread); if (thread) delete thread; continue; } thread->SetFlag(MicroThread::FREE_LIST); _freelist.push(thread); } _total_num = _freelist.size(); _max_num = max_num; _use_num = 0; if (_total_num <= 0) { return false; } else { return true; } } /** * @brief 微线程池反初始化 */ void ThreadPool::DestroyPool() { MicroThread* thread = NULL; while (!_freelist.empty()) { thread = _freelist.front(); _freelist.pop(); thread->Destroy(); delete thread; } _total_num = 0; _use_num = 0; } /** * @brief 微线程分配接口 * @return 微线程对象 */ MicroThread* ThreadPool::AllocThread() { MT_ATTR_API_SET(492069, _total_num); // 微线程池大小 MicroThread* thread = NULL; if (!_freelist.empty()) { thread = _freelist.front(); _freelist.pop(); ASSERT(thread->HasFlag(MicroThread::FREE_LIST)); thread->UnsetFlag(MicroThread::FREE_LIST); _use_num++; return thread; } MT_ATTR_API(320846, 1); // pool no nore if (_total_num >= _max_num) { MT_ATTR_API(361140, 1); // no more quota return NULL; } thread = new MicroThread(); if ((NULL == thread) || (false == thread->Initial())) { MT_ATTR_API(320847, 1); // pool init fail MTLOG_ERROR("thread alloc failed, thread: %p", thread); if (thread) delete thread; return NULL; } _total_num++; _use_num++; return thread; } /** * @brief 微线程释放接口 * @param thread 微线程对象 */ void ThreadPool::FreeThread(MicroThread* thread) { ASSERT(!thread->HasFlag(MicroThread::FREE_LIST)); thread->Reset(); _use_num--; _freelist.push(thread); thread->SetFlag(MicroThread::FREE_LIST); ///< 空闲队列 > default_thread_num, 则释放最老的, 不可以释放当前 unsigned int free_num = _freelist.size(); if ((free_num > default_thread_num) && (free_num > 1)) { thread = _freelist.front(); _freelist.pop(); thread->Destroy(); delete thread; _total_num--; } } int ThreadPool::GetUsedNum(void) { return _use_num; } /** * @brief 微线程框架类, 全局实例获取 */ MtFrame *MtFrame::_instance = NULL; inline MtFrame* MtFrame::Instance () { if (NULL == _instance ) { _instance = new MtFrame(); } return _instance; } /** * @brief HOOK系统api的设置 */ void MtFrame::SetHookFlag() { mt_set_hook_flag(); }; /** * @brief 框架初始化, 默认不带日志运行 */ bool MtFrame::InitFrame(LogAdapter* logadpt, int max_thread_num) { _log_adpt = logadpt; // 设置最大允许的线程数目, 尝试调节epoll监控的fd数目 if ((this->InitKqueue(max_thread_num) < 0) || !this->InitialPool(max_thread_num)) { MTLOG_ERROR("Init epoll or thread pool failed"); this->Destroy(); return false; } // 按需重置堆大小, 放大堆个数为2倍 if (_sleeplist.HeapResize(max_thread_num * 2) < 0) { MTLOG_ERROR("Init heap list failed"); this->Destroy(); return false; } // 定时器管理初始化, 放大堆个数为2倍 _timer = new CTimerMng(max_thread_num * 2); if (NULL == _timer) { MTLOG_ERROR("Init heap timer failed"); this->Destroy(); return false; } // 守护线程单独初始化 _daemon = AllocThread(); if (NULL == _daemon) { MTLOG_ERROR("Alloc daemon thread failed"); this->Destroy(); return false; } _daemon->SetType(MicroThread::DAEMON); _daemon->SetState(MicroThread::RUNABLE); _daemon->SetSartFunc(MtFrame::DaemonRun, this); // 特殊线程, 无需INIT, 不初始化栈, 也无回调注册, 但需要统一调度 _primo = new MicroThread(MicroThread::PRIMORDIAL); if (NULL == _primo) { MTLOG_ERROR("new _primo thread failed"); this->Destroy(); return false; } _primo->SetState(MicroThread::RUNNING); SetActiveThread(_primo); // 更新最新时间戳 _last_clock = GetSystemMS(); TAILQ_INIT(&_iolist); TAILQ_INIT(&_pend_list); //SetHookFlag(); return true; } /** * @brief 框架反初始化 */ void MtFrame::Destroy(void) { if (NULL == _instance ) { return; } if (_primo) { delete _primo; _primo = NULL; } if (_daemon) { FreeThread(_daemon); _daemon = NULL; } TAILQ_INIT(&_iolist); MicroThread* thread = dynamic_cast(_sleeplist.HeapPop()); while (thread) { FreeThread(thread); thread = dynamic_cast(_sleeplist.HeapPop()); } while (!_runlist.empty()) { thread = _runlist.front(); _runlist.pop(); FreeThread(thread); } MicroThread* tmp; TAILQ_FOREACH_SAFE(thread, &_pend_list, _entry, tmp) { TAILQ_REMOVE(&_pend_list, thread, _entry); FreeThread(thread); } if (_timer != NULL) { delete _timer; _timer = NULL; } _instance->DestroyPool(); _instance->TermKqueue(); delete _instance; _instance = NULL; } /** * @brief 微线程框架版本获取 */ char* MtFrame::Version() { return IMT_VERSION; } /** * @brief 微线程创建接口 * @param entry 线程入口函数 * @param args 线程入口参数 * @return 微线程指针, NULL表示失败 */ MicroThread* MtFrame::CreateThread(ThreadStart entry, void *args, bool runable) { MtFrame* mtframe = MtFrame::Instance(); MicroThread* thread = mtframe->AllocThread(); if (NULL == thread) { MTLOG_ERROR("create thread failed"); return NULL; } thread->SetSartFunc(entry, args); if (runable) { mtframe->InsertRunable(thread); } return thread; } int MtFrame::Loop(void* args) { MtFrame* mtframe = MtFrame::Instance(); MicroThread* daemon = mtframe->DaemonThread(); mtframe->KqueueDispatch(); mtframe->SetLastClock(mtframe->GetSystemMS()); mtframe->WakeupTimeout(); mtframe->CheckExpired(); daemon->SwitchContext(); return 0; } /** * @brief 守护线程入口函数, 函数指针要求static类型 * @param args 线程入口参数 */ void MtFrame::DaemonRun(void* args) { /* MtFrame* mtframe = MtFrame::Instance(); MicroThread* daemon = mtframe->DaemonThread(); while (true) { mtframe->KqueueDispatch(); mtframe->SetLastClock(mtframe->GetSystemMS()); mtframe->WakeupTimeout(); mtframe->CheckExpired(); daemon->SwitchContext(); } */ ff_run(MtFrame::Loop, NULL); } /** * @brief 获取当前线程的根线程 */ MicroThread *MtFrame::GetRootThread() { if (NULL == _curr_thread) { return NULL; } MicroThread::ThreadType type = _curr_thread->GetType(); MicroThread *thread = _curr_thread; MicroThread *parent = thread; while (MicroThread::SUB_THREAD == type) { thread = thread->GetParent(); if (!thread) { break; } type = thread->GetType(); parent = thread; } return parent; } /** * @brief 框架调度线程运行 */ void MtFrame::ThreadSchdule() { MicroThread* thread = NULL; MtFrame* mtframe = MtFrame::Instance(); if (mtframe->_runlist.empty()) { thread = mtframe->DaemonThread(); } else { thread = mtframe->_runlist.front(); mtframe->RemoveRunable(thread); } this->SetActiveThread(thread); thread->SetState(MicroThread::RUNNING); thread->RestoreContext(); } /** * @brief 框架处理定时回调函数 */ void MtFrame::CheckExpired() { static utime64_t check_time = 0; if (_timer != NULL) { _timer->check_expired(); } utime64_t now = GetLastClock(); if ((now - check_time) > 1000) { CNetMgr::Instance()->RecycleObjs(now); check_time = now; } } /** * @brief 框架检测到超时, 唤醒所有的超时线程 */ void MtFrame::WakeupTimeout() { utime64_t now = GetLastClock(); MicroThread* thread = dynamic_cast(_sleeplist.HeapTop()); while (thread && (thread->GetWakeupTime() <= now)) { if (thread->HasFlag(MicroThread::IO_LIST)) { RemoveIoWait(thread); } else { RemoveSleep(thread); } InsertRunable(thread); thread = dynamic_cast(_sleeplist.HeapTop()); } } /** * @brief 框架调用epoll wait前, 判定等待时间信息 */ int MtFrame::KqueueGetTimeout() { utime64_t now = GetLastClock(); MicroThread* thread = dynamic_cast(_sleeplist.HeapTop()); if (!thread) { return 10; //默认10ms epollwait } else if (thread->GetWakeupTime() < now) { return 0; } else { return (int)(thread->GetWakeupTime() - now); } } /** * @brief 框架管理线程单元, 插入排序堆 * @param thread 微线程对象 */ inline void MtFrame::InsertSleep(MicroThread* thread) { ASSERT(!thread->HasFlag(MicroThread::SLEEP_LIST)); thread->SetFlag(MicroThread::SLEEP_LIST); thread->SetState(MicroThread::SLEEPING); int rc = _sleeplist.HeapPush(thread); if (rc < 0) { MT_ATTR_API(320848, 1); // heap error MTLOG_ERROR("Insert heap failed , rc %d", rc); } } /** * @brief 框架管理线程单元, 移除排序堆 * @param thread 微线程对象 */ inline void MtFrame::RemoveSleep(MicroThread* thread) { ASSERT(thread->HasFlag(MicroThread::SLEEP_LIST)); thread->UnsetFlag(MicroThread::SLEEP_LIST); int rc = _sleeplist.HeapDelete(thread); if (rc < 0) { MT_ATTR_API(320849, 1); // heap error MTLOG_ERROR("remove heap failed , rc %d", rc); } } /** * @brief 框架管理线程单元, 执行IO等待状态 * @param thread 微线程对象 */ inline void MtFrame::InsertIoWait(MicroThread* thread) { ASSERT(!thread->HasFlag(MicroThread::IO_LIST)); thread->SetFlag(MicroThread::IO_LIST); TAILQ_INSERT_TAIL(&_iolist, thread, _entry); InsertSleep(thread); } /** * @brief 框架管理线程单元, 移除IO等待状态 * @param thread 微线程对象 */ void MtFrame::RemoveIoWait(MicroThread* thread) { ASSERT(thread->HasFlag(MicroThread::IO_LIST)); thread->UnsetFlag(MicroThread::IO_LIST); TAILQ_REMOVE(&_iolist, thread, _entry); RemoveSleep(thread); } /** * @brief 框架管理线程单元, 插入可运行队列 * @param thread 微线程对象 */ void MtFrame::InsertRunable(MicroThread* thread) { ASSERT(!thread->HasFlag(MicroThread::RUN_LIST)); thread->SetFlag(MicroThread::RUN_LIST); thread->SetState(MicroThread::RUNABLE); _runlist.push(thread); _waitnum++; } /** * @brief 框架管理线程单元, 移出可运行队列 * @param thread 微线程对象 */ inline void MtFrame::RemoveRunable(MicroThread* thread) { ASSERT(thread->HasFlag(MicroThread::RUN_LIST)); ASSERT(thread == _runlist.front()); thread->UnsetFlag(MicroThread::RUN_LIST); _runlist.pop(); _waitnum--; } /** * @brief 框架管理线程单元, 执行pend等待状态 * @param thread 微线程对象 */ void MtFrame::InsertPend(MicroThread* thread) { ASSERT(!thread->HasFlag(MicroThread::PEND_LIST)); thread->SetFlag(MicroThread::PEND_LIST); TAILQ_INSERT_TAIL(&_pend_list, thread, _entry); thread->SetState(MicroThread::PENDING); } /** * @brief 框架管理线程单元, 移除PEND等待状态 * @param thread 微线程对象 */ void MtFrame::RemovePend(MicroThread* thread) { ASSERT(thread->HasFlag(MicroThread::PEND_LIST)); thread->UnsetFlag(MicroThread::PEND_LIST); TAILQ_REMOVE(&_pend_list, thread, _entry); } /** * @brief 微线程主动切换, 等待其它线程的唤醒 * @param timeout 最长等待时间, 毫秒 */ void MtFrame::WaitNotify(utime64_t timeout) { MicroThread* thread = GetActiveThread(); thread->SetWakeupTime(timeout + this->GetLastClock()); this->InsertIoWait(thread); thread->SwitchContext(); } /** * @brief 微线程触发切换函数,调用成功 则让出cpu * @param fdlist 多路并发的socket列表 * @param fd 单个请求的fd信息 * @param timeout 最长等待时间, 毫秒 * @return true 成功, false 失败 */ bool MtFrame::KqueueSchedule(KqObjList* fdlist, KqueuerObj* fd, int timeout) { MicroThread* thread = GetActiveThread(); if (NULL == thread) { MTLOG_ERROR("active thread null, epoll schedule failed"); return false; } // 1. 整合该线程需要关心的epoll调度对象 thread->ClearAllFd(); if (fdlist) { thread->AddFdList(fdlist); } if (fd) { thread->AddFd(fd); } // 2. 设置epoll监听事件, 调整超时时间, 切换IO等待状态, 触发切换 thread->SetWakeupTime(timeout + this->GetLastClock()); if (!this->KqueueAdd(thread->GetFdSet())) { MTLOG_ERROR("epoll add failed, errno: %d", errno); return false; } this->InsertIoWait(thread); thread->SwitchContext(); // 3. 调度OK, 判定超时, epoll ctrl 还原状态 int rcvnum = 0; KqObjList& rcvfds = thread->GetFdSet(); KqueuerObj* fdata = NULL; TAILQ_FOREACH(fdata, &rcvfds, _entry) { if (fdata->GetRcvEvents() != 0) { rcvnum++; } } this->KqueueDel(rcvfds); // 在一个函数中ADD, DEL 闭环控制 if (rcvnum == 0) // 超时处理, 返回错误 { errno = ETIME; return false; } return true; } /** * @brief 微线程包裹的系统IO函数 recvfrom * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param len 接收消息缓冲区长度 * @param from 来源地址的指针 * @param fromlen 来源地址的结构长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ int MtFrame::recvfrom(int fd, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !buf || len<1) { errno = EINVAL; MTLOG_ERROR("recvfrom failed, errno: %d (%m)", errno); return -10; } if (timeout <= -1) { timeout = 0x7fffffff; } while (true) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableInput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { MTLOG_DEBUG("epoll schedule failed, errno: %d", errno); return -2; } mt_hook_syscall(recvfrom); int n = ff_hook_recvfrom(fd, buf, len, flags, from, fromlen); if (n < 0) { if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("recvfrom failed, errno: %d", errno); return -3; } } else { return n; } } } /** * @brief 微线程包裹的系统IO函数 sendto * @param fd 系统socket信息 * @param msg 待发送的消息指针 * @param len 待发送的消息长度 * @param to 目的地址的指针 * @param tolen 目的地址的结构长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ int MtFrame::sendto(int fd, const void *msg, int len, int flags, const struct sockaddr *to, int tolen, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !msg || len<1) { errno = EINVAL; MTLOG_ERROR("sendto failed, errno: %d (%m)", errno); return -10; } int n = 0; mt_hook_syscall(sendto); while ((n = ff_hook_sendto(fd, msg, len, flags, to, tolen)) < 0) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("sendto failed, errno: %d", errno); return -2; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableOutput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return n; } /** * @brief 微线程包裹的系统IO函数 connect * @param fd 系统socket信息 * @param addr 指定server的目的地址 * @param addrlen 地址的长度 * @param timeout 最长等待时间, 毫秒 * @return =0 连接成功, <0 失败 */ int MtFrame::connect(int fd, const struct sockaddr *addr, int addrlen, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !addr || addrlen<1) { errno = EINVAL; MTLOG_ERROR("connect failed, errno: %d (%m)", errno); return -10; } int n = 0; mt_hook_syscall(connect); while ((n = ff_hook_connect(fd, addr, addrlen)) < 0) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } if (errno == EISCONN) // 已连接, 返回成功 { return 0; } if (errno == EINTR) { continue; } if (errno != EINPROGRESS) { MTLOG_ERROR("connect failed, errno: %d", errno); return -2; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableOutput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return n; } /** * @brief 微线程包裹的系统IO函数 accept * @param fd 监听套接字 * @param addr 客户端地址 * @param addrlen 地址的长度 * @param timeout 最长等待时间, 毫秒 * @return >=0 accept的socket描述符, <0 失败 */ int MtFrame::accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0) { errno = EINVAL; MTLOG_ERROR("accept failed, errno: %d (%m)", errno); return -10; } int acceptfd = 0; mt_hook_syscall(accept); while ((acceptfd = ff_hook_accept(fd, addr, addrlen)) < 0) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } if (errno == EINTR) { continue; } if (!((errno == EAGAIN) || (errno == EWOULDBLOCK))) { MTLOG_ERROR("accept failed, errno: %d", errno); return -2; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableInput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return acceptfd; } /** * @brief 微线程包裹的系统IO函数 read * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param nbyte 接收消息缓冲区长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ ssize_t MtFrame::read(int fd, void *buf, size_t nbyte, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !buf || nbyte<1) { errno = EINVAL; MTLOG_ERROR("read failed, errno: %d (%m)", errno); return -10; } ssize_t n = 0; mt_hook_syscall(read); while ((n = ff_hook_read(fd, buf, nbyte)) < 0) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("read failed, errno: %d", errno); return -2; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableInput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return n; } /** * @brief 微线程包裹的系统IO函数 write * @param fd 系统socket信息 * @param buf 待发送的消息指针 * @param nbyte 待发送的消息长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ ssize_t MtFrame::write(int fd, const void *buf, size_t nbyte, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !buf || nbyte<1) { errno = EINVAL; MTLOG_ERROR("write failed, errno: %d (%m)", errno); return -10; } ssize_t n = 0; size_t send_len = 0; while (send_len < nbyte) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } mt_hook_syscall(write); n = ff_hook_write(fd, (char*)buf + send_len, nbyte - send_len); if (n < 0) { if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("write failed, errno: %d", errno); return -2; } } else { send_len += n; if (send_len >= nbyte) { return nbyte; } } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableOutput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return nbyte; } /** * @brief 微线程包裹的系统IO函数 recv * @param fd 系统socket信息 * @param buf 接收消息缓冲区指针 * @param len 接收消息缓冲区长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ int MtFrame::recv(int fd, void *buf, int len, int flags, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !buf || len<1) { errno = EINVAL; MTLOG_ERROR("recv failed, errno: %d (%m)", errno); return -10; } if (timeout <= -1) { timeout = 0x7fffffff; } while (true) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableInput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { MTLOG_DEBUG("epoll schedule failed, errno: %d", errno); return -2; } mt_hook_syscall(recv); int n = ff_hook_recv(fd, buf, len, flags); if (n < 0) { if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("recv failed, errno: %d", errno); return -3; } } else { return n; } } } /** * @brief 微线程包裹的系统IO函数 send * @param fd 系统socket信息 * @param buf 待发送的消息指针 * @param nbyte 待发送的消息长度 * @param timeout 最长等待时间, 毫秒 * @return >0 成功发送长度, <0 失败 */ ssize_t MtFrame::send(int fd, const void *buf, size_t nbyte, int flags, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if(fd<0 || !buf || nbyte<1) { errno = EINVAL; MTLOG_ERROR("send failed, errno: %d (%m)", errno); return -10; } ssize_t n = 0; size_t send_len = 0; while (send_len < nbyte) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return -1; } mt_hook_syscall(send); n = ff_hook_send(fd, (char*)buf + send_len, nbyte - send_len, flags); if (n < 0) { if (errno == EINTR) { continue; } if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { MTLOG_ERROR("write failed, errno: %d", errno); return -2; } } else { send_len += n; if (send_len >= nbyte) { return nbyte; } } KqueuerObj epfd; epfd.SetOsfd(fd); epfd.EnableOutput(); epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { return -3; } } return nbyte; } /** * @brief 微线程主动sleep接口, 单位ms */ void MtFrame::sleep(int ms) { MtFrame* frame = MtFrame::Instance(); MicroThread* thread = frame->GetActiveThread(); if (thread != NULL) { thread->sleep(ms); } } /** * @brief 微线程包裹的系统IO函数 recv * @param fd 系统socket信息 * @param events 事件类型 EPOLLIN or EPOLLOUT * @param timeout 最长等待时间, 毫秒 * @return >0 成功接收长度, <0 失败 */ int MtFrame::WaitEvents(int fd, int events, int timeout) { MtFrame* mtframe = MtFrame::Instance(); utime64_t start = mtframe->GetLastClock(); MicroThread* thread = mtframe->GetActiveThread(); utime64_t now = 0; if (timeout <= -1) { timeout = 0x7fffffff; } while (true) { now = mtframe->GetLastClock(); if ((int)(now - start) > timeout) { errno = ETIME; return 0; } KqueuerObj epfd; epfd.SetOsfd(fd); if (events & KQ_EVENT_READ) { epfd.EnableInput(); } if (events & KQ_EVENT_WRITE) { epfd.EnableOutput(); } epfd.SetOwnerThread(thread); if (!mtframe->KqueueSchedule(NULL, &epfd, timeout)) { MTLOG_TRACE("epoll schedule failed, errno: %d", errno); return 0; } return epfd.GetRcvEvents(); } }