Linux内核中断和异常分析(中)

简介:

在linux内核中,每一个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线。所有现在存在的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,上次讲到单片机的时候,我就讲到了单片机中断的一些概念。我们现在来看一幅图,更好说明一个问题:

     这下面的这幅图是51单片机的一个关于矩阵键盘的学习的一个proteus的仿真电路图。

其中P3.2和P3.3为外部中断引脚,当可编程控制器(51MCU)收到外部中断响应的时候,会执行一些特定的操作,当然这需要开发者去编写一个中断初始化程序和一个中断服务程序。


那么,可编程中断控制器会做以下的操作:

1、监视IRQ线,我们可以理解就是监视单片机外部中断的IO口,检查产生的信号。如果有条或者两条以上的IRQ上产生信号,就选择引脚编号较小的IRQ线。

2、如果一个引发信号出现在IRQ线上:

   a.把接收到的引发信号转换成对应的向量。

   b.把这个向量存放在中断控制器的一个I/O端口,从而允许CPU通过数据总线读这个向量。

   c.把引发信号发送到处理器的INTR引脚,即会产生一个中断。

   d.等待,直到CPU通过把这个中断信号写进可编程中断控制器的一个I/O端口来确认它,当这种情况发送时,清INTR线。

3、最后一步返回到第一步继续监视,然后依次执行。


    当然,也存在着一些更加高级的可编程中断控制器,其中ARM算一种,Intel也是,等等。。。单片机算是最简单的一种。像多APIC系统的结构,会存在以下的一个图的关系:


中断信号通过IO引脚,然后通过中断控制器I2C总线与相应的CPU进行通信。

一般情况下,有两种分发的方式:

1、静态分发模式:IRQ信号传递给重定向表相应的项中所列出的本地APIC,然后中断立即传递诶一个特定的CPU,或者是一组CPU,或者是所有的CPU。其实这是广播模式的一种模型,接触过UNIX网络编程应该会知道。

2、动态分发模式:如果处理器正在执行最低优先级的进程,IRQ信号线就会传递给这种处理器的本地APIC。也就是说,在CPU内部有一个控制优先级的寄存器,用来计算当前运行进程的优先级。如果两个或者多个CPU共享最低优先级,那么就利用仲裁的技术在这些CPU之间分配负荷等等的形式。

上篇文章曾介绍异常的相关,异常有很多种,在8086处理器可以找到多达20种不同的异常,内核必须为每种异常提供一个专门的异常处理程序。对于某些异常,CPU控制单元会在开始执行异常处理程序前产生一个硬件出错码,并且压入内核态的堆栈中去。

     关于这个异常处理信息,我们有必要来了解以下perror这个函数。

perror( ) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno(这里的说法不准确,errno是一个宏,该宏返回左值) 的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你输入的一些信息和现在的errno所对应的错误一起输出。
用法: void perror(const char *s); perror ("open_port");
我们写段代码来看看就知道了:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	FILE *filp ; 
	filp = fopen("txt","r"); 
	if(NULL == filp)
	{
		perror("没有相应的文件");
	}
	return 0 ;
}
运行结果:

在当前目录下,找不到txt这个文件,所以perror会根据相应的出错信息打印No such file or directory。


看了这个函数的应用,相信更会理解上面的异常的相关知识。当然还有更多的,比如段错误,段错误是最常见的,一些初学者在使用指针的时候,没有分配相应的空间,这时候给指针赋值,虽然没有语法错误,但可能会有警告。当程序运行的时候,就会自动退出并提示段错误(Segment fault),这一般是在linux上会出现这两个英语单词,在window的Devcpp上是这样,:


     段错误的产生原因有很多种,程序在进行递归的时候,如果没有相应的条件退出的话,程序一旦进行死循环递归之后就会产生爆栈错误,也就是栈被挤爆了,栈这个概念其实并不陌生。我们在写C语言程序的时候,一旦写了一个子函数,那就相当于建立了一个堆栈,一般情况下函数在执行完退出后堆栈是自动分配,自动销毁的,不用程序员去手动malloc申请内存再free释放内存。因为手动分配的内存是用了堆区的内存,而自动分配是在栈区进行分配的。在32位操作系统上,栈的大小就只有12M,所以写代码的时候,一定要记得防止爆栈错误的产生,特别是递归!在main函数中多写些子函数是有好处的,要养成良好的编程习惯。

     接下来的一篇,我将结合相应的内核驱动的代码实例来剖析linux内核中断与异常来作为文章的终结。欢迎持续关注Bruce.yang的嵌入式之旅!




  

目录
相关文章
|
9天前
|
Linux C语言
Linux内核队列queue.h
Linux内核队列queue.h
|
28天前
|
存储 Shell Linux
【Shell 命令集合 系统设置 】Linux 生成并更新内核模块的依赖 depmod命令 使用指南
【Shell 命令集合 系统设置 】Linux 生成并更新内核模块的依赖 depmod命令 使用指南
30 0
|
28天前
|
Shell Linux C语言
【Shell 命令集合 系统设置 】⭐Linux 卸载已加载的内核模块rmmod命令 使用指南
【Shell 命令集合 系统设置 】⭐Linux 卸载已加载的内核模块rmmod命令 使用指南
29 1
|
7天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【4月更文挑战第12天】 在多任务操作系统如Linux中,进程调度机制是系统的核心组成部分之一,它决定了处理器资源如何分配给多个竞争的进程。本文深入探讨了Linux内核中的进程调度策略和相关算法,包括其设计哲学、实现原理及对系统性能的影响。通过分析进程调度器的工作原理,我们能够理解操作系统如何平衡效率、公平性和响应性,进而优化系统表现和用户体验。
18 3
|
14天前
|
负载均衡 算法 Linux
深度解析:Linux内核调度器的演变与优化策略
【4月更文挑战第5天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分——内核调度器。文章将首先回顾Linux内核调度器的发展历程,从早期的简单轮转调度(Round Robin)到现代的完全公平调度器(Completely Fair Scheduler, CFS)。接着,分析当前CFS面临的挑战以及社区提出的各种优化方案,最后提出未来可能的发展趋势和研究方向。通过本文,读者将对Linux调度器的原理、实现及其优化有一个全面的认识。
|
16天前
|
Prometheus 监控 数据可视化
linux分析方法与技巧
【4月更文挑战第3天】在Linux环境中,进行日志分析和系统性能分析的关键方法包括:使用`cat`, `less`, `tail`查看和过滤日志,`logrotate`管理日志文件,`rsyslog`或`syslog-ng`聚合日志,以及通过`top`, `mpstat`, `pidstat`, `free`, `iostat`, `netstat`, `strace`, `sar`, `dstat`等工具监控CPU、内存、磁盘I/O和网络。对于高级分析,可利用Brendan Gregg的性能工具,以及Grafana、Prometheus等可视化工具。
16 2
linux分析方法与技巧
|
17天前
|
Linux 内存技术
Linux内核读取spi-nor flash sn
Linux内核读取spi-nor flash sn
13 1
|
24天前
|
监控 Linux Shell
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
39 0
|
24天前
|
存储 网络协议 Linux
【Linux 解惑 】谈谈你对linux内核的理解
【Linux 解惑 】谈谈你对linux内核的理解
22 0
|
24天前
|
消息中间件 存储 网络协议
Linux IPC 进程间通讯方式的深入对比与分析和权衡
Linux IPC 进程间通讯方式的深入对比与分析和权衡
65 0