当前位置:  操作系统/服务器>linux
本页文章导读:
    ▪Linux Kernel Development——中断      中断的上半部和下半部 中断是系统硬件与处理器通信的一种机制。当硬件设备发生中断的时候,内核会被打断,并执行中断对应的处理函数。在执行中断服务程序的时候,内核处于中断上下.........
    ▪unpV1的源码的使用方法       正准备把unpV1再看一遍,但是居然把unp的编译方法给忘记了。查了查资料,才弄好。这就是以前没有养成做笔记的习惯所带来的后果了,浪费了20分钟时间。现在把unpV1源码的使用方法记录下.........
    ▪read 与 fread 的区别的误解(转载)      原文地址:http://blog.sina.com.cn/s/blog_93b45b0f01014qyb.html 前多时间梳理了一些Linux上的编程,其实就是认识的大量的系统调用(POSIX)。这里有一个我们经常提出的问题就是fread,read的区别。(当.........

[1]Linux Kernel Development——中断
    来源:    发布时间: 2013-10-22

中断的上半部和下半部

中断是系统硬件与处理器通信的一种机制。当硬件设备发生中断的时候,内核会被打断,并执行中断对应的处理函数。在执行中断服务程序的时候,内核处于中断上下文。此时,如果不禁止中断,该中断处理程序仍有可能被其他中断事件所打断。因此,我们希望中断服务程序执行的越快越好。而通常一个中断服务程序要做很多的事情,比如网卡中断发生时,不仅要对网卡作应答,还要将网络数据包拷贝到系统内存,并作相应处理后交给合适的协议栈。这样,既想速度快,又要完成大量的工作,两者必须作出取舍。

内核对这个问题的处理比较巧妙:内核将整个的中断处理流程分为了上半部和下半部。上半部的功能是"登记中断",当一个中断发生时,它进行相应地硬件读写后就把中断例程的下半部挂到该设备的下半部执行队列中去。因此,上半部执行的速度就会很快,可以服务更多的中断请求。但是,仅有"登记中断"是远远不够的,因为中断的事件可能很复杂。因此,Linux引入了一个下半部,来完成中断事件的绝大多数使命。下半部和上半部最大的不同是下半部是可中断的,而上半部是不可中断的,下半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!下半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。 内核提供了很多下半部执行的机制,如软中断、tasklet和等待队列等。

拿网卡来举例,在linux内核中,当网卡一旦接受到数据,网卡会通过中断告诉内核处理数据,内核会在网卡的中断处理函数(也就是上半部)执行一些网卡硬件的必要设置,因为这是在中断响应后急切要干的事情。接着,内核调用对应的下半部函数来处理网卡接收到的数据,因为数据处理没必要在中断处理函数里面马上执行,可以将中断让出来做更紧迫的事情。

中断处理函数

中断处理程序使用硬件设备驱动程序的组成部分,驱动程序通过request_irq()注册并激活一个中断处理函数。而在驱动程序卸载时,通过free_irq()注销中断处理函数,并释放中断线。需要注意的是,request_irq()可能会睡眠,因此不能在中断上下文或者不允许阻塞的代码中使用;必须在进程上下文中调用free_irq()。

中断处理函数的原型为:

1: /** 2: * enum irqreturn 3: * @IRQ_NONE interrupt was not from this device 4: * @IRQ_HANDLED interrupt was handled by this device 5: * @IRQ_WAKE_THREAD handler requests to wake the handler thread 6: */ 7: enum irqreturn { 8: IRQ_NONE = (0 << 0), 9: IRQ_HANDLED = (1 << 0), 10: IRQ_WAKE_THREAD = (1 << 1), 11: }; 12:   13: typedef enum irqreturn irqreturn_t; 14:   15: typedef irqreturn_t (*irq_handler_t)(int, void *);
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

中断处理函数是无需重入的,因为当一个中断处理函数在执行时,该中断线上的其他中断都会被屏蔽掉,以防止在同一个中断线上接收另一个中断。

一个典型的中断处理函数实例:RTC中断处理函数

