skynet数据结构

327 阅读5分钟

handle模块 主要用来保存ctx及handle 名字

//用来保存名字
struct handle_name {
	char * name;
	uint32_t handle;
};

//用来保存所有ctx 及名字
struct handle_storage {
	struct rwlock lock;

	uint32_t harbor;
	uint32_t handle_index;//下一个可能为空slot的index handle
	int slot_size;
	struct skynet_context ** slot;//存放ctx
	
	int name_cap;//capicity
	int name_count;//数量
	struct handle_name *name; //排序,用二分法查找 
};

module模块 用来保存 c module

struct skynet_module {
	const char * name;//名字
	void * module;//用来存放dlopen的返回的值
	//四个回调
	skynet_dl_create create;
	skynet_dl_init init;
	skynet_dl_release release;
	skynet_dl_signal signal;
};
struct modules {
	int count;//模块的数量
	struct spinlock lock;//这个数据结构的lock
	const char * path;//module放的地方
	struct skynet_module m[MAX_MODULE_TYPE];//最多只能放32个模块
};

monitor模块 用来监控每个线程 数据结构为,每个线程一个数据

struct skynet_monitor {
	ATOM_INT version;//每check一次 inc一次
	int check_version;//五秒之前的version值
	uint32_t source;//trigger的时候的消息源
	uint32_t destination;//trigger的时候的消息目的
};

//可以认为是整个进程的monitor
struct monitor {
	int count;//m的数量 worker进程数
	struct skynet_monitor ** m;// m数组 //不知道为什么要2维
	pthread_cond_t cond;//阻塞worker的cond
	pthread_mutex_t mutex;//与cond配合使用的mutex
	int sleep;//睡的线程数量 感觉sleep等于0或1 因为被lock住了
	int quit;//进程是否退出
};

mq模块 消息结构(从哪来,消息id,数据/长度) 消息队列结构 (环形buf) 全局消息队列结构

struct skynet_message {
	uint32_t source;//消息源server
	int session;//消息id
	void * data;//消息数据
	size_t sz;//消息长度
};

//这个queue是属于某个handle的,即某个服务
struct message_queue {
	struct spinlock lock;//此结构的lock
	uint32_t handle;//可以认为是serverid
	int cap;//应该是 queue的cap
	int head;//回环buf head
	int tail;//回环buf tail
	int release;//此消息是否回收 ? 不懂
	int in_global;//==0代表此queue 可以放到global中去
	int overload;//不知道干嘛,用来判断是否太多消息?
	int overload_threshold;//overload的阈值
	struct skynet_message *queue;//此server 的消息队列
	struct message_queue *next;//global queue的 next指针
};
//公共 队列
struct global_queue {
	struct message_queue *head;
	struct message_queue *tail;
	struct spinlock lock;
};

context 模块 skynet_context主要由 module 数据 ,消息队列,统计信息组成

struct skynet_context {
	void * instance;//由module的 create返回的指针
	struct skynet_module * mod;//模块
	void * cb_ud;//skynet_cb 函数中所用到的cb_ud
	skynet_cb cb;//回调函数
	struct message_queue *queue;//此ctx 对应的消息列表
	ATOM_POINTER logfile;//啥?
	uint64_t cpu_cost;	// in microsec 统计
	uint64_t cpu_start;	// in microsec 统计
	char result[32];//当在使用 cmd_stat的时候,所产生的结果,存放在这里
	uint32_t handle;//唯一id
	int session_id;//会话id 是用来自增的 当此ctx产生一个 会话时,会话id由此产生
	ATOM_INT ref;//指针引用
	int message_count;//似乎是统计,只用来记录一下处理过的消息数量而已
	bool init;//是否已经初始化
	bool endless;//是否一直在处理中
	bool profile;//是否进行profile 是就对 cpu_cost/cpu_start 进行设置

	CHECKCALLING_DECL
};

struct skynet_node {//此进程的节点
	ATOM_INT total;//ctx的数量
	int init;//此结构是否已初始化
	uint32_t monitor_exit;//观察ctx退出的server
	pthread_key_t handle_key;//用来保存每个线程当前的handle值
	bool profile;	// 用来设置 skynet_context的profile
};

socket模块

struct socket_message {
	int id;//id是用来标记socket所在的server的
	uintptr_t opaque;//opaque 是啥
	int ud;	// for accept, ud is new connection id ; for data, ud is size of data
	char * data;
};
//不知道为什么跟下面那个不一起用

#define SKYNET_SOCKET_TYPE_DATA 1
#define SKYNET_SOCKET_TYPE_CONNECT 2
#define SKYNET_SOCKET_TYPE_CLOSE 3
#define SKYNET_SOCKET_TYPE_ACCEPT 4
#define SKYNET_SOCKET_TYPE_ERROR 5
#define SKYNET_SOCKET_TYPE_UDP 6
#define SKYNET_SOCKET_TYPE_WARNING 7
struct skynet_socket_message {
	int type;//对应上面的宏
	int id;//对应此消息socket对应的server
	int ud;//accept 是 new connection id, 数据时是data的size
	char * buffer;//数据
};

