好吧,昨晚上研究了switch()的底层实现原理--发现它并不是一般C语言教科书上那样所言,当然,这对于本身就非常熟悉汇编的同学来说,是小菜一碟。世界上,很多事情是巧合与必然的结合体,没有无缘无故的爱,也没有无缘无故的恨---我为啥会被一个switch给挡出去路?这个switch在contiki中又有何重要作用?且不回答这个问题,先来看看如何使用昨天晚上展开的PROCESS_YIELD()宏。

说明:这里就只是贴打印信息,分析打印信息了,不再贴分析过程中的代码了。

一,修改自己的hello-world.c文件内容如下:

 #include "contiki.h"

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

说明,上面代码就是在hello_process 这个process上添加了一个新的 test_process。这个test_process就是为了打印一个中国人的"Haha",不再是"Hello world"。

于是增加了第6行,以及第21~29行,修改了第8行。为了测试需要,在两个process函数体中,在PROCESS_BEGIN()之前,都添加了printf()语句。代码很简单,不做说明。

二,实现自己的contiki-main.c函数

这个就在 contiki-2.6/platform/native/ 下实现吧。只是把原来的contiki-main.c给备份了。

 #include <stdio.h>
#include <string.h>
#include "contiki.h" int
main(int argc, char **argv)
{ process_init(); autostart_start(autostart_processes); return ;
}

很简单了,初始化process,然后就自动启动hello-world.c里面的两个process.

<ps:同时,为了观察的更清楚,我去process.c/pt.h文件里也加入了一些printf(),比如一些函数中,我会加入printf("\n%s,%d\n",__func__,__LINE__);的代码,当然还有其他的一些printf()内容,不详述。所以,下面的打印中会多出一些内容。>

3,make,执行hello-world.native

 ./hello-world.native 

 process_init, 

 process_start,

 call_process, 

 test hello_process...

 PT_YIELD_FLAG =
PT_EXITED = , PT_ENDED = , PROCESS_EVENT_EXIT = ,PT_YIELDED = , ret = process_start, call_process, test test_process.. Haha, only test
process end: PT_YIELD_FLAG =
PT_EXITED = , PT_ENDED = , PROCESS_EVENT_EXIT = ,PT_YIELDED = , ret = exit_process,
exit_process, , and call call_process() call_process, test hello_process... PT_YIELD_FLAG =
Hello, world
process end: PT_YIELD_FLAG =
PT_EXITED = , PT_ENDED = , PROCESS_EVENT_EXIT = ,PT_YIELDED = , ret = exit_process,
exit_process, , and call call_process() call_process, exit_process, ok exit... exit_process, ok exit...

1,第三行---->main()中的process_init()执行。

2,第5行---->main()中的autostart_start(autostart_processes);执行。然后整个函数会在一个for()里面调用process_start()函数

3,第7行---->就是process_start()后,会牵涉出后面的process处理函数,这里已经到了call_process,意思是开始准备调用某个process了。

4,第10行--->在call_process()的作用下,我们自己的hello_process开始执行了。这里已经开始进入了hello_process的函数体了。

5,第13行--->检测出 (char) PT_YIELD_FLAG 的值为0。其实这已经执行到了hello_process中的 PROCESS_YIELD()宏了。这个宏在上文已经展开--如果PT_YIELD_FLAG 为0,会直接返回一个(PT_YIELDED = 1),而不会再接着执行下面的代码了。需要说明的是,PROCESS_YIELD()宏是位于PROCESS_BEGIN()宏后面,在PROCESS_BEGIN()中,已经将PT_YIELD_FLAG 初始化为 1了。但是在PROCESS_YIELD()中又被强制置0了。当然,PROCESS_YIELD还保存了当前所在行的行数,这是通过宏"__LINE__"来实现的。

6,第14行--->正如第5点所言,call_process在调用hello_process()函数后,因为PROCESS_YIELD()宏的作用,导致得到了一个返回值为 (PT_YIELDED =1)的结果。

7,第16行、第18行-->重新开了process_start ,call_process的执行。这其实是开始调用下一个process了。从这里可以看出,hello_process中的"Hello world"并没有执行,马上就把cpu的权利让给了下一个process--->类似于hello_process睡着了~~

8,第21行--->进入了test_process这个process的函数体。我在test_process中并没有再次使用PROCESS_YIELD()宏了,所以就顺风顺水的把test_process给执行完了。执行完毕后,把PT_YIELDED 写为0,这个动作是在 PROCESS_END()宏里完成。

9,第,27行--->test_process执行完毕,开始进入了exit阶段,准备释放自己的资源什么的,交出cpu控制权什么的。

10,第28行-->在exit阶段,test_process会把cpu控制权交给下一个相邻的process-->当然,最好的办法是启动这个process,于是可见,在exit阶段,call_process又一次被使用了。当然,test_process的邻process是hello_process,于是就直接启动了hello_process了。在这里有一点要说明,似乎test_process在exit的时候,仅仅是交出了cpu的控制权,但是是否真正exit了呢-->也就是所有的资源都释放了,不再占用了呢?

11,第30、33行,表明程序在一次进入了hello_process-->也即是,hello_process再一次开始执行,那么结果如何?

