第一篇:《Linux协议栈源码分析》读书报告
读 书 报 告
题目 《Linux协议栈源码分析》
一、介绍......................................................................................................................................1.1、中断模型......................................................................................................................-21.1.2、硬中断...............................................................................................................-2
二、中断处理..............................................................................................................................2.1、中断线..........................................................................................................................-32.1.2、特性...................................................................................................................-32.2.1、硬中断的开关...................................................................................................-42.3、软中断处理..................................................................................................................-52.3.2、注册软中断处理函数.......................................................................................-52.4、软中断处理和硬中断处理区别..................................................................................-6
三、中断处理中数据结构...........................................................................................................3.1、中断描述符..................................................................................................................-63.3、中断控制器描述符(PIC、APIC)................................................................................3.4、中断服务例程(ISR)...................................................................................................四、总结..................................................................................................................................../ 13
二、中断处理
2.1、中断线
每个能够产生中断的设备或者模块都会在内核中注册一个中断服务例程(ISR),当产生中断时,中断处理程序会被执行,在中断处理程序中,首先会保存中断向量号和上下文,之后执行中断线对应的中断服务例程。对于CPU来说,中断线是非常宝贵的资源,而由于计算机的发展,外部设备数量和种类越来越多,导致了中断线资源不足的情况,linux为了应对这种情况,实现了两种中断线分配方式,分别是:共享中断线,中断线动态分配。2.1.1、中断线分配方式(1)共享中断线
多个设备共用一条中断线,当此条中断线发生中断时,因为不可能预先知道哪个特定的设备产生了中断,因此,这条中断线上的每个中断服务例程都会被执行,以验证是哪个设备产生的中断(一般的,设备产生中断时,会标记自己的状态寄存器,中断服务例程通过检查每个设备的状态寄存器来查找产生中断的设备),因此共享中断线的分配方式是比较常见的。(2)中断线动态分配
一条中断线在可能使用的时刻才与一个设备驱动程序关联起来,这样一来,即使几个硬件设备并不共享中断线,同一个中断向量也可以由这几个设备在不同时刻运行。2.1.2、特性
(1)中断处理程序正在运行时,CPU会通知中断控制器屏蔽产生此中断的中断线。此中断线发出的信号被暂时忽略,当中断处理程序结束时恢复此中断线。(2)在中断服务例程的设计中,原则上是立即处理紧急的操作,将非紧急的操作延后处理(交给软中断进行处理)。
(3)中断处理程序是运行在中断上下文,但是其是代表进程运行的,因此它所代表的进行必须处于TASK_RUNNING状态,否则可能出现僵死情况,因此在中断处理程序中不能执行任何阻塞过程。
/ 13
action=(struct irqaction*)Kmalloc(sizeof(struct irqaction),GFR_ATOMIC);……
此handler就是刚才介绍的handle_IRQ_event 函数中要处理的handler。action->handler=handler;action->flags=irqflags;action->maks-0;action->name=devname;action->next=NULL;action->dev_id=dev_id;retval=setup_irq(irq,action);return retval;}
2.3、软中断处理
2.3.1、软中断的开关
禁止下半部,如softirq、tasklet和workqueue等: local_bh_disable();local_bh_enable();需要注意的是,禁止下半部时仍然可以被硬中断抢占。软中断由softirq_action结构体表示: struct softirq_action { void(*action)(struct softirq_action *);/* 软中断的处理函数 */ };2.3.2、注册软中断处理函数 /** * @nr: 软中断的索引号 * @action: 软中断的处理函数
*/void open_softirq(int nr, void(*action)(struct softirq_action *)){ softirq_vec[nr].action = action;} 例如:
open_softirq(NET_TX_SOFTIRQ, net_tx_action);open_softirq(NET_RX_SOFTIRQ, net_rx_action);
/ 13
函数,而在do_IRQ()函数中,会根据中断向量号,从中断描述符数组中获取对应的中断描述符,如下图: 整个中断描述符结构如下: struct irq_desc {
struct irq_data irq_data;/* irq的统计信息,在proc中可查到 */ unsigned int __percpu *kstat_irqs;/* 回调函数,当此中断产生中断时,会调用handle_irq,在handle_irq中进行遍历irqaction链表
* handle_simple_irq 用于简单处理;
* handle_level_irq 用于电平触发中断的流控处理;
* handle_edge_irq 用于边沿触发中断的流控处理;
* handle_fasteoi_irq 用于需要响应eoi的中断控制器;
* handle_percpu_irq 用于只在单一cpu响应的中断;
* handle_nested_irq 用于处理使用线程的嵌套中断; */irq_flow_handler_t handle_irq;#ifdef CONFIG_IRQ_PREFLOW_FASTEOI irq_preflow_handler_t preflow_handler;#endif
/* 中断服务例程链表 */ struct irqaction *action;
/* IRQ action list *//* 状态 */ unsigned int status_use_accessors;/* 函数调用中使用,另一个名称为istate */ unsigned int
core_internal_state__do_not_mess_with_it;/* 嵌套深度,中断线被激活显示0,如果为正数,表示被禁止次数 */ unsigned int
depth;
/* nested irq disables */ unsigned int
wake_depth;
/* nested wake enables */ /* 此中断线上发生的中断次数 */ unsigned int
irq_count;
/* For detecting broken IRQs */ /* 上次发生未处理中断时的jiffies值 */ unsigned long
last_unhandled;
/* Aging timer for unhandled count */ /* 中断线上无法处理的中断次数,如果当第100000次中断发生时,有超过99900次是意外中断,系统会禁止这条中断线 */ unsigned int
irqs_unhandled;atomic_t
threads_handled;
/ 13
core_internal_state__do_not_mes_with_it成员是用于记录此中断线状态的,中断线状态有如下几种形式:
IRQS_AUTODETECT
/* 该IRQ线用来进行硬件设备探测 */ IRQS_SPURIOUS_DISABLED // 该IRQ线被禁止,是由于产生了欺骗性中断
IRQS_POLL_INPROGRESS
/* 该IRQ进行轮询检查是否发生中断 */ IRQS_ONESHOT
/* 此IRQ没有在主处理函数中进行unmasked处理 */ IRQS_REPLAY
/* IRQ线已被禁止,但前一个出现的中断还没有被应答 */ IRQS_WAITING
/* 进行硬件设备探测时,会将所有没有挂载中断服务程序的IRQ线状态设置为IRQS_WAITING,如果该IRQ上有中断产生,就清除这个状态,可以推断哪些引脚产生过中断 */ IRQS_PENDING /* IRQ已经被应答(挂起),但是内核还没有进行处理 */ IRQS_SUSPENDED
/* 此IRQ被延迟 */
3.2、中断描述符表和中断描述符数组
在中断系统中有两个名字很相像的结构,就是中断描述符表和中断描述符数组。这里我们先说说中断描述符表。一个系统中的中断和异常加起来一共是256个,它们以向量的形式保存在中断描述符表中,每一个向量是8字节(整个表大小就是8 x 256=2048字节),其主要保存着权限位和向量对应的中断或异常处理程序的入口地址。而一般的,linux会将中断描述符表中的0~31用于非屏蔽中断和异常,其他的中断用于32~255之间。CPU把中断描述符表的向量类型分为三种类型:任务门、中断门、陷阱门。CPU为了防止恶意程序访问中断,限制了中断门的权限,而在某些时候,用户程序又必须使用中断,所以Linux把中断描述符的中断向量类型改为了5种:中断门,系统门,系统中断门,陷阱门,任务门。这个中断描述符表的基地址保存在idtr寄存器中。(1)中断门
用户程序不能访问的CPU中断门(权限字段为0),所有的中断处理程序都是这个,被限定在内核态执行。会清除IF标志,屏蔽可屏蔽中断。
/ 13
信号,将IRQ1的中断向量号发到数据总线上,此时CPU会通过数据总线读取IRQ1的中断向量号。
最后,如果中断控制器需要EOI(End of Interrupt)信号,CPU则会发送,否则中断控制器自动将INT拉低,并清除IRQ1对应的中断请求寄存器位。
在linux内核中,用struct irq_chip结构体描述一个可编程中断控制器,它的整个结构和调度器中的调度类类似,里面定义了中断控制器的一些操作,如下: struct irq_chip { /* 中断控制器的名字 */ const char
*name;/* 控制器初始化函数 */ unsigned int
(*irq_startup)(struct irq_data *data);/* 控制器关闭函数 */ void
(*irq_shutdown)(struct irq_data *data);/* 使能irq操作,通常是直接调用irq_unmask(),通过data参数指明irq */ void
(*irq_enable)(struct irq_data *data);/* 禁止irq操作,通常是直接调用irq_mask,严格意义上,他俩其实代表不同的意义,disable表示中断控制器根本就不响应该irq,而mask时,中断控制器可能响应该irq,只是不通知CPU */ void
(*irq_disable)(struct irq_data *data);/* 用于CPU对该irq的回应,通常表示cpu希望要清除该irq的pending状态,准备接受下一个irq请求 */ void(*irq_ack)(struct irq_data *data);/* 屏蔽irq操作,通过data参数表明指定irq */ void
(*irq_mask)(struct irq_data *data);/* 相当于irq_mask()+ irq_ack()*/ void
(*irq_mask_ack)(struct irq_data *data);/* 取消屏蔽指定irq操作 */ void
(*irq_unmask)(struct irq_data *data);/* 某些中断控制器需要在cpu处理完该irq后发出eoi信号 */ void
(*irq_eoi)(struct irq_data *data);/* 用于设置该irq和cpu之间的亲和力,就是通知中断控制器,该irq发生时,那些cpu有权响应该irq */ int(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
1/ 13
void __percpu
*percpu_dev_id;
/* 链表中下一个中断服务例程 */
struct irqaction
*next;
/* 进行中断处理的内核线程执行函数 */
irq_handler_t
thread_fn;
/* 一个内核线程,用于执行中断处理 */
struct task_struct
*thread;
/* IRQ线,IRQ号 */
unsigned int
irq;
unsigned int
flags;
unsigned long
thread_flags;
unsigned long
thread_mask;
const char
*name;
/* 指向/proc/irq/n目录的描述符 */
struct proc_dir_entry
*dir;} ____cacheline_internodealigned_in_smp;
四、总结
在CPU里,中断和异常都会放入到一个中断描述符表中,都需要特定的处理程序进行处理,并且它们都是异步事件,内核完全不知道何时会有一个异常或者中断发生。当异常或者中断发生时,进程都会陷入内核,在内核中执行相应的处理。异常一般都是由CPU内部或者进程产生,而中断一般都是由外部设备产生。异常处理过程实际上和系统调用没什么区别(实际上系统调用是通过一个0x80异常陷入内核当中),而中断的处理过程和情况就相对来说比较复杂。
一个中断处理分为硬中断和软中断两个部分,在中断处理的过程中系统是禁止调度和抢占的,而异常处理过程中是允许的。一个中断处理程序可以抢占其他的中断处理程序,也可以抢占异常处理程序,相反的,异常处理程序却不能够抢占中断处理程序。
3-/ 13
第二篇:java-Floodlight源码分析IOFMessageListener
package net.floodlightcontroller.core;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFType;
/**
*
*
* @author
*/
public interface IOFMessageListener extends IListener
/** messages
* @param sw the OpenFlow switch that sent this message
* @param msg the message
* @param* information between listeners
* @return the command to continue or stop the execution
*/
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx);
}
IOFMessageListener接口继承了IListener接口,协议类型为
receive方法的返回值使用了IListener中的枚举类型,且receive方法没有方法体,在OFMessageFilterManager中可以看到它的实现。
第三篇:软件源码移交保密协议
系统源码授权使用保密协议
╳╳系统
源码授权使用保密协议
甲方:珠海市联进高技术有限公司乙方:
签订地点:
一、协议背景 ╳╳系统是珠海市联进高技术有限公司(以下简称甲方)为╳╳(以下简称乙方)承建的。兹双方确认甲方拥有╳╳系统全部源代码的版权,为了便于乙方更好的进行系统维护工作,并考虑到今后的业务需求变更后,对业务系统可能提出的修改要求,甲方把与业务系统相关的源代码授权乙方使用,同时双方达成以下协议。协议条款标的内容:
甲方提供给乙方的源代码,是现行╳╳系统的应用程序部分。甲方保证所提供的部分源代码与系统当前正在运行的前台程序是同一版本,利用所提供的源代码及相关资源可以直接编译生成当前系统的应用程序部分。
二、用途限定
甲方授权乙方使用源代码的方式仅限于对现行系统的程序改进之用途;乙方有义务对源代码进行保密,在任何情况下,未经甲方同意,乙方不得将此源代码提供给任何第三方。乙方并应限制有关源代码的具体使用范围,使之仅限于现行系统的维护/升级等系统开发用途,仅为直接开发人员所了解和使用,不应在同行业其他项目使用,不得用于其他用途。
三、知识产权归属 甲方拥有╳╳系统全部源代码的版权。
乙方可以对源代码进行改变,由此衍生的有关程序及源代码的知识产权由双方共同拥有。未经甲方许可,乙方不得将修改后的源代码提供给任何第三方。甲方原则上没有义务向乙方提供对源代码及其相关资讯的技术支持和培训,但双方另有协议除外。
对于由乙方使用修改后程序所引起的故障和损失,根据是初始程序内BUG引起的还是由于乙方的不当修改造成,分清责任,并视责任情况承担各自的责任。对于假若不修改程序就不会出现的故障,甲方不承担责任。在乙方使用有关源代
系统源码授权使用保密协议
码的过程中,确需甲方技术支持的,可以通过协商解决。
四、生效条件与协议终止
有关协议一旦签署,立即生效;并将长期有效,除非以下条件之一成立:
4.1、双方另有协议,并一致同意废止此协议;
4.2、乙方不再使用现行系统;
4.3、乙方主动提出终止此协议;
4.4、由于乙方过错导致系统源代码泄密,甲方有权解除此协议。
协议终止时,乙方有责任向甲方提交或立即销毁所持有、保管或控制的包含所有该源代码信息的所有文档,软件及相关资料(不含由接收方开发的后续版本所属的文档,软件及相关资料),并向甲方提供书面确认,作为法律上认可的凭据。
五、违约责任
乙方如果违反本协议第二条及第四条条款,在未经甲方许可的情况下,将甲方授权其使用的源代码或修改后的衍生源代码提供给任何第三方,均应承担对甲方的赔偿责任,方式为向甲方支付违约金人民币20万元(大写:贰拾万元整)。
六、争议解决条款
本合同一式两份,甲乙双方各执一份,具有同等法律效力。
在履行本协议中出现任何争议,双方均应首先协商解决,协商没有结果的。甲方有权向乙方所在地司法机关提起上诉。
甲方(盖章):╳╳乙方(盖章):╳╳╳╳╳╳
代表人(签字):代表人(签字):电话:╳╳╳╳
2011年 3月 15 日
电话:╳╳╳╳ 2011年 3月 15 日
第四篇:软件自组网协议栈
软件自组网流程:
设备启动之后,由主机进行扫描,由于出厂时候设备id相同均为00 00 00 00,不同的只有设备编号,主机会向00 00 00 00 ID发送查询包。此时只有1台设备同主机建立连接(该设备自动选定)。设备会向主机报告设备类型,主机会根据设备类型给该节点分配ID,设备受到新ID后,会将本ID写入flash。依次类推,可以对每一个接入设备分配不同ID。同时主机将在rom中保持一个对应设备列表:
设备ID--设备类型--设备命名。
设备列表作用为,主机断电之后不需要重新进行自组网。
此时设备命名为空。
设备命名流程:
自组网完成后,手机端软件进行查询,会发现未命名开关1-1(表示开关1的第一位),未命名开关1-2(表示开关1的第二位),未命名开关2-1(表示开关2的第一位)等,未命名插座1-1(插座1的第一位),未命名插座1-2(插座1的第二位)。客户可以对各个开关/插座进行重新命名。比如:客户家里开关1的第一位为走廊灯,就可以在手机软件中进行修改,并提交主机进行保存配置。主机在收到保存配置命令之后,主机rom中列表的设备命名项进行相应更新。如果手机软件每次开启之后会对设备命名、设备类型和主机进行同步(从主机中读取设备列表,并进行更新)。设备可以在路由配置页面(PC访问),手机APP中进行配置,两者配置功能相同。
第五篇:数据结构栈与队列报告
栈和队列上机实习
1、实验目的:
(1)熟练掌握栈的逻辑结构和操作规则,能在相应的实际问题中正确选用该结构。(2)熟练掌握栈的2种存储结构实现方法(顺序栈和链栈),两种存储结构和基本运算的实
现算法,注意栈空盒满的判断条件及它们的描述方法。
(3)熟练掌握队列的逻辑结构和操作规范,能在相应的实际问题中正确选用该结构。(4)掌握循环队列与链队列两种存储结构的实现,熟练掌握各种队列基本运算的实现。
2、实验要求:
(1)顺序栈的插入、删除,栈顶数据元素的读取。(2)链栈的插入、删除,栈顶数据元素的读取。(3)循环队列的插入、删除。(4)链队列的插入、删除。
3、实验内容: ① 栈
(1)抽象数据类型定义
typedef struct
{
ElemType data[MaxSize];
//栈的空间大小为MaxSize
int top;
//设置栈顶指针
}SqStack;
//栈的结构定义
在本次实验中,首先建立一个空栈,进入主程序后首先初始化栈为其分配空间,然后进入菜单选择界面,通过不同的数字输入,实现入栈,出栈,读取栈顶元素,显示栈的所有元素,栈的长度,释放栈等操作。
(2)存储结构定义及算法思想
在栈结构体的定义中,typedef int Typeelem 为整型,存储结构(入栈)如下:
cin>>a;
s->top++;
//在入栈是首先将栈顶指针向上加1
s->data[s->top]=a;
//与数组赋值一样,直接赋值
//其他存储与此类似,都是直接赋值与数组的某一位
退栈函数模块:
void Pop(SqStack * &s){
//对指针的引用
if(s->top ==-1){
cout<<“栈是空栈,不能退栈”< //首先判断是否为空栈,若为空,则退出 return;} cout<<“退栈的元素为:”< //显示退栈元素 s->top--; //栈顶元素减1,指向实际栈的最上面 } 显示栈所有元素函数模块: void DispStack(SqStack *s){ //从栈顶到栈底顺序显示所有元素 int i;cout<<“栈的元素分别为:”< //同过循环实现实现从栈顶元素到栈底元素的遍历以输出 } cout< 栈结构的入栈和退栈是两个相反的过程,先进后出,入栈是先让栈顶指针加1,指向未被赋值位置,然后进行赋值,退栈是先取出退栈元素,然后栈顶元素减1,指向推展后的实际栈顶。诸如读取栈顶元素,显示栈的元素,读取栈的长度,都是用过对栈顶指针实现相关操作。 (3)实验结果与分析 ② 循环队列 (1)抽象数据类型定义 typedef struct { ElemType elem[Maxqsize]; //循环队列的长度为MaxSize int front,rear; //设置队列的头指针和尾指针 }SqQueue; //循环队列的结构体定义 在本次实验中,首先建立一个空队列,进入主程序后首先初始化队列为其分配空间,然后进入菜单选择界面,通过不同的数字输入,实现入队,出队,显示队列的所有元素,队列的长度,释放队列等操作。 (2)存储结构定义及算法思想 在队列结构体的定义中,typedef int Typeelem 为整型,存储(入队)结构如下: q->rear=(q->rear+1)%Maxqsize; //尾指针加1 q->elem[q->rear]=a; //将入队元素装到新的空尾部 在此队列的存储结构的实现:先让队尾指针进1,再将新的元素加入到队尾指针所指示的位置,因此,队尾指针指示实际的队尾位置,队头指针指示实际队头的前一位置,要想退出队头元素,必须先让队头指针进1,才能取出队头元素。 退队函数模块如下: void deQueue(SqQueue *&q){ //对指针的引用 if(QueueEmpty(q)) { //调用带返回值的判断空队函数 cout<<“队列为空”< //判断队列是否为空 } q->front=(q->front+1)%Maxqsize; //队头指针进1 cout<<“退队的元素为:”< //取出队头元素 } 遍历队表函数: void displayqueue(SqQueue *q){ int m;m=q->front+1; //队头元素进1,指向实际队头 if(QueueEmpty(q)) { cout<<“队列为空”< //判断是够为空队 } cout<<“所有队列元素为:”< while(q->rear+1>m){ cout< //通过循环遍历所有元素 m++; } cout< 循环队列的入队和退队分别是在队尾与队头跟别进行操作的,通过队头队尾指针的操作便可实现对队列的相关操作。 (3)实验结果与分析 ③ 心得体会 本次上机是做栈与队列的操作,这次实验,我有意的用到了对指针的引用与指针实现子函数功能的调用,刚开始编译的时候也有错误,但是在慢慢的摸索中,也逐渐掌握了它们的用法,这次实验也让我熟练了对队列与栈存储结构的应用。 附录: 顺序表源代码: 栈: #include void InitStack(SqStack * &s) //建立一个空栈,即将栈顶指针指向-1即可 的引用 { s=(SqStack *)malloc(sizeof(SqStack));s->top=-1;} void ClearStack(SqStack * &s) //释放栈s占用的存储空间 { free(s);} void StackLength(SqStack *s) { cout<<“栈的长度为:” <<(s->top +1)< int StackEmpty(SqStack *s){ return(s->top==-1);} void Push(SqStack *&s){ if(s->top==MaxSize-1) { cout<<“栈满”< // s=(SqStack *)realloc(s,sizeof(SqStack));} int a; 指针 cout<<“请输入入栈元素”< void Pop(SqStack * &s){ if(s->top ==-1){ cout<<“栈是空栈,不能退栈”< return;} cout<<“退栈的元素为:”< void GetTop(SqStack * &s,ElemType &e){ if(s->top==-1){cout<<“空栈”< void DispStack(SqStack *s) //从栈顶到栈底顺序显示所有元素 { int i;cout<<“栈的元素分别为:”< cout<<“请选择功能”< cout<<“ 入栈 1”< cout<<“ 出栈 2”< cout<<“ 读取栈顶元素 3”< cout<<“ 显示栈所有元素 4”< cout<<“ 栈的长度 5”< cout<<“ 释放栈 6”< cin>>k; switch(k) { case 1: Push(s);break; case 2: Pop(s);break; case 3: GetTop(s,e);cout<<“栈顶元素为: ”< case 4: DispStack(s);break; case 5: StackLength(s);break; case 6: ClearStack(s);break; default :break; } } } 队列: #include TypeElem elem[Maxqsize]; int front,rear;}SqQueue;void InitQueue(SqQueue *&q){ q=(SqQueue *)malloc(sizeof(SqQueue)); q->front=q->rear=0;} void ClearQueue(SqQueue *&q){ free(q);exit(0);} void QueueLength(SqQueue *q){ cout<<“队列长度为:”<<(q->rear-q->front+Maxqsize)%Maxqsize< return(q->front==q->rear); } void enQueue(SqQueue *&q){ int a; if((q->rear+1)%Maxqsize==q->front) { cout<<“队列已满,无法插入”< } cout<<“请输入插入元素”< cin>>a; q->rear=(q->rear+1)%Maxqsize; q->elem[q->rear]=a;} void deQueue(SqQueue *&q){ if(QueueEmpty(q)) { cout<<“队列为空”< } q->front=(q->front+1)%Maxqsize; cout<<“退队的元素为:”< } void displayqueue(SqQueue *q){ int m;m=q->front+1; if(QueueEmpty(q)) { cout<<“队列为空”< } cout<<“所有队列元素为:”< while(q->rear+1>m) { cout< m++; } cout< int k=0; SqQueue *q; InitQueue(q); if(QueueEmpty(q))cout<<“队列为空”< while(1){ cout<<“请选择功能”< cout<<“ 入队 cout<<” 出队 cout<<“ 队列长度 cout<<” 显示队列元素 cout<<“ 释放栈 cin>>k; switch(k) { case 1: enQueue(q);break; case 2: deQueue(q);break; case 3: QueueLength(q);break; case 4: displayqueue(q);break; case 5: ClearQueue(q);break; default :break; } } } 1”< 2“< 4“<