一、事件相关数据结构

1、事件结构体

struct event_data {
process_event_t ev;
process_data_t data;
struct process *p;
};

其中process_event_t和process_data_t的定义:

typedef unsigned char process_event_t;
typedef void * process_data_t;

所以event_data结构体中的ev是一个unsigned char型数据,标识事件的类型

(1)事件标识ev

其中0-127为用户进程内使用,128-255用于不同进程之间的通信。

Event identifiers below 127 can be freely used within a user process, whereas event identifiers above 128 are intended to be used between different processes. Identifiers above 128 are managed by the kernel. The first numbers over 128 are statically allocated by the kernel, to be used for a range of different purposes.

  • 系统定义的事件标识:
#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
#define PROCESS_EVENT_MSG 0x86
#define PROCESS_EVENT_EXITED 0x87
#define PROCESS_EVENT_TIMER 0x88
#define PROCESS_EVENT_COM 0x89
#define PROCESS_EVENT_MAX 0x8a

PROCESS_EVENT_NONE : This event identifier is not used.

PROCESS_EVENT_INIT : This event is sent to new processes when they are initiated.

PROCESS_EVENT_POLL : This event is sent to a process that is being polled.

PROCESS_EVENT_EXIT : This event is sent to a process that is being killed by the kernel. The process may choose to clean up any allocated resources, as the process will not be invoked again after receiving this event.

PROCESS_EVENT_CONTINUE : This event is sent by the kernel to a process that is waiting in aPROCESS_YIELD() statement.

PROCESS_EVENT_MSG : This event is sent to a process that has received a communication message. It is typically used by the IP stack to inform a process that a message has arrived, but can also be used between processes as a generic event indicating that a message has arrived.

PROCESS_EVENT_EXITED : This event is sent to all processes when another process is about to exit. A pointer to the process control block of the process that is existing is sent along the event. When receiving this event, the receiving processes may clean up state that was allocated by the process that is about to exit.

PROCESS_EVENT_TIMER : This event is sent to a process when an event timer (etimer) has expired.

  • 最后一个事件标识lastevent

我们知道128-255用于不同进程之间的通信,lastevent用来记录最后一个分配出去的事件标识,下个事件标识应该是lastevent加1。lastevent初始化为PROCESS_EVENT_MAX。

/*---------------------------------------------------------------------------*/
process_event_t
process_alloc_event(void)
{
return lastevent++;
}
  lastevent = PROCESS_EVENT_MAX;

(2)事件数据

event_data是事件发生时,所携带的相关信息,其类型为指向void型的指针

(3)事件所要传递到的目的进程的指针

struct process *p;

p为指向这个事件所要传递到的进程的指针。

http://www.cnblogs.com/songdechiu/p/5801136.html我们知道,进程执行实体函数如下

static char process_thread_name(struct pt *process_pt, process_event_t ev, process_data_t data);

进程是由事件驱动的,并采用了protothread机制。进程执行实体函数,三个参数,

struct pt *process_pt, process_event_t ev, process_data_t data

其中process_pt可以理解为lc,ev就是本次传递给本进程的事件标识,data为本次传递给本进程事件所携带的信息。

2、事件队列

static struct event_data events[PROCESS_CONF_NUMEVENTS];
#define PROCESS_CONF_NUMEVENTS 32

这个事件队列是由数组实现的循环队列,默认最多可以存放32个事件。当超过32个事件后,从头开始循环存储。

大致示意图:

参考百度百科

(1)事件总数nevents和队列头指针fevent

static process_num_events_t nevents, fevent;
typedef unsigned char process_num_events_t;

在do_event中可看出

/* Since we have seen the new event, we move pointer upwards
and decrese the number of events. */
fevent = (fevent + ) % PROCESS_CONF_NUMEVENTS;
--nevents;

nevents是需要处理的事件总数,也是队列大小。

