Contiki进程间的交互
之前都是从各个模块开始看起,从底层开始看起。应该改变一下思路,从高往下看,站得高看得远。
一、Main函数
源码:contiki-release-2-7\platform\stm32test\contiki-main.c
int
main()
{
dbg_setup_uart();
printf("Initialising\n"); clock_init();
process_init();
process_start(&etimer_process, NULL);
autostart_start(autostart_processes);
printf("Processes running\n");
while() {
do {
} while(process_run() > 0);
idle_count++;
/* Idle! */
/* Stop processor clock */
/* asm("wfi"::); */
}
return ;
}
主函数中,关于进程的操作:
先对进程进行初始化process_init()。
用process_start(&etimer_process, NULL),启动etimer_process进程。
用autostart_start(autostart_processes),启动需要自动启动的进程,看自启动进程相关知识。
最后循环执行进程调度函数process_run。
二、进程初始化
void
process_init(void)
{
lastevent = PROCESS_EVENT_MAX; nevents = fevent = ;
#if PROCESS_CONF_STATS
process_maxevents = ;
#endif /* PROCESS_CONF_STATS */ process_current = process_list = NULL;
}
初始化最后一个事件标识lastevent为PROCESS_EVENT_MAX
初始化事件总数nevents和事件队列头指针fevent为0。
初始化进程链表头process_list和当前进程process_current为NULL。
三、启动进程
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;//设置进程状态为准备就绪状态
PT_INIT(&p->pt);//初始化进程pt(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);//用同步事件启动进程p
}
先确保要启动的进程没有在进程链表中。
再将进程添加到进程链表中。
设置进程状态为PROCESS_STATE_RUNNING,即就绪状态,并初始化pt。
最后传递同步事件给进程p,其中事件标识为PROCSS_EVENT_INIT,事件携带数据data为NULL。
1、传递同步事件
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_current变量。
2、调用进程
static void
call_process(struct process *p, process_event_t ev, process_data_t data)
{
int ret;//进程执行主体函数返回值 #if DEBUG
if(p->state == PROCESS_STATE_CALLED) {//再次调用?
printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev);
}
#endif /* DEBUG */ if((p->state & PROCESS_STATE_RUNNING) &&
p->thread != NULL) {//就绪状态并且执行主体函数不为NULL?
PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);
process_current = p;//设置当前进程变量
p->state = PROCESS_STATE_CALLED;//设置进程状体为已被调用
ret = p->thread(&p->pt, ev, data);//执行进程主体函数
if(ret == PT_EXITED ||
ret == PT_ENDED ||
ev == PROCESS_EVENT_EXIT) {//返回值为PT_EXITED或PT_ENDED或传递进来的事件为PROCESS_EVENT_EXIT
exit_process(p, p);//执行退出进程函数
} else {
p->state = PROCESS_STATE_RUNNING;//重新设置为就绪状态,等待事件的到来
}
}
}
在进程状态为就绪状态PROCESS_STATE_RUNNING,并且执行主体函数不为NULL的情况下。
设置当前进程变量为p,并设置状态为已被调用状态PROCESS_STATE_CALLED。
调用执行主体函数p->thread(&p->pt, ev, data)。
如果返回值为PT_EXITED或者返回值为PT_ENDED或者这个事件是PROCESS_EVENT_EXIT,则这个进程已经执行完毕了。执行退出进程操作exit_process,做一些善后工作。
否则重新设置进程状态为就绪状态,继续等待事件的到来。
注:注意区分PROCESS_EVENT_EXIT事件和PROCESS_EVENT_EXITED事件,PROCESS_EVENT_EXIT是通知要退出的进程p本身,而PROCESS_EVENT_EXITED是通知其他进程,有进程p即将退出。
退出进程操作有两种情况,一种是自己要退出,即上述情况:返回值为PT_EXITED或者返回值为PT_ENDED或者这个事件是PROCESS_EVENT_EXIT。
另一种是其他进程要这个进程退出。
退出进程
static void
exit_process(struct process *p, struct process *fromprocess)
{
register struct process *q;
struct process *old_current = process_current;//先保存当前进程变量 PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p)); /* 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_STATE_NONE才进入
/* Process was running */
p->state = PROCESS_STATE_NONE;//设置状态为PROCESS_STATE_NONE /*
* 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);
}
}//通知其他所有进程,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);
}
}//再次执行p进程的执行主体函数(p和fromprocess不同的情况下) 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;
}
}
}//将进程p从进程链表中删除 process_current = old_current;//恢复当前进程变量
}
先确定要退出的进程在进程链表中,并且进程状态不是PROCESS_STATE_NONE。
先给其他所有进程,传递同步事件PROCESS_EVENT_EXITED,通知p这个进程即将退出。
如果是其他进程要p退出的话,则再次执行p的执行主体函数。
如果是p要p退出的话,那么执行主体函数都已经执行过了,所以不用再执行。
最后将进程p从进程链表中删除。
int
process_is_running(struct process *p)
{
return p->state != PROCESS_STATE_NONE;
}
process_is_running
四、进程调度
int
process_run(void)
{
/* Process poll events. */
if(poll_requested) {
do_poll();
} /* Process one event from the queue */
do_event(); return nevents + poll_requested;
}
进程调度函数中先处理抢占式进程,然后再处理协同式进程(非同步事件)。
1、推举抢占式进程
void
process_poll(struct process *p)
{
if(p != NULL) {
if(p->state == PROCESS_STATE_RUNNING ||
p->state == PROCESS_STATE_CALLED) {
p->needspoll = ;
poll_requested = ;
}
}
}
最主要的工作时将进程p的needspoll标志设置为1,以及是否有poll请求标志poll_requested设置为1。
2、抢占式进程处理
static void
do_poll(void)
{
struct process *p; poll_requested = ;//恢复标志
/* Call the processes that needs to be polled. */
for(p = process_list; p != NULL; p = p->next) {//遍历进程链表,调用所有需要poll的进程
if(p->needspoll) {
p->state = PROCESS_STATE_RUNNING;
p->needspoll = ;//恢复标志
call_process(p, PROCESS_EVENT_POLL, NULL);
}
}
}
注:从上边我们知道,抢占式进程会全部都执行完之后,再从事件队列中取出一个事件传递给目的进程处理。
总结
要先用process_start或者autostart_start先将进程启动。
后续的进程调度函数process_run时在进程启动后进行的一些调度,准确的说是传递事件。
进程的状态:
#define PROCESS_STATE_NONE 0 退出前的一个状态,就差从进程链表中删除。
#define PROCESS_STATE_RUNNING 1 就绪状态,即已经初始化完毕,等待事件的到来,然后执行进程执行主体函数。
#define PROCESS_STATE_CALLED 2 进程正在被调用,也就是执行主体函数正在运行中。
Contiki进程间的交互的更多相关文章
- 【python】-- 多进程的基本语法 、进程间数据交互与共享、进程锁和进程池的使用
多进程 进程之间是相互独立的,python是启动进程的时候,是启动的是原生进程.进程是没有GIL锁的,而且不存在锁的概念,进程之间的数据式不能共享的,而线程是可以的. 1.进程的定义 用mulipro ...
- Python 进程间数据交互
进程间通信:进程之间必须需要中间件. 不同进程间内存是不共享的,要想实现两个进程间的数据交换 Queues:实现传输两个进程的数据 线程queue,访问数据只能在一个进程内进行线程与线程之间的 ...
- Qt学习之路(58): 进程间交互(QProcess.readAllStandardOutput可以读取控制台的输出)
所谓 IO 其实不过是与其他设备之间的数据交互.在 Linux 上这个概念或许会更加清楚一些.Linux 把所有设备都看作是一种文件,因此所有的 IO 都归结到对文件的数据交互.同样,与其他进程之间也 ...
- python的进程间的数据交互
#先来看下如何实现多进程 # multiprocessing 这个是python的多进程的模块,我们会用到这个模块的很多方法 from multiprocessing import Process i ...
- linux 共享内存shm_open实现进程间大数据交互
linux 共享内存shm_open实现进程间大数据交互 read.c #include <sys/types.h> #include <sys/stat.h> #includ ...
- Python使用进程间共享变量来控制两个进程(监听键盘和相机录制)的交互
我有个简单的应用需求: 1. 该应用随时会监听键盘的输入: 2. 当输入指定键时会控制相机录制的启动和关闭. 监听键盘是一个事件循环,相机录制也是一个循环录制的过程.我试着用 Python 启动两个进 ...
- CEF3开发者系列之进程间消息传递
在使用CEF3作为框架开发过程中,实现WebSockets.XMLHttpRequest.JS与本地客户端交互等功能时,需要在渲染(Render)进程和浏览(Browser)进程中传递消息.CEF3在 ...
- AIDL进程间调用与Binder的简单介绍
Binder是安卓中特有的一种进程间通信(IPC)方式,从Unix发展而来的手段,通信双方必须处理线程同步.内存管理等复杂问题,传统的Socket.匿名通道(Pipe).匿名管道(FIFO).信号量( ...
- 服务 进程间通讯 IPC AIDL Parcelable 简介
1.IBinder和Binder是什么鬼? 我们来看看官方文档怎么说: 中文翻译: IBinder是远程对象的基本接口,是为了高性能而设计的轻量级远程调用机制的核心部分. 但他不仅用于远程调用,也用 ...
随机推荐
- js处理日期格式yyyy-MM-dd hh:mm:ss
直接上代码: 使用方法: dateformat('h:m:s') => 09:08:11 dateformat('y-M-d h:m:s') => 2018-06-08 09:08:11 ...
- XML基础知识学习
概念: XML 指可扩展标记语言 XML 是一种标记语言,非常类似 HTML ,文本文件. XML 的设计宗旨是数据传输,而非显示数据 .存储和传输复杂的关系模型数据 XML 标签没有被提前定义 使用 ...
- codeforces 283C
给 n 中 钱币.以及每两种钱币的关系,表示,ai 的 个数 要大于 bi 组合成一个价值val,求方案数,好奇妙的一个处理方式,不得不说又学到了 #include<stdio.h> #i ...
- linux安装svn客户端subversion及使用方法
1.下载 [maintain@HM16-213 software]$ wget http://subversion.tigris.org/downloads/subversion-deps-1.6.1 ...
- 解决phpmyadmin导入大数据库出现一系列问题
在用phpmyadmin导入mysql数据库文件时,往往超过2M就会提示文件大,导入不成功.这时我们打开phpmyadmin-->libraries-->config.default.ph ...
- iBatis2 SqlMap中经常使用sql语句
本来我也不喜欢iBatis,那是由于我当时还不怎么会用它,如今我想说,iBatis是个好东西,不信你试试看.以下是我在项目实践中对iBatis的一个小总结.希望帮助众多在疲于iBatis编码而无暇思考 ...
- C市现在要转移一批罪犯到D市,C市有n名罪犯,按照入狱时间有顺序,另外每个罪犯有一个罪行值,值越大罪越重。现在为了方便管理,市长决定转移入狱时间连续的c名犯人,同时要求转移犯人的罪行值之和不超过t,问有多少种选择的方式?
// ConsoleApplication12.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" // ConsoleApplication1 ...
- FreeRTOS在神舟IV号开发板的应用demo
下面一个可以直接编译运行的例子,FreeRTOS的版本是V7.1.0,芯片是STM32F107VCT6,使用的开发环境是Keil uVision5. 这里例子创建了四个任务,每个任务控制一个LED的亮 ...
- IIS 配置错误:不能在此路径中使用此配置节。如果在父级别上锁定了该节,便会出现这种情况。 HTTP 错误 500.19
因为 IIS 7 采用了更安全的 web.config 管理机制,默认情况下会锁住配置项不允许更改.运行命令行 %windir%\system32\inetsrv\appcmd unlock conf ...
- 【Python基础】之函数、类和方法
一.函数 1. def定义函数 Python Shell: def add(a,b): return a+b >>>add(1,2) 3 def add(a=1,b=2): retu ...