contiki-进程
进程的结构
Contiki的进程由两部分组成:进程控制块和进程线程。进程控制块存储在内存中,它包含进程运行时的信息,比如:进程名、进程状态、指向进程线程的指针。
进程线程是存储在ROM中的一个代码块。
进程控制块PCB(process control block)
struct process {
struct process *next;
#if PROCESS_CONF_NO_PROCESS_NAMES
#define PROCESS_NAME_STRING(process) ""
#else
const char *name;
#define PROCESS_NAME_STRING(process) (process)->name
#endif
PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));
struct pt pt;
unsigned char state, needspoll;
};
struct pt {
lc_t lc;
};
/** \hideinitializer */
typedef unsigned short lc_t;
进程控制块包含每个进程的信息,比如进程状态、指向进程的线程的指针、进程的文本名称。进程控制块只在内核内部使用,不能被进程直接访问。
用户代码不能直接访问进程控制块的任何成员。
进程控制块是轻量级的,只需要几个字节的内存。进程控制块的结构体如上面所示。该结构体中任何成员都不能被直接访问,只有进程管理函数能够访问这些成员。
进程控制块的第一个成员 struct process *next,指向进程链表中的下一个进程控制块。
成员const char *name,指向进程的文本类型的名字。
成员PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t)),一个函数指针,指向了进程的线程。
成员unsigned char state, needspoll,是内部标志,当进程被轮询时,通过函数process_poll()修改该标志。
进程的创建过程
进程控制块不是直接定义和声明的,而是通过宏PROCESS()。
PROCESS(hello_world_process, "Hello world");
如上例所示,该宏有两个参数,用于访问该进程的进程控制块变量名hello_world_process、用于调试和打印进程的进程文本名字"Hello world"。
进程线程
进程线程是一个单一的protothread,由进程调度器调度。例子如下:
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN(); printf("Hello, world\n"); PROCESS_END();
}
Protothreads
当在等待某个事件发生时,protothread允许系统运行其它活动。protothread的概念是在开发Contiki的过程中提出来的,但是这个概念不是与Contiki绑定在一起的。protothread也可以很好地运行在许多其它的系统中。
Contiki运行在内存受限的系统之上,减小内存负载显得尤为重要。protothread提供了一种很好的方法,可以让C函数在没有传统线程内存负载的情况下,以类似线程的方式运行。
protothread可以看作是一个常规的C函数。该函数使用两个特殊的宏作为开始和结束:PROCESS_BEGIN()和PROCESS_END()。
C预处理器实现了protothread的主要操作:
struct pt {
lc_t lc;
};
#define PT_WAITING 0
#define PT_YIELDED 1
#define PT_EXITED 2
#define PT_ENDED 3
#define PT_INIT(pt) LC_INIT((pt)->lc)
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1;\
if (PT_YIELD_FLAG) {;} LC_RESUME((pt)->lc)
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
PT_INIT(pt); return PT_ENDED; }
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while()
#define PT_EXIT(pt) \
do { \
PT_INIT(pt); \
return PT_EXITED; \
} while()
进程中的Protothreads
Contiki进程自身实现了一套protothread,它允许进程等待即将到来的事件。因此,Contiki进程中使用的protothread语句与上面介绍的纯protothread语句有微小的差异。
Contiki进程中使用的进程相关的protothread宏:
PROCESS_BEGIN(); // Declares the beginning of a process' protothread.
PROCESS_END(); // Declares the end of a process' protothread.
PROCESS_EXIT(); // Exit the process.
PROCESS_WAIT_EVENT(); // Wait for any event.
PROCESS_WAIT_EVENT_UNTIL(); // Wait for an event, but with a condition.
PROCESS_YIELD(); // Wait for any event, equivalent to PROCESS_WAIT_EVENT().
PROCESS_WAIT_UNTIL(); // Wait for a given condition; may not yield the process.
PROCESS_PAUSE(); // Temporarily yield the process.
事件
Contiki中,进程接收到一个事件后就会运行。Contiki中有两种事件:异步事件和同步事件。
当一个异步事件被发出时,该事件被放到内核中的事件队列中,并在一段时间后被传递到接收进程中。

当一个同步事件被发出时,该事件被立即传递到接收进程中。

