uip之protothreads
来源:互联网 发布:2017中国经济数据 编辑:程序博客网 时间:2024/05/15 23:44
本文简单介绍一下网络协议栈uip中的protothreads(协程)部分。
通常我们等待一个事件时有阻塞和非阻塞两种方式,uip不支持多线程操作,也不依靠中断来通知事件,所以要使用阻塞的方式。但阻塞这种方式又会白白浪费cpu时间阻塞在那里等待事件发生。因而uip使用了一种protothreads方式。我们暂称其协程。
下面是官方文档的一些简介。
协程是一种无堆栈的轻量级线程,它被设计用在服务一些简单有限的内存体系上,如一些嵌入式系统等。协程为事件驱动的线性代码执行,提供C的实现。协程可以被用在有或无RTOS(实时操作系统)的结构上。协程是一个非常轻量级,无堆栈线程,提供了事件驱动系统顶层的阻塞上下文的功能。而不需要每个线程的堆栈。协程的目的是实现连续流程的控制,而不需要状态机或者完整的多线程机制支持。在C函数中协程提供条件阻塞。
翻译的很拗口,直接写吧。
要使用协程,先看下以下几个基本API,初始化PT_INIT().执行PT_BEGIN(),条件阻塞PT_WAIT_UNTIL(),和结束PT_END().
我们从uip的一个应用实例dhcpc中看一下这个协程是如何使用及其原理(删去了无关代码)
在dhcpc初始化函数中调用了
PT_INIT(&s.pt);
下面是dhcpc的应用主函数
点击(此处)折叠或打开
- static
- PT_THREAD(handle_dhcp(void))
- {
- PT_BEGIN(&s.pt);
- do {
- send_discover(); //发送dhcpc探求包
- timer_set(&s.timer, s.ticks);
- PT_WAIT_UNTIL(&s.pt, uip_newdata()|| timer_expired(&s.timer));
- //do something
- if(s.ticks< CLOCK_SECOND * 60){
- s.ticks *= 2;
- }
- } while(s.state!= STATE_OFFER_RECEIVED);
-
- do {
- send_request(); //发送dhcpc接受包
- timer_set(&s.timer, s.ticks);
- PT_WAIT_UNTIL(&s.pt, uip_newdata()|| timer_expired(&s.timer));
-
- if(s.ticks<= CLOCK_SECOND* 10) {
- s.ticks += CLOCK_SECOND;
- } else {
- PT_RESTART(&s.pt);
- }
- } while(s.state!= STATE_CONFIG_RECEIVED);
- while(1){
- PT_YIELD(&s.pt);
- }
- PT_END(&s.pt);
- }
我们分别看下这几个宏的实现。
1.PT_INIT
初始化协程宏,必须在执行相应的协程函数前执行此宏
#define PT_INIT(pt) LC_INIT((pt)->lc)
我们看到这里又有一个新的宏LC_INIT(这是Local continuations(局部连续块)部分),其实就是初始化状态的
#define LC_INIT(s) s = 0;
结构pt的定义
struct pt {
lc_t lc;
};
所以PT_INIT(&s.pt);这个宏展开就是
s.pt->lc = 0;
2.PT_THREAD
定义协程函数的宏,凡是要使用协程的函数都要被此宏定义(修饰),宏定义如下
#define PT_THREAD(name_args) char name_args
3.PT_BEGIN
协程开始宏,定义如下
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
其中LC_RESUME宏,定义如下
#define LC_RESUME(s) switch(s) { case 0:
所以PT_BEGIN(&s.pt);宏展开如下
char PT_YIELD_FLAG = 1;
switch(s.pt->lc){
case 0:
可以看出这个宏就是定义了一个switch的头。
4.PT_WAIT_UNTIL
等待条件成立宏,此宏将“阻塞”在这个条件下
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while(0)
其中LC_SET宏为,
#define LC_SET(s) s = __LINE__; case __LINE__:
其中__LINE__是编译器内部产生的变量,它表示当前程序的行数。
所以将宏展开为
do{
s = __LINE__;
case __LINE__;
if(!(condition)){
return PT_WAITING;
}
}while(0)
5.PT_RESTART
重启协程宏,定义
#define PT_RESTART(pt) \
do { \
PT_INIT(pt); \//关键,将条件归0
return PT_WAITING; \
} while(0)
6.PT_YIELD
放弃执行宏,此宏功能是放弃此次执行函数返回。
#define PT_YIELD(pt) \
do { \
PT_YIELD_FLAG = 0; \
LC_SET((pt)->lc); \
if(PT_YIELD_FLAG == 0) { \
return PT_YIELDED; \
} \
} while(0)
7.PT_END
协程结束宏
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
PT_INIT(pt); return PT_ENDED; }
其中LC_END宏定义为
#define LC_END(s) }
我们将上面那个函数展开,如下
-----------------------------------------------------------
点击(此处)折叠或打开
- static char handle_dhcp(void)
- {
- char PT_YIELD_FLAG = 1;
- switch(s.pt->lc){
- case 0:
- do{
- send_discover(); //发送dhcpc探求包
- timer_set(&s.timer, s.ticks);
- do{
- s.pt->lc= __LINE__;
- case __LINE__;
- if(!(uip_newdata())){
- return PT_WAITING;
- }
- }while(0)
- }while(s.state!= STATE_OFFER_RECEIVED);
-
-
- do {
- send_request(); //发送dhcpc接受包
- timer_set(&s.timer, s.ticks);
- do{
- s.pt->lc= __LINE__;
- case __LINE__;
- if(!(uip_newdata())){
- return PT_WAITING;
- }
- }while(0)
-
- if(s.ticks<= CLOCK_SECOND* 10) {
- s.ticks += CLOCK_SECOND;
- } else {
- do {
- s.pt->lc= 0;
- return PT_WAITING;
- } while(0)
- }
- } while(s.state!= STATE_CONFIG_RECEIVED);
-
- while(1){ //这个死循环是应用中的需求,dhcp后这个程序不要再执行了
- do {
- PT_YIELD_FLAG = 0;
- s.pt->lc= __LINE__;
- case __LINE__:
- if(PT_YIELD_FLAG== 0){
- return PT_YIELDED;
- }
- } while(0) //可以看出此宏功能是,此次程序执行到这里就返回,下次再到本协程函数,不返回继续往后执行。
-
- }
-
- }
- PT_YIELD_FLAG = 0;
- s.pt->lc= 0;
- return PT_ENDED;
- }
0 0
- uip之protothreads
- UIP 之uip_conn
- uip
- ENC28J60以太网之uIP协议
- uip之UDP应用笔记
- Protothreads简介
- 图解Protothreads
- Protothreads 简介
- 毕业设计之路(6)——uip
- 20130408-[转]ENC28J60以太网之uIP协议
- lwip/uip移植之二:S3C2440+DM9000A
- 单片机之UIP--TCP 校验和计算
- uIP调试之ping、arp与死机
- contiki之uip-ds6-route头文件
- uIP协议栈——转载:uIP之ARP:地址…
- UIP(MVC->UIP)简介
- ProtoThreads - Producer&Consumer
- ProtoThreads如何工作的
- JavaSE学习笔记
- 使用SurfaceView模拟下雪花的动画
- CALayer基本属性
- CTreeCtrl 控件使用总结
- 聊聊JVM:相对全面的GC总结(专栏)
- uip之protothreads
- php结合数据库演示商品多图片上传
- Weblogic10 与 Websphere MQ7集成方案[1]
- LEETCODE之Combination Sum系列
- Activity与Fragment通用的跳转工具类JumpUtil的实现
- 从输入URL到浏览器显示页面的详细过程
- Safari 3D变换会忽略z-index问题解决
- tomcat6.0与7.0 配置https协议
- FormatMessage函数的用法