fevent是当前需要处理的事件在数组数组中的偏移,这里fevent相当于头指针head

(2)process_maxevents

#if PROCESS_CONF_STATS
process_num_events_t process_maxevents;
#endif
#if PROCESS_CONF_STATS
if(nevents > process_maxevents) {
process_maxevents = nevents;
}
#endif /* PROCESS_CONF_STATS */

process_maxevents为最多事件数,注意与PROCESS_CONF_NUMEVENTS区分,PROCESS_CONF_NUMEVENTS为队列的最大容量

二、事件相关处理函数

1、process_nevents

int
process_nevents(void)
{
return nevents + poll_requested;
}

返回需要处理的事件总数nevents和poll请求标志的和。进程分为两种,协调式和抢占式。nevents代表需药给协调式进程处理的事件,poll_requested代表需要给抢占式进程处理的事件。

2、非同步事件处理

非同步事件处理中,函数process_post先将事件放到事件队列中。

事件处理函数do_event()再把事件传递给接收事件的进程。

(1)非同步事件传递函数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) {//队列已满,返回错误信息RPOCESS_ERR_FULL
#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;//事件总数加1 #if PROCESS_CONF_STATS
if(nevents > process_maxevents) {
process_maxevents = nevents;//更新process_maxevents
}
#endif /* PROCESS_CONF_STATS */ return PROCESS_ERR_OK;//返回成功信息
}

这个函数就是把事件放到事件队列中去。先判断队列是否已经满,满了就返回错误信息。没满则先找到尾指针,将事件添加到队列尾部,返回成功信息。

(2)事件处理函数do_event

static void
do_event(void)
{
static process_event_t ev;
static process_data_t data;
static struct process *receiver;
static struct process *p; /*
* If there are any events in the queue, take the first one and walk
* through the list of processes to see if the event should be
* delivered to any of them. If so, we call the event handler
* function for the process. We only process one event at a time and
* call the poll handlers inbetween.
*/ if(nevents > ) {//有事件需要处理,取出第一个事件 /* There are events that we should deliver. */
ev = events[fevent].ev; data = events[fevent].data;
receiver = events[fevent].p; /* Since we have seen the new event, we move pointer upwards
and decrese the number of events. */
fevent = (fevent + ) % PROCESS_CONF_NUMEVENTS;//头指针后移
--nevents;//事件总数减1 /* If this is a broadcast event, we deliver it to all events, in
order of their priority. */
if(receiver == PROCESS_BROADCAST) {//广播事件?
for(p = process_list; p != NULL; p = p->next) {//遍历所有进程 /* If we have been requested to poll a process, we do this in
between processing the broadcast event. */
if(poll_requested) {//在此期间,如果有抢占式进程需要执行,则先执行抢占式进程
do_poll();
}
call_process(p, ev, data);//没有的话,将事件依次传给所有进程
}
} else {//不是广播事件
/* This is not a broadcast event, so we deliver it to the
specified process. */
/* If the event was an INIT event, we should also update the
state of the process. */
if(ev == PROCESS_EVENT_INIT) {//初始化事件?
receiver->state = PROCESS_STATE_RUNNING;//设置状态,这个状态是就绪状态
} /* Make sure that the process actually is running. */
call_process(receiver, ev, data);//传递事件给特定进程
}
}
}

这个函数最终就是调用call_process函数,将事件传递给特定进程。进程执行主体函数开始执行。

3、同步事件处理

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;//恢复当前进程指针
}

同步事件处理中,事件立马就传递给了特定的进程,表现为立马执行ProcessB的执行实体函数。

