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;//真正的时间点
};