12,第36行,在PROCESS_YIELD()这个宏里面,检测到了PT_YIELD_FLAG 这个值为1,那就开始了下面代码的执行。需要说明的是,PROCESS_YIELD()里面有个case语句,它会和PROCESS_BEGIN()宏里面的switch匹配。而其工作原理,也其实类似于一个goto语句。这在上篇笔记已经说明了,不再赘述。

13,第37、39行,很无聊了,没必要再说。

14,第41行-->hello_process 准备exit了。

15,第42、44行,就是一个准备交出cpu控制权的过程了。但是貌似hello_process发现它的邻process是一个 NULL,于是一赌气,索性就全部exit了,包括控制权和资源。为嘛hello_process的邻process是一个NULL呢?因为process_list是一个链表,链表的终端指向了NULL,这在process_init()中就决定了它的命运。

16,第46、48行,exit了两次,这让我很惊讶,暂时没弄明白。等后面再补充。

ps: 原来准备在该笔记中,将整个process的流程再用一个流程图画一下,但由于打印的第46,48行,不知为啥会去执行两次,一时没明白,图片就暂时不画了,先研究下了。

贴一下,宏展开代码:

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

这个宏展开代码中,switch的用法很奇特,不过是正确的。其原理,已经在上篇笔记写明了。

好了,就这么多。

PROCESS_YIELD()宏使用及过程分析<contiki学习笔记之八>的更多相关文章

  1. 简单的玩玩etimer <contiki学习笔记之九>

    好吧,我承认etimer有点小复杂,主要是它似乎和contiki的process搅在一起,到处都在call_process.那就先搜搜contiki下的etimer的example看看,然后再试着写一 ...

  2. 简单的玩玩etimer <contiki学习笔记之九 补充>

    这幅图片是对前面  <<contiki学习笔记之九>>  的一个补充说明. 简单的玩玩etimer <contiki学习笔记之九> 或许,自己正在掀开contiki ...

  3. PROCESS_YIELD()宏和C语言的switch语句< contiki学习笔记之七>

    写在前面:  按照main()函数的代码一行一行的分析,该是看到了 etimer_process 这个位置.但是etimer_process实现里的一个宏 PROCESS_YIELD()引出了很多故事 ...

  4. 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  5. contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>

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

  6. Contiki学习笔记  第一个程序:Hello World

    想来想去,还是得先写一个程序,找下感觉,增强一下自信心,那就国际惯例Hello World吧.先到这个网址下一个Instant Contiki 2.7.之所以没用3.0的,是因为有些问题,我源码是下的 ...

  7. contiki学习笔记---process结构体

    process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...

  8. Contiki学习笔记

    http://blog.chinaunix.net/uid-9112803-id-2975824.html

  9. python学习笔记之八:迭代器和生成器

    一. 迭代器 在前面的笔记中,已经提到过迭代器(和可迭代),这里会对此进行深入讨论.只讨论一个特殊方法---__iter__,这个方法是迭代器规则的基础. 1.1 迭代器规则 迭代的意思是重复做一些事 ...

随机推荐

  1. 【JSP】JSP检查字符串是否为数字

    //判断是否是正整数 function IsNum(s) { if(s!=null){ var r,re; re = /\d*/i; //\d表示数字,*表示匹配多个数字 r = s.match(re ...

  2. Oracle 一次 锁表 处理小记

    同事说测试库上的一张表被锁了. 不能执行DML 操作. 锁表的准确说法应该是阻塞.之前的一遍blog里有说明: 锁 死锁 阻塞Latch 等待 详解 http://blog.csdn.net/tian ...

  3. andeoid学习笔记七

    Android中Broadcast的Intent大全 Api Level 3:(SDK 1.5) android.bluetooth.a2dp.intent.action.SINK_STATE_CHA ...

  4. mount

    产品,平台,RS6000, pseries 软件版本, aix 当NFS在NFS客户端加载时,系统会问是使用 soft-mount 还是hard-mount, 它们之间有什么区别? 它们的区别在于当发 ...

  5. iOS 7 自定义Back按钮 与 Pop interactive gesture 问题

    1.自定义Back按钮 iOS中很多时候我们都会自定义返回按钮,也是一件easy的事,类似如下: // 返回按钮 1 - (void)showNavBackButton { UIButton *bac ...

  6. Headmaster's Headache

    题意: s门课程,现任老师有m个给出工资,和他们能教的课,现在有n个应聘的老师,给出费用和能教的课程标号,求使每门课都至少有两个老师教的最小花费 分析: n个老师选或不选有背包的特征,n很小想到用状压 ...

  7. CSS书写规范、顺序

    写了这么久的CSS,但大部分前端er都没有按照良好的CSS书写规范来写CSS代码,这样会影响代码的阅读体验,总结一个CSS书写规范.CSS书写顺序供大家参考,这些是参考了国外一些文章以及我的个人经验总 ...

  8. Gridview数据导出到ExcelWord 防止出现乱码

    1.页面中添加绿色字体代码<%@ Page Language="C#" CodeFile="111.aspx.cs" Inherits="111 ...

  9. C 实现的算法篇

    算法的定义:算法是解决实际问题的一种精确的描述方法,目前,广泛认同的定义是:算法的模型分析的一组可行的确定的和有穷的规则 算法的五个特性:有穷性,确切性,输入,输出,可行性.目前算法的可执行的步骤非常 ...

  10. MorningSale 使用帮助

    待添加     http://121.37.42.173:8080/morningsale