1: /* 2: * A very tiny interrupt handler. It runs with IRQF_DISABLED set, 3: * but there is possibility of conflicting with the set_rtc_mmss() 4: * call (the rtc irq and the timer irq can easily run at the same 5: * time in two different CPUs). So we need to serialize 6: * accesses to the chip with the rtc_lock spinlock that each 7: * architecture should implement in the timer code. 8: * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) 9: */ 10:   11: static irqreturn_t rtc_interrupt(int irq, void *dev_id) 12: { 13: /* 14: * Can be an alarm interrupt, update complete interrupt, 15: * or a periodic interrupt. We store the status in the 16: * low byte and the number of interrupts received since 17: * the last read in the remainder of rtc_irq_data. 18: */ 19:   20: spin_lock(&rtc_lock); 21: rtc_irq_data += 0x100; 22: rtc_irq_data &= ~0xff; 23: if (is_hpet_enabled()) { 24: /* 25: * In this case it is HPET RTC interrupt handler 26: * calling us, with the interrupt information 27: * passed as arg1, instead of irq. 28: */ 29: rtc_irq_data |= (unsigned long)irq & 0xF0; 30: } else { 31: rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); 32: } 33:   34: if (rtc_status & RTC_TIMER_ON) 35: mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); 36:   37: spin_unlock(&rtc_lock); 38:   39: /* Now do the rest of the actions */ 40: spin_lock(&rtc_task_lock); 41: if (rtc_callback) 42: rtc_callback->func(rtc_callback->private_data); 43: spin_unlock(&rtc_task_lock); 44: wake_up_interruptible(&rtc_wait); 45:   46: kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); 47:   48: return IRQ_HANDLED; 49: } 50: #endif

.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color:

    
[2]unpV1的源码的使用方法
    来源:    发布时间: 2013-10-22

正准备把unpV1再看一遍,但是居然把unp的编译方法给忘记了。查了查资料,才弄好。这就是以前没有养成做笔记的习惯所带来的后果了,浪费了20分钟时间。现在把unpV1源码的使用方法记录下来:

        1.  编译静态库并复制到/usr/lib和/usr/lib64.

cd lib
make
cd ..
sudo cp libunp.a /usr/lib
sudo cp libunp.a /usr/lib64

         2.修改unp.h

#include "../config.h" 的../去掉,即#include "config.h"
加上#define MAX_LINE 2048
注释掉struct in_pktinfo结构体的声明

         3.复制unp.h和config.h到/usr/include

         4.编译方法,链接libunp.a静态库就可以了,即-lunp。举个例子:

${CC} -g -o tcpserv01 tcpserv01.c -lunp

 

         

本文链接


    
[3]read 与 fread 的区别的误解(转载)
    来源:    发布时间: 2013-10-22

原文地址:http://blog.sina.com.cn/s/blog_93b45b0f01014qyb.html

 

前多时间梳理了一些Linux上的编程,其实就是认识的大量的系统调用(POSIX)。这里有一个我们经常提出的问题就是fread,read的区别。(当然这两个分别代表了操作文件系统的两套不同的函数,包括open,read, write, seek 等)。我们都知道,他们的区别就是一个(read)是UNIX 中的系统调用,是类UNIX系统,提供给程序员操作文件的接口(要不然你如何操作文件?);而另外一个则是C语言提供的读取文件的函数库,自然这个函数库(ANSI)的实现是以对应的系统调用为基础的。

那么为什么C语言的函数库需要向我们提供这样的包装,而其他的系统调用(像进程、线程管理与通信等等)没有这样的包装呢?

这当然是有原因的,也就是我们常说的有缓冲读写和无缓冲读写。

 

但是,我们进一步学习了UNIX系统中,直接I/O的概念之后,对上面的了解需要更深一步了。

 

为什么要缓冲?

 

我们先不管用户态、核心态这些事情,我们先思考,读取外设上的文件为什么需要缓冲。

(我们知道,一般意义上流的概念已经被使用到了文件读写中,这个概念与缓冲的概念没有关系。)

我们使用函数向某个文件从当前流标签所在位置,读取n个字符。我们也会使用函数想文件的某个流位置写如n字符。但是,当这种写的动作小、而频繁。每次写又必须反映到硬盘上,也就是说需要频繁的操作硬盘,写一些小的更改,这是非常耗损效率。所以自然我们想到了,我们设立一个缓冲区,将那些要写如的数据先写到缓冲区中,当缓冲区满,或者其他情况发生的是否,我们在一起将他们写入到硬盘上。这样可以大大提高应用程序读写文件的速度。

 

这就是为什么需要缓冲,根本原因我认为是磁盘等外设的数据还和内存的速度相差甚远,所以我们不希望由于操作外设的原因让本来很快的内存和CPU跟着一起慢,我们想的办法:一是异步写(但这有时候不能符合应用要求),二就是缓冲读写。

 

而我们通常所理解的就是,read体系,就是那种无缓冲读写,不管是读还是写,调用这个体系的函数,会马上启动一次外设操作,读取数据或者写入数据。而fread体系则,使用了缓冲读写的方式,一定时间才调用read体系的函数。

 

