本文深入源码,详细分析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

1. 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);
}

2. process_post_synch函数

process_post_synch()直接调用call_process(),期间需要保存process_current,这是因为当调用call_process执行这个进程p时,process_current就会指向当前进程p,而进程p可能会退出或者被挂起等待一个事件。

//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
}

3. 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  /*进程被调用,运行状态*/

4. exit_process函数

先进行参数验证,确保进程在进程链表中并且不是PROCESS_STATE_NONE状态,向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,让与该进程相关的进程进行相应处理。

如果一个程序要退出的话,就会给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;
}
本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-21 09:05

results matching ""

    No results matching ""