// 从别的服务 转发过来的buff
// 0:对于malloc 内存块的数据
// 1:udp那种数据包(自带长度 ??
//  2:指针类型:你可以自己用,但不能释放,如果要备份,需要自行拷贝/释放
#define SOCKET_BUFFER_MEMORY 0
#define SOCKET_BUFFER_OBJECT 1
#define SOCKET_BUFFER_RAWPOINTER 2
struct socket_sendbuffer {
	int id;
	int type;
	const void *buffer;
	size_t sz;
};

//这个只是为了给lua层返回一个socket的信息
struct socket_info {
	int id;
	int type;
	uint64_t opaque;
	uint64_t read;
	uint64_t write;
	uint64_t rtime;
	uint64_t wtime;
	int64_t wbuffer;
	uint8_t reading;
	uint8_t writing;
	char name[128];
	struct socket_info *next;
};

//封装epoll event
struct event {
	void * s;//句炳
	bool read;//是否可读
	bool write;//是否可写
	bool error;//是否出错
	bool eof;//是否eof
};

//socket server的数据结构
struct write_buffer {
	struct write_buffer * next;//链表next
	const void *buffer;//不知道是啥
	char *ptr;//data
	size_t sz;//data len
	bool userobject;
	uint8_t udp_address[UDP_ADDRESS_SIZE];
};

#define SIZEOF_TCPBUFFER (offsetof(struct write_buffer, udp_address[0]))
#define SIZEOF_UDPBUFFER (sizeof(struct write_buffer))

struct wb_list {//write_buffer list
	struct write_buffer * head;//队列
	struct write_buffer * tail;
};

struct socket_stat {//socket 统计信息
	uint64_t rtime;
	uint64_t wtime;
	uint64_t read;
	uint64_t write;
};
//只记得一个 high/low
struct socket {//每个socket连接对应的数据结构
	uintptr_t opaque; //bind的worker服务
	struct wb_list high; //send data hight list
	struct wb_list low; //send data low list
	int64_t wb_size; //需要发送的data 的字节数,当大于1M的数据还没有发送时,会有警告
	struct socket_stat stat;//统计信息
	ATOM_ULONG sending;
	int fd;//socket fd
	int id;//ctx id
	ATOM_INT type;//SOCKET_TYPE_XXXXXX
	uint8_t protocol;//PROTO
	bool reading;//缓存住 epollfd 那里,给它设置可读可写等操作
	bool writing;
	bool closing;//当关闭时,会把此值赋为true
	ATOM_INT udpconnecting;//udp connect的数量
	int64_t warn_size;//每次wb_size > warn_size时,会倍增
	union {
		int size;
		uint8_t udp_address[UDP_ADDRESS_SIZE];
	} p;
	struct spinlock dw_lock;//dw是什么意思
	int dw_offset;//不知道干嘛
	const void * dw_buffer;//不知道干嘛
	size_t dw_size;
};
//主要由  pipe文件,socket池,及 epoll_event三部分组成
struct socket_server {
	volatile uint64_t time;
	int recvctrl_fd; //pipe 开的 读fd
	int sendctrl_fd; //别的线程向socket服写数据写fdh
	int checkctrl;//是否需要检查别的线程有没有向socket发送数据
	poll_fd event_fd;//epoll fd
	ATOM_INT alloc_id;//整个socket线程给 socket分配id时用
	int event_n;//epoll的 event 数量
	int event_index;//缓存正在处理的ev下标
	struct socket_object_interface soi;//一个interface 能够 free getdata getdatasize
	struct event ev[MAX_EVENT];//缓存epoll event
	struct socket slot[MAX_SOCKET];//保存所有的socket
	char buffer[MAX_INFO];//128长的buffer,用来保存ip的字符串形式
	uint8_t udpbuffer[MAX_UDP_PACKAGE];//用来缓存udp的buffer ? 好像说不过去
	fd_set rfds;//select用的 如果不用select 那么会block住,那么接收消息,就接不了
};

timer模块 由事件,事件链表,全局时间,三个组成

struct timer_event {
	uint32_t handle;//事件的ctx id
	int session;//事件的 会话id
};

//在申请内存的时候,会额外申请 timer_event 的空间,并把内容赋进去
struct timer_node {
	struct timer_node *next;//链表的next
	uint32_t expire;//当高的level向低的level滑动时,有用
};

struct link_list {
	struct timer_node head;//当空时,tail指向这个 是为了方便不用判空吧
	struct timer_node *tail;
};
//主要由时间及层级事件列表组成
struct timer {
	struct link_list near[TIME_NEAR];//每一帧都会拿到的一个list
	struct link_list t[4][TIME_LEVEL];//然后其它4个level
	struct spinlock lock;//此结构的lock
	uint32_t time;//每帧增1的timer
	uint32_t starttime;//等于os.time()
	uint64_t current;//上一次计算的时间增加diff得到的值 为什么要2个?
	uint64_t current_point;//真正的时间点
};