contiki-main.c 中的process系列函数学习笔记

时间:2023-12-25 19:40:37

说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件。

-------------------------------------------------------------------------------------------------------------------------------------

根据上一个笔记里面添加的printf()语句的打印信息提示,hello world 打印是在执行了

 autostart_start(autostart_processes);

这行代码后才打印的。而我试着将这行代码注释掉,结果hello-world就不再打印了。那么,根据猜测,这个hello-world的打印可能会与process相关。

当然,这只是猜测,一切都还得从代码里来看看。

-------------------------------------------------------------------------------------------------------------------------------------

先看main(){}里面使用到的几个和process相关的函数:

void
process_init(void);

contiki/ ./core/sys/process.c

 void
process_init(void)
{
//./core/sys/process.h: typedef unsigned char process_event_t; lastevent = PROCESS_EVENT_MAX; // static process_event_t lastevent; PROCESS_EVENT_MAX (0x8a) // ./core/sys/process.h:typedef unsigned char process_num_events_t; nevents = fevent = ; // static process_num_events_t nevents, fevent;
#if PROCESS_CONF_STATS
process_maxevents = ;
#endif /* PROCESS_CONF_STATS */
// ./core/sys/process.c:struct process *process_current = NULL;
// ./core/sys/process.c:struct process *process_list = NULL;
process_current = process_list = NULL;
}

这里的变量都是静态全局变量。

1、定义事件  lastevent 、nevents、fevent

2、初始化或者说创建一个任务链表。当然指向了NULL。

<ps:  按说,全局变量蛮占空间的,这对于contiki OS强调的节省资源似乎相悖,为什么呢? google关键字: potothread 机制>

void
process_start(struct process *p, const char *arg);

contiki/ ./core/sys/process.c

  void
process_start(struct process *p, const char *arg)
{
struct process *q; /* First make sure that we don't try to start a process that is already running. */
for(q = process_list; q != p && q != NULL; q = q->next); /* If we found the process on the process list, we bail out. */
if(q == p) {
return;
}
/* Put on the procs list.*/
p->next = process_list;
process_list = p;
p->state = PROCESS_STATE_RUNNING; //#define PROCESS_STATE_RUNNING 1
PT_INIT(&p->pt); // (&p->pt)->lc = 0; struce process {... struct pt {lc_t lc}}; PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p)); /* Post a synchronous initialization event to the process. */
process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
}

这是一个启动一个process的函数。我这里直接写成process,而不会写成进程或者任务什么的。假设一个process  A将要启动

1、先遍历整个process链,看要启动的这个process  A是否已经存在于该链表中,若存在,则直接返回。

2、若process  A并不存在于整个process链中,则将该process A添加到这个链表中。

添加方式是:将process A添加到原来的process 链表的头部;并且将process A的地址作为整个process 链表的新地址。

3、将process A置为运行态 running,并初始化A的   lc   值为 0。  这个   lc   的值似乎很重要,在process切换的时候,它可能将产生作用。

4、执行  process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg); 把初始化事件同步到process中去..   <应该是process链表中?>

void
process_post_synch(struct process *p, process_event_t ev, process_data_t data);

contiki/./core/sys/process.c

  void
process_post_synch(struct process *p, process_event_t ev, process_data_t data)
{
struct process *caller = process_current; call_process(p, ev, data);
process_current = caller;
}

process_current 表示运行状态的process

1、将 process_current 中的东西交给 caller保存。

2、call_process() 将唤醒另外一个process <执行另外一个process>

3、将caller里面保存的东西<地址>重新交还给 process_current 。

上面这三行代码,如果我没有理解错的话---------那么它们干了一件事情,那就是从一个process 切换到另外一个process,然后又切换回来。嗯~~ 有可能,因为这代码是在process_start()函数里面,启动这个process,势必就要停用另外一个process。

static void
call_process(struct process *p, process_event_t ev, process_data_t data);

contiki/./core/sys/process.c

  static void
call_process(struct process *p, process_event_t ev, process_data_t data)
{
int ret;
// #define PROCESS_STATE_RUNNING 1
// 调用 hello_world_process() 返回值为 char
if( (p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) {
process_current = p;
p->state = PROCESS_STATE_CALLED; // process.c:#define PROCESS_STATE_CALLED 2
ret = p->thread(&p->pt, ev, data);
if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT) {
exit_process(p, p);
} else {
p->state = PROCESS_STATE_RUNNING;
}
}
}

仔细看,就干了一件事情:调用我们工程目录下的那个自己实现的钩子函数。

就拿hello-world.c 里面的钩子函数为例:

 PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN(); printf("Hello, world\n"); PROCESS_END();
}

就这个函数,宏展开的话,就是这个:

 static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
{
char PT_YIELD_FLAG = ;
if (PT_YIELD_FLAG) {;}
switch((process_pt) -> lc) {
case :
printf("Hello world!\n");
};
PT_YIELD_FLAG = ;
process_pt->lc = ;
return PT_ENDED;
}

如果是打印"hello world"的话,这里,它就该出现了。而这个钩子函数,在数据结构 struct process{}里面也有体现了。

