f-stack/app/micro_thread/micro_thread.h

548 lines
14 KiB
C++

/**
* 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.h
* @info micro thread manager
*/
#ifndef ___MICRO_THREAD_H__
#define ___MICRO_THREAD_H__
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/queue.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <set>
#include <vector>
#include <queue>
#include "heap.h"
#include "kqueue_proxy.h"
#include "heap_timer.h"
using std::vector;
using std::set;
using std::queue;
namespace NS_MICRO_THREAD {
#define STACK_PAD_SIZE 128
#define MEM_PAGE_SIZE 4096
#define DEFAULT_STACK_SIZE 128*1024
#define DEFAULT_THREAD_NUM 2000
typedef unsigned long long utime64_t;
typedef void (*ThreadStart)(void*);
class ScheduleObj
{
public:
static ScheduleObj* Instance (void);
utime64_t ScheduleGetTime(void);
void ScheduleThread(void);
void ScheduleSleep(void);
void SchedulePend(void);
void ScheduleUnpend(void* thread);
void ScheduleReclaim(void);
void ScheduleStartRun(void);
private:
static ScheduleObj* _instance;
};
struct MtStack
{
int _stk_size;
int _vaddr_size;
char *_vaddr;
void *_esp;
char *_stk_bottom;
char *_stk_top;
void *_private;
int valgrind_id;
};
class Thread : public HeapEntry
{
public:
explicit Thread(int stack_size = 0);
virtual ~Thread(){};
virtual void Run(void){};
bool Initial(void);
void Destroy(void);
void Reset(void);
void sleep(int ms);
void Wait();
void SwitchContext(void);
void RestoreContext(void);
utime64_t GetWakeupTime(void) {
return _wakeup_time;
};
void SetWakeupTime(utime64_t waketime) {
_wakeup_time = waketime;
};
void SetPrivate(void *data)
{
_stack->_private = data;
}
void* GetPrivate()
{
return _stack->_private;
}
bool CheckStackHealth(char *esp);
protected:
virtual void CleanState(void){};
virtual bool InitStack(void);
virtual void FreeStack(void);
virtual void InitContext(void);
private:
MtStack* _stack;
jmp_buf _jmpbuf;
int _stack_size;
utime64_t _wakeup_time;
};
class MicroThread : public Thread
{
public:
enum ThreadType
{
NORMAL = 0, ///< normal thread, no dynamic allocated stack infomations.
PRIMORDIAL = 1, ///< primordial thread, created when frame initialized.
DAEMON = 2, ///< daemon thread, IO event management and scheduling trigger.
SUB_THREAD = 3, ///< sub thread, run simple task.
};
enum ThreadFlag
{
NOT_INLIST = 0x0,
FREE_LIST = 0x1,
IO_LIST = 0x2,
SLEEP_LIST = 0x4,
RUN_LIST = 0x8,
PEND_LIST = 0x10,
SUB_LIST = 0x20,
};
enum ThreadState
{
INITIAL = 0,
RUNABLE = 1,
RUNNING = 2,
SLEEPING = 3,
PENDING = 4,
};
typedef TAILQ_ENTRY(MicroThread) ThreadLink;
typedef TAILQ_HEAD(__ThreadSubTailq, MicroThread) SubThreadList;
public:
MicroThread(ThreadType type = NORMAL);
~MicroThread(){};
ThreadLink _entry;
ThreadLink _sub_entry;
virtual utime64_t HeapValue() {
return GetWakeupTime();
};
virtual void Run(void);
void ClearAllFd(void) {
TAILQ_INIT(&_fdset);
};
void AddFd(KqueuerObj* efpd) {
TAILQ_INSERT_TAIL(&_fdset, efpd, _entry);
};
void AddFdList(KqObjList* fdset) {
TAILQ_CONCAT(&_fdset, fdset, _entry);
};
KqObjList& GetFdSet(void) {
return _fdset;
};
void SetType(ThreadType type) {
_type = type;
};
ThreadType GetType(void) {
return _type;
};
bool IsDaemon(void) {
return (DAEMON == _type);
};
bool IsPrimo(void) {
return (PRIMORDIAL == _type);
};
bool IsSubThread(void) {
return (SUB_THREAD == _type);
};
void SetParent(MicroThread* parent) {
_parent = parent;
};
MicroThread* GetParent() {
return _parent;
};
void WakeupParent();
void AddSubThread(MicroThread* sub);
void RemoveSubThread(MicroThread* sub);
bool HasNoSubThread();
void SetState(ThreadState state) {
_state = state;
};
ThreadState GetState(void) {
return _state;
}
void SetFlag(ThreadFlag flag) {
_flag = (ThreadFlag)(_flag | flag);
};
void UnsetFlag(ThreadFlag flag) {
_flag = (ThreadFlag)(_flag & ~flag);
};
bool HasFlag(ThreadFlag flag) {
return _flag & flag;
};
ThreadFlag GetFlag() {
return _flag;
};
void SetSartFunc(ThreadStart func, void* args) {
_start = func;
_args = args;
};
void* GetThreadArgs() {
return _args;
}
protected:
virtual void CleanState(void);
private:
ThreadState _state;
ThreadType _type;
ThreadFlag _flag;
KqObjList _fdset;
SubThreadList _sub_list;
MicroThread* _parent;
ThreadStart _start;
void* _args;
};
typedef std::set<MicroThread*> ThreadSet;
typedef std::queue<MicroThread*> ThreadList;
class LogAdapter
{
public:
LogAdapter(){};
virtual ~LogAdapter(){};
virtual bool CheckDebug(){ return true;};
virtual bool CheckTrace(){ return true;};
virtual bool CheckError(){ return true;};
virtual void LogDebug(char* fmt, ...){};
virtual void LogTrace(char* fmt, ...){};
virtual void LogError(char* fmt, ...){};
virtual void AttrReportAdd(int attr, int iValue){};
virtual void AttrReportSet(int attr, int iValue){};
};
class ThreadPool
{
public:
static unsigned int default_thread_num;
static unsigned int default_stack_size;
static void SetDefaultThreadNum(unsigned int num) {
default_thread_num = num;
};
static void SetDefaultStackSize(unsigned int size) {
default_stack_size = (size + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE * MEM_PAGE_SIZE;
};
bool InitialPool(int max_num);
void DestroyPool (void);
MicroThread* AllocThread(void);
void FreeThread(MicroThread* thread);
int GetUsedNum(void);
private:
ThreadList _freelist;
int _total_num;
int _use_num;
int _max_num;
};
typedef TAILQ_HEAD(__ThreadTailq, MicroThread) ThreadTailq;
class MtFrame : public KqueueProxy, public ThreadPool
{
private:
static MtFrame* _instance;
LogAdapter* _log_adpt;
ThreadList _runlist;
ThreadTailq _iolist;
ThreadTailq _pend_list;
HeapList _sleeplist;
MicroThread* _daemon;
MicroThread* _primo;
MicroThread* _curr_thread;
utime64_t _last_clock;
int _waitnum;
CTimerMng* _timer;
int _realtime;
public:
friend class ScheduleObj;
public:
static MtFrame* Instance (void);
static int sendto(int fd, const void *msg, int len, int flags, const struct sockaddr *to, int tolen, int timeout);
static int recvfrom(int fd, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, int timeout);
static int connect(int fd, const struct sockaddr *addr, int addrlen, int timeout);
static int accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int timeout);
static ssize_t read(int fd, void *buf, size_t nbyte, int timeout);
static ssize_t write(int fd, const void *buf, size_t nbyte, int timeout);
static int recv(int fd, void *buf, int len, int flags, int timeout);
static ssize_t send(int fd, const void *buf, size_t nbyte, int flags, int timeout);
static void sleep(int ms);
static int WaitEvents(int fd, int events, int timeout);
static MicroThread* CreateThread(ThreadStart entry, void *args, bool runable = true);
static void DaemonRun(void* args);
static int Loop(void* args);
MicroThread *GetRootThread();
bool InitFrame(LogAdapter* logadpt = NULL, int max_thread_num = 50000);
void SetHookFlag();
void Destroy (void);
char* Version(void);
utime64_t GetLastClock(void) {
if(_realtime)
{
return GetSystemMS();
}
return _last_clock;
};
MicroThread* GetActiveThread(void) {
return _curr_thread;
};
int RunWaitNum(void) {
return _waitnum;
};
LogAdapter* GetLogAdpt(void) {
return _log_adpt;
};
CTimerMng* GetTimerMng(void) {
return _timer;
};
virtual int KqueueGetTimeout(void);
virtual bool KqueueSchedule(KqObjList* fdlist, KqueuerObj* fd, int timeout);
void WaitNotify(utime64_t timeout);
void RemoveIoWait(MicroThread* thread);
void InsertRunable(MicroThread* thread);
void InsertPend(MicroThread* thread);
void RemovePend(MicroThread* thread);
void SetRealTime(int realtime_)
{
_realtime =realtime_;
}
private:
MtFrame():_realtime(1){ _curr_thread = NULL; };
MicroThread* DaemonThread(void){
return _daemon;
};
void ThreadSchdule(void);
void CheckExpired();
void WakeupTimeout(void);
void SetLastClock(utime64_t clock) {
_last_clock = clock;
};
void SetActiveThread(MicroThread* thread) {
_curr_thread = thread;
};
utime64_t GetSystemMS(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL);
};
void InsertSleep(MicroThread* thread);
void RemoveSleep(MicroThread* thread);
void InsertIoWait(MicroThread* thread);
void RemoveRunable(MicroThread* thread);
};
#define MTLOG_DEBUG(fmt, args...) \
do { \
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckDebug()) \
{ \
fm->GetLogAdpt()->LogDebug((char*)"[%-10s][%-4d][%-10s]"fmt, \
__FILE__, __LINE__, __FUNCTION__, ##args); \
} \
} while (0)
#define MTLOG_TRACE(fmt, args...) \
do { \
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckTrace()) \
{ \
fm->GetLogAdpt()->LogTrace((char*)"[%-10s][%-4d][%-10s]"fmt, \
__FILE__, __LINE__, __FUNCTION__, ##args); \
} \
} while (0)
#define MTLOG_ERROR(fmt, args...) \
do { \
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckError()) \
{ \
fm->GetLogAdpt()->LogError((char*)"[%-10s][%-4d][%-10s]"fmt, \
__FILE__, __LINE__, __FUNCTION__, ##args); \
} \
} while (0)
#define MT_ATTR_API(ATTR, VALUE) \
do { \
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
if (fm && fm->GetLogAdpt()) \
{ \
fm->GetLogAdpt()->AttrReportAdd(ATTR, VALUE); \
} \
} while (0)
#define MT_ATTR_API_SET(ATTR, VALUE) \
do { \
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
if (fm && fm->GetLogAdpt()) \
{ \
fm->GetLogAdpt()->AttrReportSet(ATTR, VALUE); \
} \
} while (0)
}// NAMESPACE NS_MICRO_THREAD
#endif