说明:本文依然依赖于 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的切换和销毁,真的就如我上面所说?还是另有途径?

contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>的更多相关文章

  1. main.js中封装全局登录函数

    1. 在 main.js 中封装全局登录函数 通过 vue 对象的原型扩展,可以扩展一个函数,这样这个函数就可以在每一个界面通过类似指向对象的方式,去访问这个函数. 如下是 main.js 扩展的函数 ...

  2. numpy中的arg系列函数

    numpy中的arg系列函数 觉得有用的话,欢迎一起讨论相互学习~Follow Me 不定期更新,现学现卖 numpy中arg系列函数被经常使用,通常先进行排序然后返回原数组特定的索引. argmax ...

  3. php中的preg系列函数

    mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int ...

  4. (linux)main.c中的初始化

    main.c中的初始化 head.s在最后部分调用main.c中的start_kernel() 函数,从而把控制权交给了它. 所以启动程序从start_kernel()函数继续执行.这个函数是main ...

  5. Java:main方法前面一定要加static?在main方法中一定要调用static方法?

    今天敲代码的时候发现,出现了这样一个情况: 我在我在main方法中调用了一个函数,并且这个函数没有用static修饰,就像这样: 这样报错了!!! 我虽然学Java 的时间也不多,但这个问题也帮助我更 ...

  6. Linux中exec()执行文件系列函数的使用说明

    函数原型: 描述:    exec()系列函数使用新的进程映像替换当前进程映像.    工作方式没有什么差别, 只是参数传递的方式不同罢了. 说明:    1. 这6个函数可分为两大类: execl( ...

  7. PHP中ob系列函数整理

    ob,输出缓冲区,是output buffering的简称,而不是output cache.ob用对了,是能对速度有一定的帮助,但是盲目的加上ob函数,只会增加CPU额外的负担. 下面我说说ob的基本 ...

  8. PHP中ob系列函数讲解(浏览器缓存技术) (转)

    Output Control 函数可以让你自由控制脚本中数据的输出.它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况. 输出控制函数不对使用 header() 或 setcooki ...

  9. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    C#中的函数式编程:递归与纯函数(二)   在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...

随机推荐

  1. Java [Leetcode 234]Palindrome Linked List

    题目描述: Given a singly linked list, determine if it is a palindrome. Follow up:Could you do it in O(n) ...

  2. 【Python】实践笔记

    为什么要在脚本中加入? import sys reload(sys) sys.setdefaultencoding('utf-8')

  3. test chemes

    rcmobile://messages rcmobile://badge rcmobile://dialer rcmobile://open rcmobile://sms?type=new

  4. zoj 2286 Sum of Divisors

    // f(n)表示 n的约数和 不包括自己// 给你一个m 求1 到 100万里面 f(n)<=m 的个数// 那么首先要用筛选求出所有出 f(n)// 然后就好办了 // 写好后 看见别人好快 ...

  5. Android裁剪固定大小头像的功能

    转载自: http://www.eoeandroid.com/thread-497277-1-1.html 效果很好,特意转载过来记录一下,加深一下印象. 效果就是 :中间的方框不动,可以拖动图片,选 ...

  6. 【转】正确理解PHP程序编译时的错误信息

    我们编写程序时,无论怎样小心谨慎,犯错总是在所难免的.这些错误通常会迷惑PHP编译器.如果开发人员无法了解编译器报错信息的含义,那么这些错误信息不仅毫无用处,还会常常让人感到沮丧. 编译PHP脚本时, ...

  7. linux命令——磁盘命令mkdir

    一.介绍 mkdir 命令用于创建文件夹或目录(类似dos下的md命令),要求创建目录的用户在当前目录中具有写权限, 并且指定目录名不能是当前目录中已有的目录或文件名称.名称区分大小写. 二.用法及参 ...

  8. 【LeetCode 160】Intersection of Two Linked Lists

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  9. Selenium IDE测试创建

    Selenium IDE 测试创建 涉及使用IDE Selenium创建测试,如下面的步骤 记录和测试添加命令 保存测试记录 保存测试程序 执行测试记录 在测试中记录和添加命令 为了演示目的,我们将利 ...

  10. PHP 系统命令函数

    function execute($cmd) { $res = ''; if ($cmd) { if(function_exists('system')) { @ob_start(); @system ...