当然,钩子函数执行完毕,就会退出这个process:

 exit_process(p, p);

然后切换到原来的或者别的process上去。

static void
exit_process(struct process *p, struct process *fromprocess);

contiki/./core/sys/process.c

  static void
exit_process(struct process *p, struct process *fromprocess)
{
register struct process *q;
struct process *old_current = process_current; /* Make sure the process is in the process list before we try to
exit it. */
for(q = process_list; q != p && q != NULL; q = q->next);
if(q == NULL) {
return;
} if(process_is_running(p)) {
/* Process was running */
p->state = PROCESS_STATE_NONE; // #define PROCESS_STATE_NONE 0 /*
* Post a synchronous event to all processes to inform them that
* this process is about to exit. This will allow services to
* deallocate state associated with this process.
*/
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);
}
} if(p == process_list) {
process_list = process_list->next;
} else {
for(q = process_list; q != NULL; q = q->next) {
if(q->next == p) {
q->next = p->next;
break;
}
}
} process_current = old_current;
}

退出process的时候,它会做这一些工作:

1、例行工作---先检查要退出的这个process是否是存在于process链表中,如果不是,那证明搞错了。

2、如果该process依然处于running状态,则必须将该process的状态置为停止状态。

3、然后向整个process链表通告,这个process告别大家了,留下的资源神马的,大伙儿该分就分,该拿就拿。<真是如此吗?难道不是如此吗?>

4、彻底表明,该process running状态是过去时了 <process_current = old_current;> ,下一个process该怎么办就怎么办。

总结: 这个process的退出过程,其实就是一个链表结点销毁的过程。就这么简单。

接下来,看看文章开头遇到的那个函数: autostart_start()。正是因为它,才有了我们的hello-world的打印,必须看看它是怎么实现的。

void
autostart_start(struct process * const processes[]);

contiki/./core/sys/autostart.c

   void
autostart_start(struct process * const processes[])
{
int i;
for(i = ; processes[i] != NULL; ++i) {
process_start(processes[i], NULL);
PRINTF("autostart_start: starting process '%s'\n", processes[i]->name);
}
}

干了一件事情:start 一些 process。而这些process被放进了某一个数组。那么这个可能放许多的process的数组又是何许物也? 看看main()里面是怎么使用它的:

int main()
{
//....
autostart_start(autostart_processes); //......
}

不错,autostart_start() 里的参数是  autostart_processes。 那么这个  autostart_processes又是何方神圣?依据伟大的find命令的查询:

autostart_processes  出现在了 contiki/./core/sys/autostart.h文件中:

  #if AUTOSTART_ENABLE            //  这个可能在Makefile.include 里面以 -D的方式定义了./Makefile.include:    $(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@
#define AUTOSTART_PROCESSES(...) \
struct process * const autostart_processes[] = {__VA_ARGS__, NULL}
#else /* AUTOSTART_ENABLE */
#define AUTOSTART_PROCESSES(...) \
extern int _dummy
#endif /* AUTOSTART_ENABLE */

似曾相识? 再整洁点:

 #if AUTOSTART_ENABLE
#define AUTOSTART_PROCESSES(...) struct process * const autostart_processes[] = {__VA_ARGS__, NULL}
#else
#define AUTOSTART_PROCESSES(...) extern int _dummy
#endif

嗯哼~   不错,autostart_processes 这个东西和宏AUTOSTART_PROCESSES()有关的,而宏AUTOSTART_PROCESSES()出现在了哪里?

 #include "contiki.h"

 #include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN(); printf("Hello, world\n"); PROCESS_END();
}
/*---------------------------------------------------------------------------*/

没错,就是我们自己写的那个 hello-world.c 文件里。

千里一线,说白了,那就是 autostart_start(struct process * const processes[]);这个函数和  AUTOSTART_PROCESSES() 这个宏有关嘛。

AUTOSTART_PROCESSES()这个搞了多少个process,那么autostart_processes 这个数组里就有了多少个process,那么autostart_start()就会挨着start几个process。原来,辛苦半天,它在这里等着。

顺便提一下,还有一个

void
autostart_exit(struct process * const processes[]);

它的实现如下:

   void
autostart_exit(struct process * const processes[])
{
int i; for(i = ; processes[i] != NULL; ++i) {
process_exit(processes[i]);
PRINTF("autostart_exit: stopping process '%s'\n", processes[i]->name);
}
}

对应着前面的 autostart_start()   start了多少个 process,这里就会exit多少个process。因为前面提到一处exit_procee(),而这里是process_exit(),那它们有什么异同呢?

没错,就是一个封装:

  void
process_exit(struct process *p)
{
exit_process(p, PROCESS_CURRENT());
}

总结下吧:  就是把A  B  C  D .. 这些process 放到一个链表中去,然后再从链表中按要求删除---这真够无聊的:但目前为止,许多操作系统似乎都是这么无聊的干着...

好吧,contiki的 process 的皮毛就先学习到这里,后面再继续思考,每个process的切换和销毁,真的就如我上面所说?还是另有途径?