摘要:
本文深入源码,详细分析Contiki启动一个进程的过程。先是总结了process_start()都做了些什么事,进而跟踪代码进行详细分析。
引言
process_start函数用于启动一个进程,将进程加入进程链表(事先验证参数,确保进程不在进程链表中),初始化进程(将进程状态设为运行状态及lc设为0)。给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行(事先参数验证,确保进程已被设为运行态并且进程的函数指针thread不为空),事实上是执行进程结构体中的thread函数指针所指的函数,而这恰恰是PROCESS_THREAD(name, ev, data)函数的实现。判断执行结果,如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出,否则进程被挂起,等待事件。
理解系统最好的方法就是阅读源码,分享Linus的一句话,接下来跟踪代码详细分析Contiki系统是如何启动一个进程的。
- Read the Fucking Source Code --Linus Torvalds
整个调用过程如下:
- process_start——>process_post_synch——>call_process——>exit_process
一、process_start函数
将进程加入进程链表(事先验证参数,确保进程不在进程链表中),初始化进程(将进程状态设为运行状态及lc设为0)。给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行。
- /*******启动一个进程********/
-
void process_start(struct process *p, const char *arg) //可以传递arg给进程p,也可以不传,直接“NULL”
-
{
-
struct process *q;
-
/*参数验证:确保进程不在进程链表中*/
-
for(q = process_list; q != p && q != NULL; q = q->next);
-
if(q == p)
-
{
-
return;
-
}
-
/*把进程加到进程链表首部*/
-
p->next = process_list;
-
process_list = p;
-
-
p->state = PROCESS_STATE_RUNNING;
-
PT_INIT(&p->pt); //将p->pt->lc设为0,使得进程从case 0开始执行
-
-
PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));
-
-
//给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行
-
process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
-
}
二、process_post_synch函数
process_post_synch()直接调用call_process(),期间需要保存process_corrent,这是因为当调用call_process执行这个进程p时,process_current就会指向当前进程p,而进程p可能会退出或者被挂起等待一个事件[1]。
- //process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
-
void process_post_synch(struct process *p, process_event_t ev, process_data_t data) //typedef void * process_data_t;
-
{
-
struct process *caller = process_current; //相当于PUSH,保存现场process_current
-
-
call_process(p, ev, data);
-
-
process_current = caller; //相当于POP,恢复现场process_current
-
}
三、call_process函数
如果进程process的状态为PROCESS_STATE_RUNNING,并且进程中的thread函数指针(相当于该进程的主函数)不为空的话,就执行该进程。如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出,否则进程被挂起,等待事件。
- //call_process(p, PROCESS_EVENT_INIT, (process_data_t)arg);
-
static void call_process(struct process *p, process_event_t ev, process_data_t data)
-
{
-
int ret;
-
-
#if DEBUG
-
if(p->state == PROCESS_STATE_CALLED)
-
{
-
printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev);
-
}
-
#endif /* DEBUG */
-
-
if((p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) //thread是函数指针
-
{
-
PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);
-
process_current = p;
-
p->state = PROCESS_STATE_CALLED;
-
ret = p->thread(&p->pt, ev, data); //才真正执行PROCESS_THREAD(name, ev, data)定义的内容
-
if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT)
-
{
-
exit_process(p, p); //如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出
-
} else
-
{
-
p->state = PROCESS_STATE_RUNNING; //进程挂起等待事件
-
}
-
}
-
}
PT四种状态
- #define PT_WAITING 0 /*被阻塞,等待事件发生*/
-
#define PT_YIELDED 1 /*主动让出*/
-
#define PT_EXITED 2 /*退出*/
-
#define PT_ENDED 3 /*结束*/
进程状态
- #define PROCESS_STATE_NONE 0 /*类似于Linux系统的僵尸状态,进程已退出,只是还没从进程链表删除*/
- #define PROCESS_STATE_RUNNING 1 /*进程正在执行*/
- #define PROCESS_STATE_CALLED 2 /*被阻塞,运行?*/
四、exit_process函数
先进行参数验证,确保进程在进程链表中并且不是PROCESS_STATE_NONE状态,向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,让与该进程相关的进程进行相应处理。
用[1]中的一个例子:如果一个程序要退出的话,就会给etimer_process进程发送一个PROCESS_EVENT_EXITED事件,那么收到这个事件之后,etimer_process就会查找timerlist看看哪个timer是与这个进程相关的,就把它从timerlist中清除。
- //struct process *p 指要退出的进程
-
//struct process *fromprocess 指当前的进程 ?
-
//exit_process(p, p)
-
static void exit_process(struct process *p, struct process *fromprocess)
-
{
-
register struct process *q;
-
struct process *old_current = process_current;
-
PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));
-
-
/*参数验证:确保要退出的进程在进程链表中*/
-
for(q = process_list; q != p && q != NULL; q = q->next);
-
if(q == NULL)
-
{
-
return;
-
}
-
if(process_is_running(p)) //return p->state != PROCESS_STATE_NONE;
-
{
-
p->state = PROCESS_STATE_NONE;
-
-
/*向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,使得与该进程相关的进程进行相应处理*/
-
for(q = process_list; q != NULL; q = q->next)
-
{
-
if(p != q)
-
{
-
call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
-
}
-
}
-
-
if(p->thread != NULL && p != fromprocess) /*退出的进程不是当前进程*/
-
{
-
/* Post the exit event to the process that is about to exit. */
-
process_current = p;
-
p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL); //给进程p传递一个PROCESS_EVENT_EXIT事件,通常用于退出死循环(如PROCESS_WAIT_EVENT函数),从而使其从主体函数退出
-
}
-
}
-
-
/*将进程p从进程链表删除*/
-
if(p == process_list) //进程p恰好在进程链表首部
-
{
-
process_list = process_list->next;
-
}
-
else //进程p不在进程链表首部
-
{
-
for(q = process_list; q != NULL; q = q->next) //遍历进程链表,寻找进程p,删除之
-
{
-
if(q->next == p)
-
{
-
q->next = p->next;
-
break;
-
}
-
}
-
}
-
process_current = old_current;
-
}
PS:本文系阅读源码、论坛资料、官方资料的个人见解,如有错误的地方,烦请您指出,也欢迎交流Jelline@126.com。
参考资料:
[1]贴子《》
阅读(8976) | 评论(2) | 转发(3) |