说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件。
-------------------------------------------------------------------------------------------------------------------------------------
根据上一个笔记里面添加的printf()语句的打印信息提示,hello world 打印是在执行了
1 autostart_start(autostart_processes);
这行代码后才打印的。而我试着将这行代码注释掉,结果hello-world就不再打印了。那么,根据猜测,这个hello-world的打印可能会与process相关。
当然,这只是猜测,一切都还得从代码里来看看。
-------------------------------------------------------------------------------------------------------------------------------------
先看main(){}里面使用到的几个和process相关的函数:
void
process_init(void);
contiki/ ./core/sys/process.c
1 void 2 process_init(void) 3 { 4 //./core/sys/process.h: typedef unsigned char process_event_t; 5 6 lastevent = PROCESS_EVENT_MAX; // static process_event_t lastevent; PROCESS_EVENT_MAX (0x8a) 7 8 // ./core/sys/process.h:typedef unsigned char process_num_events_t; 9 10 nevents = fevent = 0; // static process_num_events_t nevents, fevent; 11 #if PROCESS_CONF_STATS 12 process_maxevents = 0; 13 #endif /* PROCESS_CONF_STATS */ 14 // ./core/sys/process.c:struct process *process_current = NULL; 15 // ./core/sys/process.c:struct process *process_list = NULL; 16 process_current = process_list = NULL; 17 }
这里的变量都是静态全局变量。
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
1 void 2 process_start(struct process *p, const char *arg) 3 { 4 struct process *q; 5 6 /* First make sure that we don't try to start a process that is already running. */ 7 for(q = process_list; q != p && q != NULL; q = q->next); 8 9 /* If we found the process on the process list, we bail out. */ 10 if(q == p) { 11 return; 12 } 13 /* Put on the procs list.*/ 14 p->next = process_list; 15 process_list = p; 16 p->state = PROCESS_STATE_RUNNING; //#define PROCESS_STATE_RUNNING 1 17 PT_INIT(&p->pt); // (&p->pt)->lc = 0; struce process {... struct pt {lc_t lc}}; 18 19 PRINTF("process: starting '%s' ", PROCESS_NAME_STRING(p)); 20 21 /* Post a synchronous initialization event to the process. */ 22 process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg); 23 }
这是一个启动一个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
1 void 2 process_post_synch(struct process *p, process_event_t ev, process_data_t data) 3 { 4 struct process *caller = process_current; 5 6 call_process(p, ev, data); 7 process_current = caller; 8 }
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
1 static void 2 call_process(struct process *p, process_event_t ev, process_data_t data) 3 { 4 int ret; 5 // #define PROCESS_STATE_RUNNING 1 6 // 调用 hello_world_process() 返回值为 char 7 if( (p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) { 8 process_current = p; 9 p->state = PROCESS_STATE_CALLED; // process.c:#define PROCESS_STATE_CALLED 2 10 ret = p->thread(&p->pt, ev, data); 11 if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT) { 12 exit_process(p, p); 13 } else { 14 p->state = PROCESS_STATE_RUNNING; 15 } 16 } 17 }
仔细看,就干了一件事情:调用我们工程目录下的那个自己实现的钩子函数。
就拿hello-world.c 里面的钩子函数为例:
1 PROCESS_THREAD(hello_world_process, ev, data) 2 { 3 PROCESS_BEGIN(); 4 5 printf("Hello, world "); 6 7 PROCESS_END(); 8 }
就这个函数,宏展开的话,就是这个:
1 static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data) 2 { 3 char PT_YIELD_FLAG = 1; 4 if (PT_YIELD_FLAG) {;} 5 switch((process_pt) -> lc) { 6 case 0: 7 printf("Hello world! "); 8 }; 9 PT_YIELD_FLAG = 0; 10 process_pt->lc = 0; 11 return PT_ENDED; 12 }
如果是打印"hello world"的话,这里,它就该出现了。而这个钩子函数,在数据结构 struct process{}里面也有体现了。
当然,钩子函数执行完毕,就会退出这个process:
1 exit_process(p, p);
然后切换到原来的或者别的process上去。
static void
exit_process(struct process *p, struct process *fromprocess);
contiki/./core/sys/process.c
1 static void 2 exit_process(struct process *p, struct process *fromprocess) 3 { 4 register struct process *q; 5 struct process *old_current = process_current; 6 7 /* Make sure the process is in the process list before we try to 8 exit it. */ 9 for(q = process_list; q != p && q != NULL; q = q->next); 10 if(q == NULL) { 11 return; 12 } 13 14 if(process_is_running(p)) { 15 /* Process was running */ 16 p->state = PROCESS_STATE_NONE; // #define PROCESS_STATE_NONE 0 17 18 /* 19 * Post a synchronous event to all processes to inform them that 20 * this process is about to exit. This will allow services to 21 * deallocate state associated with this process. 22 */ 23 for(q = process_list; q != NULL; q = q->next) { 24 if(p != q) { 25 call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p); 26 } 27 } 28 29 if(p->thread != NULL && p != fromprocess) { 30 /* Post the exit event to the process that is about to exit. */ 31 process_current = p; 32 p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL); 33 } 34 } 35 36 if(p == process_list) { 37 process_list = process_list->next; 38 } else { 39 for(q = process_list; q != NULL; q = q->next) { 40 if(q->next == p) { 41 q->next = p->next; 42 break; 43 } 44 } 45 } 46 47 process_current = old_current; 48 }
退出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
1 void 2 autostart_start(struct process * const processes[]) 3 { 4 int i; 5 for(i = 0; processes[i] != NULL; ++i) { 6 process_start(processes[i], NULL); 7 PRINTF("autostart_start: starting process '%s' ", processes[i]->name); 8 } 9 }
干了一件事情: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 */
似曾相识? 再整洁点:
1 #if AUTOSTART_ENABLE 2 #define AUTOSTART_PROCESSES(...) struct process * const autostart_processes[] = {__VA_ARGS__, NULL} 3 #else 4 #define AUTOSTART_PROCESSES(...) extern int _dummy 5 #endif
嗯哼~ 不错,autostart_processes 这个东西和宏AUTOSTART_PROCESSES()有关的,而宏AUTOSTART_PROCESSES()出现在了哪里?
1 #include "contiki.h" 2 3 #include <stdio.h> /* For printf() */ 4 /*---------------------------------------------------------------------------*/ 5 PROCESS(hello_world_process, "Hello world process"); 6 AUTOSTART_PROCESSES(&hello_world_process); 7 /*---------------------------------------------------------------------------*/ 8 PROCESS_THREAD(hello_world_process, ev, data) 9 { 10 PROCESS_BEGIN(); 11 12 printf("Hello, world "); 13 14 PROCESS_END(); 15 } 16 /*---------------------------------------------------------------------------*/
没错,就是我们自己写的那个 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[]);
它的实现如下:
1 void 2 autostart_exit(struct process * const processes[]) 3 { 4 int i; 5 6 for(i = 0; processes[i] != NULL; ++i) { 7 process_exit(processes[i]); 8 PRINTF("autostart_exit: stopping process '%s' ", processes[i]->name); 9 } 10 }
对应着前面的 autostart_start() start了多少个 process,这里就会exit多少个process。因为前面提到一处exit_procee(),而这里是process_exit(),那它们有什么异同呢?
没错,就是一个封装:
1 void 2 process_exit(struct process *p) 3 { 4 exit_process(p, PROCESS_CURRENT()); 5 }
总结下吧: 就是把A B C D .. 这些process 放到一个链表中去,然后再从链表中按要求删除---这真够无聊的:但目前为止,许多操作系统似乎都是这么无聊的干着...
好吧,contiki的 process 的皮毛就先学习到这里,后面再继续思考,每个process的切换和销毁,真的就如我上面所说?还是另有途径?