首页
社区
课程
招聘
[原创]分层体系结构模式的应用
发表于: 2009-3-23 12:00 6178

[原创]分层体系结构模式的应用

2009-3-23 12:00
6178

分层体系结构模式的应用

author: liucy

前言:

软件体系结构根据项目的情况从大的方向来看可分为 从混沌到结构、分布式系统、交互式系统和适应性系统等等。

分层模式属于从混沌到结构,他适用一项工作可以分解为子任务,其中每个子任务处于一个特定的抽象层次上。

分层的应用很广泛,Windows系统/Linux系统中都有这种应用的存在,就是嵌入式硬件中也存在,如RMI的mips体系结构的板子中的加密引擎中就存在这种应用。

说明:

这里从Windows驱动或linux中总结一下分层体系结构一些特点,思想可为我们所用。

1 使用条件:  一个需要分解的比较大的大系统。如Windows内核,他是采用了层次结构,这是我们都知道的。比较著名的网络协议的iso 7层模型。

2 分层的标准: 这个没有一定的标准,但是简单可以按照一个层次只做一件事的原则来分解。

3 层次的要求:下层不可见上层,上层可见下层。也就是说下层暴露的接口可以为上层可见和使用,而上层暴露的接口不可以为下层可见和使用。

4 一个统一的数据结构作为数据流再所有层次中流转,作为数据传递的介质。Windows中就是常见的IRPs,Linux网络中是sk_buff结构。

5 上面实现了从上向下单向数据流,可需要双工怎么办,也就是底层需要调用上层?如Windows驱动中底层硬件完成了操作,如何通知上层应用呢?注意,这里不是说可以通过轮训或者中断等等方法之类来调用上层的问题,而是如何调用上层模块的方式。

笼统的说是采用回调的方式,简单实用。

5.1   linux内核网络部分实现的层次回调

linux中是使用了模块注册钩子方式,固定了层次之间的关系。在底层收到事件需要传递到上层时,使用注册的钩子,把数据传递到上层模块。

   如网卡接收到数据后,需要传递给ip层,看看他是如何做的。

   先看一个数据结构:

        struct packet_type {
        __be16                        type;        /* 上层的类型,这里是ip协议:0x0800 */
        struct net_device        *dev;       
        int                        (*func) (struct sk_buff *,
                                         struct net_device *,
                                         struct packet_type *,
                                         struct net_device *);  /* 这是关键所在。上层注册的回调函数 */

        struct sk_buff                *(*gso_segment)(struct sk_buff *skb,
                                                int features);
        int                        (*gso_send_check)(struct sk_buff *skb);
        void                        *af_packet_priv;
        struct list_head        list;    /* 链路层保持的上层协议注册的结构链表。*/
};

   ip模块初始化:

        static struct packet_type ip_packet_type = {
        .type = __constant_htons(ETH_P_IP),
        .func = ip_rcv, /* 接收回调函数 */
        .gso_send_check = inet_gso_send_check,
        .gso_segment = inet_gso_segment,
        };

        static int __init inet_init(void)
        {
            ....

            dev_add_pack(&ip_packet_type); / * 链路层提供的接口,注册了ip层回调到底层. */

            ....
        }

       这样,在底层链路层收到tcp/ip数据后,根据链路层中协议字段值作为.type的检索值,调用func。这里的func就是ip_rcv.
   
       由于这种模块间紧注册的关系,造成linux提供的只能以hook点方式来过滤数据。
      
5.2 Windows内核实现的层次回调

        Windows内核的层次调用与linux不同:Windows通过irp动态完成回调的处理,也就是通过模块间的数据流同时携带了控制流,而不是如同linux通过模块间注册回调来完成,这是两种不同的思路。

        windows这种设计有它的灵活性,比如更加方便的动态添加过滤模块。

        下面看看windows如何处理的。首先了解一下单个i/o 栈结构:

        MajorFunction
        MinorFunction
        Flags
        Control
        Parameters (32 bytes)
        DeviceObject
        FileObject
        CompletionRoutine      ---> 关键点, 回调函数地址
        Context Pointer

        通过IoSetCompletionRoutine设置回调:

        #define IoSetCompletionRoutine( Irp, Routine, CompletionContext,
                        Success, Error, Cancel ) {           PIO_STACK_LOCATION irpSp;  
                                ASSERT( (Success) | (Error) | (Cancel) ? (Routine) !=
                                NULL : TRUE );  
                irpSp = IoGetNextIrpStackLocation( (Irp) );  
                irpSp->CompletionRoutine = (Routine);   /* 回调函数哦 */
                irpSp->Context = (CompletionContext);  
                irpSp->Control = 0;  
                if ((Success)) { irpSp->Control = SL_INVOKE_ON_SUCCESS; }  
                if ((Error)) { irpSp->Control |= SL_INVOKE_ON_ERROR; }  
                if ((Cancel)) { irpSp->Control |= SL_INVOKE_ON_CANCEL; }
        }

       注意了,这个回调函数注册位置不是在本驱动所在的stack位置,而是下一个驱动的stack位置上。这样做,一方面是最底层驱动并不需要回调函数,他在完成任务后直接调用IoCompleteRequest();另一方面从空间利用的角度来考虑的,一般分配irp的驱动并不需要i/0 stack,而最低层驱动并不需要完成函数,所以把完成例程放到了下一个i/o栈。

        i/o管理器在这里也起到关键作用。在完成回调中,i/o管理器分为两个阶段完成:线程无关处理和线程相关处理。线程无关处理主要是个分层驱动的回调接口的调用;而线程相关处理是把irp中数据copy给相关的线程。       

6 总结

        这里列的技术大家可能都知道,仅是对比一下,看看两种系统对分层模式再系统设计中的应用。重点是在系统中如何使用分层模式。

        两种不同分层的实现:模块注册回调(注册完成即是层次确定之时)和数据流中注册回调(层次确定通过设备链动态完成),各有优势。在系统设计过程中综合考虑,可以采用不同的方案来解决。

        有不对的地方,请大家指教。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 563
活跃值: (95)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持下
2009-3-23 12:12
0
游客
登录 | 注册 方可回帖
返回
//