异步事件
异步事件在被发出一段时间后才能被传递到接收进程。在事件被发出后和被传递前的这段时间,它被保存在Contiki内核的事件队列中。
内核负责将事件队列中的事件传递到接收进程。内核循环遍历事件队列,通过调用进程将队列中的事件传递到进程中。
异步事件的接收者可以是一个特殊进程(何为特殊进程?),也可以是所有正在运行的通用进程。当接收者是一个特殊进程,内核就调用该进程并传递事件到该进程中。当事件接收者是系统中的通用进程,内核将一个接一个地顺序传递事件到所有的进程中。
异步事件通过函数process_post()发出。
int
process_post(struct process *p, process_event_t ev, process_data_t data)
{
static process_num_events_t snum; if(PROCESS_CURRENT() == NULL) {
PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",
ev,PROCESS_NAME_STRING(p), nevents);
} else {
PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n",
PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);
} if(nevents == PROCESS_CONF_NUMEVENTS) {
#if DEBUG
if(p == PROCESS_BROADCAST) {
printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));
} else {
printf("soft panic: event queue is full when event %d was posted to %s frpm %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
}
#endif /* DEBUG */
return PROCESS_ERR_FULL;
} snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
events[snum].ev = ev;
events[snum].data = data;
events[snum].p = p;
++nevents; #if PROCESS_CONF_STATS
if(nevents > process_maxevents) {
process_maxevents = nevents;
}
#endif /* PROCESS_CONF_STATS */ return PROCESS_ERR_OK;
}
process_post()的内部实现很简单(还是理清头绪才简单)。先检查当前事件队列的大小,检查是否还有可以存放事件的空间,然后再做决定,如果没有足够的空间,该函数返回一个错误,如果有足够的空间,该函数将事件插入到事件队列的末尾,然后返回。
同步事件
与异步事件不同的是,同步事件被发出后不经过事件队列,会被直接传递。同步事件只能被发出给一个特定进程。由于同步事件直接被传递,因此传递一个同步事件在功能上等同于一个函数调用:接收进程被直接调用,发送进程在接收进程完成处理事件前一直处于阻塞状态。不过,接收进程不会被告诉所发出的事件是同步事件还是异步事件。
同步事件是通过函数process_post_synch()发出。
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_poll()请求被轮询。进程请求轮询后,会尽可能快地被调用。当轮询到该进程时,会传递一个特殊的事件到进程中。
事件标识(zhi)符
事件被事件标识符所标识。事件标识符是一个8比特,一个字节的数组,会被传递到接收进程中。接收进程可以根据接收到的不同的事件标识符来做相应不同的处理。
事件标识符的范围是0~255,在127一下的事件标识符可以在一个用户进程中自由使用,在128以上的事件标识符只能在不同的进程间使用。在128以上的事件标识符被内核所管理。
从128开始的数字被内核静态分配,用于实现不同的目的。
Contiki内核保留的事件标识符:
#define PROCESS_EVENT_NONE 0x80 //该事件标识符 没有被使用
#define PROCESS_EVENT_INIT 0x81 //该事件被发送到一个正在初始化的新进程中
#define PROCESS_EVENT_POLL 0x82 //该事件被发送到一个轮询进程中
#define PROCESS_EVENT_EXIT 0x83 //该事件被发送到一个正在被内核杀死的进程中。
//进程接收到该事件后,因为可能不会被再次调用,因此它可以选择清空自己分派到的资源
#define PROCESS_EVENT_SERVICE_REMOVED 0x84
#define PROCESS_EVENT_CONTINUE 0x85 //该事件被内核发送到一个执行了PROCESS_YIELD()而正在等待的进程
#define PROCESS_EVENT_MSG 0x86 //该事件被发送到一个已经接收到通信消息的进程。
//它一般被用于IP栈去通知进程有消息到来了,也可以用与两个进程间表示一个通用消息到来了。
#define PROCESS_EVENT_EXITED 0x87 /*当一个进程将要退出时,该事件被发送到所有进程。
发送事件的同时,还会发送一个指向正在退出的进程的进程控制块的指针。
当接收到该事件时,接收进程将清除将要退出进程所分配的状态*/
#define PROCESS_EVENT_TIMER 0x88 //该事件被发送给一个事件定时器etimer到期的进程
#define PROCESS_EVENT_COM 0x89
#define PROCESS_EVENT_MAX 0x8a
除静态分配事件号之外,进程可以分配用于进程间的大于128的事件标识符。被分配的事件标识符被存储在一个变量中,接收进程可以使用该变量来匹配事件标识符。
摘录自:http://blog.csdn.net/tidyjiang/article/details/51378589
contiki-进程的更多相关文章
- Contiki进程间的交互
之前都是从各个模块开始看起,从底层开始看起.应该改变一下思路,从高往下看,站得高看得远. 一.Main函数 源码:contiki-release-2-7\platform\stm32test\cont ...
- Contiki-一个进程的例子
进程调度器 进程调度器的作用是调用进程.进程调度器通过调用实现进程线程的函数来调用进程.Contiki中所有的进程被设计为响应传递到进程中的事件,或者相应进程请求的轮询.进程调度器在调度进程的时候会将 ...
- [置顶] STM32移植contiki进阶之三(中):timer 中文版
鉴于自己英语水平不高,在这里,将上一篇关于contiki 的timer的文章翻译为中文,让自己在学习的时候,更方便点.文中有许多不是很通顺的地方,将就吧. Timers Contiki系统提供了一套时 ...
- [Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统
说明:本系列文章翻译自Contiki之父Adam Dunkels经典论文,版权归原作者全部. Contiki是由Adam Dunkels及其团队开发的系统,研读其论文是对深入理解Contiki系统的最 ...
- Protothread 机制
一.概述 很多传感器操作系统都是基于事件驱动模型的,事件驱动模型不用为每个进程都分配一个进程栈,这对内存资源受限的无线传感器网络嵌入式系统尤为重要. 然而事件驱动模型不支持阻塞等待抽象语句,因此程序员 ...
- Contiki学习笔记 第一个程序:Hello World
想来想去,还是得先写一个程序,找下感觉,增强一下自信心,那就国际惯例Hello World吧.先到这个网址下一个Instant Contiki 2.7.之所以没用3.0的,是因为有些问题,我源码是下的 ...
- 专为物联网开发的开源操作系统Contiki(转)
专为物联网开发的开源操作系统Contiki(转) (2012-04-19 15:31:09) 原文网址:http://blog.sina.com.cn/s/blog_6de000c201010z7n ...
- contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>
说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件. ---------------------------------------------- ...
- Contiki系统介绍
本文内容来源为contiki英文介绍,自己为了学习,将其大致翻译成中文,以便了解. 欢迎转载,转载请注明来源,如果有什么翻译不合适的地方,请留言指出,相互交流学习. 介绍 Contiki是一个开放源码 ...
随机推荐
- 回归测试---junit
回归测试是指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误. JUnit是一个Java语言的单元测试框架. http://blog.csdn.net/andycpp/ar ...
- 基于XMPP协议(openfire服务器)的消息推送实现
转自:http://blog.csdn.net/nomousewch/article/details/8088277 最近好像有不少朋友关注Android客户端消息推送的实现,我在之前的项目中用到过J ...
- wp插件
- Java复习笔记--java中this 关键字
Java中this关键字,this可以调用类的成员变量和成员方法,this还可以调用类中的构造方法.使用这种方式值得注意的是, 只可以在无参构造方法中的第一句使用this关键字调用有参构造方法. pu ...
- JS小数点加减乘除运算后位数增加的解决方案
/** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...
- 父目录的权限对子目录有没有影响?[Linux]
问题源头: 登录到服务器(实验室分的一个服务器账号)上,想在当前目录下创建一个文件,但提示“文件系统只读”,无法创建文件.通过ls -l 查看当前用户在当前目录的权限,发现具有rwx权限.所以在想会不 ...
- SD卡读写遇到的一些函数
SD_SPI_ReadWriteByte(0XFF): 你的数据线写0xff,就是一直保持高,clk就有了8个,可以说只是发送的数据是0xff,这又不是SD的命令,但是它必须要靠控制器提供时钟才能工作 ...
- javascript jsscript .js xml html json soap
javascript ecma标准的脚本语言用于 jsscript 微软标准的一种脚本语言 .js javascript或jsscript保存成文件的形式可用于在html里重复引用 jsscript只 ...
- H5 新标签用法及解释
HTML 5 是一个新的网络标准,目标在于取代现有的 HTML 4.01, XHTML 1.0 and DOM Level 2 HTML 标准.它希望能够减少浏览器对于需要插件的丰富性网络应用服务(p ...
- Eclipse in Ubuntu16.04LTS Final Beta
#2016.03.30 在虚拟机Ubuntu16.04LTS上,用Eclipse编写运行Java,就目前而言,实在不是明智之举.卡顿极其厉害,还是在物理机上运行吧.那么继续Ubuntu的探索历程. 用 ...