加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

如何在中断处理程序中调用printf

(2009-01-14 12:53:05)
标签:

it

分类: 编程技巧
如何在中断处理程序中调用printf
 
在操作系统中,中断处理程序(在Linux中称为上半部)一般都需要快速地返回。(以下如果没有明确说明,中断处理指的都是中断处理的上半部)大部分中断处理工作是由内核线程来完成的。在内核线程里,中断是开启的,可以接收更多中断。在中断处理程序只是做少量的必要的工作。比如激活一个中断处理内核线程。(当然,操作系统的实现千差万别。Linux可以用所谓的Tasklet和下半部,也可以用内核线程。而Solaris就用内核线程来做大部分的中断事务处理。)中断处理的过程中,中断是被禁止的。以防止重入。中断处理程序必须快速返回,以便及时开启中断。如果不能及时开启中断,就有可能造成中断丢失。
 
在中断处理程序里调用printf,其实并不是个好主意。printf是向文件输出格式化的字符串。在内核里,printf(在Linux内核中是printk)向系统控制台发送内核打印信息。注意是系统控制台。这就是为何telnet到目标机就会看不到内核打印的原因。在当前的开发环境里,系统控制台就是UART串口。也就是你看到的USB MiniB的接口。虽然它看上去像USB MiniB,其实内部连线是UART(没有仔细查看原理图,只是和硬件部门确认了一下)
 。而我们的UART的波特率是9600。可见串口输出有多慢。况且控制台有各种各样的。有VGA,电传打字机(PDP-6上可能有,已经进博物馆了),UART等等。很难说控制台的速度到底有多慢。在中断处理程序里调用控制台打印例程的确不是好主意。但是并不是说在那里不能调用printf或printk。我查了printf和printk的实现代码。了解到一般printf或printk会调用write或putc之类的更底层的例程。这类例程的实现也不尽相同。我无法确认putc之类的例程在操作VGA或UART的时候是否依靠中断驱动。虽然本质上VGA和UART比较简单。输出一个字符并不需要中断支持,如VGA,只要写视频内存即可。UART输出例程一般使用轮询方式。但是我已经说过,各种实现都不相同。如果某个输出例程使用中断驱动方式。而你恰恰在中断禁止的时候调用它(也就是在中断处理上半部中调用printf或printk)问题就来了。导致不能正常打印输出。
在中断处理上半部调用printf或printk输出信息到控制台必然导致中断处理时间延长很多(当然有的printf和printk只是打印到内存区)。由于这时中断是禁止的。外部中断有可能会丢失。这种情况在繁忙的网络处理器中尤其严重。中断非常快速地到来,如果在中断处理程序里调用printf或printk,CPU几乎会被占满。如果非要在中断处理程序里调用printf或printk那该这么办?这种情况在驱动程序开发初期的调试阶段很常见。有一个变通的办法。如果中断不停地过来,你可以选择是否只打印一次或者若干次,可以选择打印最开始的几次还是最后的几次,可以选择把打印次数降到原来的1%或0.1%等等。当然,这需要一些小计巧。就是维护一个打印计数。
如:
 
int interrupt_handler(void)
{
 static int count = 0;
 ......
 if(!((count++) % 100)))
  printk("blur blur blur\n");
 ......
}
可以把原来的打印信息减少到1%。各种方法,不一而足。
强烈建议在最终release的代码中去掉中断打印。你可以用编译开关来禁止中断打印,以便以后维护。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有