上面的认识,事实上可以一定程度上说明问题的。但是,我们也太低估UNIX系统的智商了,要知道,不只是应用程序需要与外设进行交互,操作系统更是要与外设频繁的交互。(事实上应用程序是通过操作系统与外设交互的,所以就有了用户态和核心态概念)。

 

我们知道,应用程序要读写文件,一般是通过操作系统的(这样才发挥了操作系统管理系统的各项硬软件的功能)。读写的过程并不是直接将外设中的数据,直接往用户应用程序的空间传送(虽然理论上好像可以,内核还不能往用户空间写数据?但是这不符合这种隔离的思想),而是首先由内核发出外设操作,将数据传送到内核空间中(DMA技术),然后从内核传送的用户空间中。这样的好处就是能够隔离开应用程序与硬件设备的直接交流(那会导致应用软件设计的复杂都增长)。但是这也导致了我们通常说的“多拷贝”问题。

 

在操作系统内核的管理下,数据想要从一个文件到另外一个文件,需要经过:

文件1(外设)——>内核空间——>用户空间——>内核空间——文件2(外设)。

这里还是假设用户空间里面该数据没有拷贝动作,我们可以看到,中间的拷贝过程全部发生在内存中,只是分在内核与用户的区别。

 

这种样的过程其实是伤害效率的,但是如果不是对读写效率的要求过于苛刻,仍然使用这种方法。

 

事实上,read体系也有自己的缓冲机制,但是我们可以通过设置(open函数中DIRECT标志),放弃这种方式。

我们可以说,fread是在用户应用程序空间中,自己建立了一个缓冲机制,这种缓冲机制和内核read的缓冲机制并不冲突。

事实上,当我们使用read体系的是否,我们放弃了应用程序空间中的缓冲机制,但是如果不设置DIRECT标志,内核中的缓冲机制依然存在。

 

我们还有一种特殊的读写应用程序,叫着自缓冲读写,其实fread就是这样一种方式。只是它没有放弃内核的缓冲机制。但是对于复杂应用程序,例如数据库,这种对读写效率要求高的地方,他们使用了自己定义缓冲机制并且毅然放弃了内核的缓冲方式,为什么呢?因为内核缓冲方式,对缓冲数据何时应该存入到硬盘上,那些数据应该留下来更久没有应用背景相关的信息,所以它所出来的决策,通常是盲目的。但是,如果应用程序自己设置这种缓冲,可以很大程度上弥补这一问题。

 

 

缓冲I/O绝对有它的好处,这种机制的使用不仅在用户空间中,也在内核实现时会使用。当然有是否我们为了最求某些特别的需求,会使用直接I/O方式。当然事实上,这种I/O方式,与缓冲与否不是对立的。但是往往这样做了之后,缓冲就不够。我们要使用直接I/O要慎重考虑,你应用程序的需求,例如,你需要存取大块数据。这个是否“多拷贝”无疑是一个问题。 其中取舍需要仔细考虑、权衡。

本文链接


    
最新技术文章:
▪linux系统中的列出敏感用户的脚本代码
▪a10 config backup for aXAPI
▪一键备份gitolite服务器的Shell脚本
▪nagios 分发文件实现代码
▪阿里云云服务器Linux系统更新yum源Shell脚本
NOSQL iis7站长之家
▪Linux下实现SSH免密码登录和实现秘钥的管理、...
▪Shell正则表达式之grep、sed、awk实操笔记
▪3个备份系统文件并邮件发送的Shell脚本分享
▪CentOS 6.3下给PHP添加mssql扩展模块教程
▪监控网站是否可以正常打开的Shell脚本分享
▪shell脚本编程之if语句学习笔记
▪shell脚本编程之循环语句学习笔记
▪shell脚本编程之case语句学习笔记
▪Shell脚本实现的阳历转农历代码分享
▪Shell脚本实现复制文件到多台服务器的代码分...
▪Shell脚本实现批量下载网络图片代码分享
▪Shell脚本实现检测文件是否被修改过代码分享
▪Shell脚本数组用法小结
▪Shell脚本批量重命名文件后缀的3种实现
▪C语言实现的ls命令源码分享
▪Linux下查找后门程序 CentOS 查后门程序的shell脚...
▪Shell 函数参数
▪linux shell 自定义函数方法(定义、返回值、变...
▪Shell实现判断进程是否存在并重新启动脚本分...
▪Shell脚本break和continue命令简明教程
▪Shell脚本函数定义和函数参数
▪让代码整洁、过程清晰的BASH Shell编程技巧
▪shell常用重定向实例讲解
▪awk中RS、ORS、FS、OFS的区别和联系小结
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3