Contiki事件的更多相关文章

  1. JNI详解---从不懂到理解

    转载:https://blog.csdn.net/hui12581/article/details/44832651 Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 C ...

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

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

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

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

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

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

  5. Contiki学习入门之概览

    Contiki是专为物联网领域而设计的开源操作系统,适用于联网嵌入式系统和无线传感器网络.由瑞典计算机科学学院的Adam Dunkels团队开发.它有以下几个特点. 1. 网络标准 contiki提供 ...

  6. Contiki系统介绍

    本文内容来源为contiki英文介绍,自己为了学习,将其大致翻译成中文,以便了解. 欢迎转载,转载请注明来源,如果有什么翻译不合适的地方,请留言指出,相互交流学习. 介绍 Contiki是一个开放源码 ...

  7. [置顶] STM32移植contiki进阶之三(中):timer 中文版

    鉴于自己英语水平不高,在这里,将上一篇关于contiki 的timer的文章翻译为中文,让自己在学习的时候,更方便点.文中有许多不是很通顺的地方,将就吧. Timers Contiki系统提供了一套时 ...

  8. contiki etimer部分

    1.前言     contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统.国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有 ...

  9. [Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统

    说明:本系列文章翻译自Contiki之父Adam Dunkels经典论文,版权归原作者全部. Contiki是由Adam Dunkels及其团队开发的系统,研读其论文是对深入理解Contiki系统的最 ...

随机推荐

  1. 2017.2.20 activiti实战--第五章--用户与组及部署管理(一)用户与组

    学习资料:<Activiti实战> 第五章 用户与组及部署管理(一)用户与组 内容概览:讲解activiti中内置的一套用户.组的关系,以及如何通过API添加.删除.查询. 5.1 用户与 ...

  2. leetcode 46-Permutations and 47-Permutations II

    Permutations Given a collection of numbers, return all possible permutations. For example, [1,2,3] h ...

  3. Android使用OKHttp3实现下载(断点续传、显示运行进度)

    OKHttp3是现在很流行的Android网络请求框架,那么怎样利用Android实现断点续传呢,今天写了个Demo尝试了一下,感觉还是有点意思 准备阶段 我们会用到OKHttp3来做网络请求,使用R ...

  4. linux 内核(系统)、函数的理解、宏的程序调试

    1.操作系统 1.1.Linux 内核(系统)的组成的部分: 内核主要有:进程调度.内存管理.虚拟文件系统.网络接口和进程通信五个部分组成. (1)进程调度 进程调度是CPU对多个进程对CPU访问的调 ...

  5. 关于iOS Tabbar的一些设置

    事实上iOS Tabbar的可定制性很高,我们没有必要反复造轮子,以下是笔者收集的一些tabbar的经常使用设置.希望对大家有所帮助. 设置tabbar选中颜色 iOS7设置例如以下: [self.t ...

  6. redmine 自己定义字段mysql表结构

    redmine能够创建自己定义字段,我经经常使用它来满足不同的管理需求.如今来解读一下.看看这些自己定义字段是怎样存在mysql表中的. 表issues 用来存放issue的标准字段. mysql&g ...

  7. js运算【按位非】~

    这个运算符有点意思:按位非[~] 先来几个例子: ~undefined: -1 ~false: -1 ~true: -2 ~10:-11 找出规律了吧~~ 再说一下运用场景: 之前判断字符串是否存在是 ...

  8. linux下修改tomcat80端口

    在这里利用iptables防火墙,将80端口的请求转发到8080端口 在root用户下执行iptales -t nat -A PREROUTING -p tcp --dport 80 -j REDIR ...

  9. 献给写作者的 Markdown 新手指南及语法

    烈推荐所有写作者学习和掌握该语言.为什么?可以参考: 『为什么作家应该用 Markdown 保存自己的文稿』. 『Markdown写作浅谈』 让你专注于文字而不是排版. 标题 只需要在文本前面加上 # ...

  10. 【转】soapUI和Jmeter的接口测试结构区别

    使用SoapUI和Jmeter都可以进行自动化接口测试,但是每个工具都有自身的特点,所以他们的结构也有一定的区别 SoapUI 项目名称 -Rest服务.Rest资源 在使用SoapUI进行接口测试时 ...