现在我们从st_init函数开始看起,
首先,它初始化了一个内部的事件系统,
1、通过st_set_eventsys,设置了一个全局变量_st_eventsys,而我们一般都使用epoll,所以这个对象指向了_st_epoll_eventsys;
static _st_eventsys_t _st_epoll_eventsys = {
"epoll",
ST_EVENTSYS_ALT,
_st_epoll_init,
_st_epoll_dispatch,
_st_epoll_pollset_add,
_st_epoll_pollset_del,
_st_epoll_fd_new,
_st_epoll_fd_close,
_st_epoll_fd_getlimit
};
2、接着调用_st_io_init:忽略SIGPIPE信号,获取系统打开文件最大限制,存入全局变量_st_osfd_limit中;
3、初始化_st_this_vp全局变量,并初始化其run_q,io_q,zombie_q链表【也就是协程链表,使用了C语言的通用列表方式,我们就不深究通用链表的设计,要了解查看其它相关资料即可】
4、调用:(*_st_eventsys->init)(),初始化事件系统,也就是_st_epoll_init;
它主要初始化了_st_epoll_data全局变量,这个变量主要包括:
epfd:epoll句柄;
fd_hint:epoll的最大文件数量
fd_data_size:等于fd_hint;
fd_data:初始化未一个fd_data_size大小的数组,每个数组元素里面存着当前文件句柄的读引用数量,写引用数量,执行引用数量及当前文件句柄存着的事件【相当于记录了文件句柄的状态信息】
evtlist_size:等于fd_hint;
evtlist:就是epoll_event结构的数组,数组大小也就是fd_data_size了;
5、
_st_this_vp.pagesize = getpagesize();//设置一个内存页的大小
_st_this_vp.last_clock = st_utime();//设置上次时钟
6、初始化idle协程
_st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0);
st_thread_create:
a、首先创建一个栈使用的内存,通过_st_stack_new返回一个_st_stack_t对象:
typedef struct _st_stack {
_st_clist_t links;
char vaddr; / Base of stack's allocated memory /
int vaddr_size; / Size of stack's allocated memory /
int stk_size; / Size of usable portion of the stack */
char stk_bottom; / Lowest address of stack's usable portion */
char stk_top; / Highest address of stack's usable portion */
void sp; / Stack pointer from C's point of view */
ifdef ia64
void bsp; / Register stack backing store pointer */
endif
} _st_stack_t;
栈大小一般为64kB或者128kB,根据系统不同而有所差异,这里的vaddr就是通过malloc出来的栈空间,一般上就是通过malloc来分配的空间;而stk_bottom会跳过一个REDZONE区域,应该是为了避免栈间冲突之类的设计吧,把栈底一部分空间不用;另外,为了高效分配,会为空闲的栈做一个空闲链表,应该是协程销毁就归还到空闲链表里面吧;
b、初始化好栈后,将sp指针初始化指向栈的中间位置;bsp也指向那里,然后bsp又做了下对齐,并上移了4095字节,好像是为了和下面一半空间有段空白间隔;然后栈的下半部分:sp = sp - (ST_KEYS_MAX * sizeof(void ));,预留16个void的空间【ptds = (void *) sp;】真讨厌这种缩写,完全看不出ptds什么意思,好像是16个void都是存的私有数据,所以这里要指向下;然后
sp = sp - sizeof(_st_thread_t);
thread = (_st_thread_t *) sp;,预留_st_thread_t的存储空间;
接下来sp又做了64字节对齐,并且空出来4095字节:stack->sp = sp - _ST_STACK_PAD_SIZE;
接着,初始化:
memset(thread, 0, sizeof(_st_thread_t));
memset(ptds, 0, ST_KEYS_MAX * sizeof(void *));
thread->private_data = ptds;//好吧,ptds,private data,实在让人想不通为什么不在前面命名直接叫private_data_arr之类的;
thread->stack = stack;//栈
thread->start = start;//协程开始函数
thread->arg = arg;//参数
c、栈就初始化好了,根据英文注解:
/*
- The stack segment is split in the middle. The upper half is used
- as backing store for the register stack which grows upward.
- The lower half is used for the traditional memory stack which
- grows downward. Both stacks start in the middle and grow outward
- from each other.
*/
stack内存段被一分为二,上半部分用作注册栈bsp(什么意思?),下半部分用作普通的内存栈,也就是C语言用的栈;
7、将idle_thread从run_q中剔除,然后创建一个叫“基础的”线程:
thread = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + (ST_KEYS_MAX * sizeof(void *)));
if (!thread)
return -1;
thread->private_data = (void **) (thread + 1);//刚好指向ST_KEYS_MAX的 dif
thread->state = _ST_ST_RUNNING;
thread->flags = _ST_FL_PRIMORDIAL;
_ST_SET_CURRENT_THREAD(thread);
_st_active_count++;
又创建了一个没有start(函数地址)的线程?这是干嘛?
然后就返回0了;
至此st_init完成;
网友评论