欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > PPT文档下载
     

    中断定时和系统调用.ppt

    • 资源ID:2710228       资源大小:1,021.51KB        全文页数:55页
    • 资源格式: PPT        下载积分:8
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要8
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    中断定时和系统调用.ppt

    中断、定时和系统调用,中断和异常,中断是一种触发信号,一个CPU接收到这样一种信号后会改变它执行代码的流程,一般是从一个固定的地址执行一段预先设定好的程序。 中断的种类 同步中断:异常,软中断 程序运行过程中产生 页错误,被0除,中断指令(int),. 异步中断:中断,硬中断 由设备产生 键盘中断,时钟中断,. 中断信号常被用来泛指上述各种中断。中断信号是系统的重要和稀缺的资源。 每个中断和异常都有一个编号,0-255,称为中断向量。,中断信号处理,中断信号可以由进程或外部事件产生 中断信号的处理只能由内核完成 中断当前的程序,切换到中断处理代码 中断处理代码不属于进程 同步中断与当前进程相关 异步中断与当前进程无关 中断的结果与进程相关 中断处理条件: 中断响应时间越快越好 中断处理分成top half和bottom half。 中断嵌套 中断处理过程中对临界区的处理,中断,中断 可屏蔽中断 不可屏蔽中断 中断控制器 可编程中断控制器:PIC 单处理器环境,8259A 先进可编程中断控制器:APIC 多处理器环境,中断请求和中断控制器响应,中断请求(IRQ) 对中断请求的响应 中断控制器 产生中断的设备,8259A,8259A,80x86,0,15,异常,80x86处理器约有20个异常 常见异常 Divide error:被0除异常 Invalid opcode:无效操作码异常 Page fault:页失效异常 每个异常都有相应的异常处理函数(handler) divide_error( ), invalid_op( ), page_fault( ), .,中断门描述符,内核管理中断使用的数据结构 一个中断门描述符由8个字节组成 描述符中保存有关中断的各种信息 中断向量 中断处理函数地址 各种权限参数 i386共有3种类型的中断门描述符 Task Gate Descriptor:任务门描述符 Interrupt Gate Descriptor:中断门描述符 Trap Gate Descriptor:自陷门描述符,不同类型的中断门描述符,中断门描述符表,内核维护的一个由256个表项的表,每个表项为一个中断门描述符。 一个中断门描述符由8个字节组成,整个表共用内存空间2048字节。 中断门描述符表保存在内存中,其起始地址保存在一个专用的寄存器中。 操作系统在使能中断之前要初始化中断门描述附表。,中断门描述符表结构,0,1,32,33,128,255,0号异常:Divide error,被0除,1号异常:Debug,调试,0号中断:IRQ0,1号中断:IRQ1,中断指令:int 80,Linux对中断的使用,中断指令int int指令可以产生任意向量的中断 Linux对中断的划分 中断门:interrupt gate,用于硬件中断信号产生的中断,只能在内核模式下使用。 系统门:system gate,用于实现系统调用,可由用户模式下的代码产生。 int3, into, bound, int 80. 自陷门:trap gate,用于其他异常的中断,只能在内核模式下使用。,初始化中断门描述符表,初级初始化:setup_idt() 缺省的中断处理函数:ignore_int() 打印“Unknown interrupt“ 用ignore_int()填充中断门描述符表中所有表项的中断处理函数 ignore_int函数应该永远不会被调用,除非系统硬件或内核出现问题。,/* This is the default interrupt “handler“ :-) */ int_msg: .asciz “Unknown interruptn“ ALIGN ignore_int: cld pushl%eax pushl %ecx pushl %edx pushl %es pushl %ds movl $(_KERNEL_DS),%eax movl %eax,%ds movl %eax,%es pushl $int_msg call SYMBOL_NAME(printk) popl %eax popl %ds popl %es popl %edx popl %ecx popl %eax iret,arch/i386/kernel/head.S: ignore_int,/* * setup_idt * * sets up a idt with 256 entries pointing to * ignore_int, interrupt gates. It doesn't actually load * idt - that can be done only after paging has been enabled * and the kernel moved to PAGE_OFFSET. Interrupts * are enabled elsewhere, when we can be relatively * sure everything is ok. */ setup_idt: lea ignore_int,%edx movl $(_KERNEL_CS 16),%eax movw %dx,%ax /* selector = 0x0010 = cs */ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ lea SYMBOL_NAME(idt_table),%edi mov $256,%ecx rp_sidt: movl %eax,(%edi) movl %edx,4(%edi) addl $8,%edi dec %ecx jne rp_sidt ret,arch/i386/kernel/head.S: setup_idt,异常的处理,Linux通常将CPU发出的异常作为错误条件处理 页失效异常(page fault)作为内存管理的手段 当异常发生时,内核向当前进程发送信号,通知进程有异常状态出现。 通常情况下,进程因为错误状态的出现而退出运行。 异常的处理 将CPU的各种寄存器保存在进程的内核堆栈上 调用异常处理函数处理异常 调用ret_from_exception()从异常返回,. set_trap_gate(0, .,arch/i386/kernel/trap.c: trap_init,中断的处理,中断的出现与当前进程很可能完全没有关系。 中断发生时,内核不能通过向进程发送信号的方式通知进程出现中断信号。 中断通常表示某种资源变得可用。 中断的分类 I/O中断 定时器(Timer)中断 CPU间中断 内核根据中断种类分类处理,I/O中断处理,I/O中断线是系统稀有资源 中断共享 不同设备可以共享同一个中断信号 这种情况下,只使用中断向量不足以区分中断的来源 中断动态分配 中断资源只有在使用时才真正进行分配,并在使用后予以释放。 中断处理函数中不能有任何进入阻塞的调用 I/O中断的处理 使用进程的内核堆栈保存中断向量以及各种CPU寄存器 向中断控制器发送应答信号 执行中断处理函数(中断服务程序,ISR) 使用ret_from_intr()返回,I/O中断的处理,Linux中使用的中断向量分配,I/O中断向量的分配,IRQ描述符,irqaction描述符,handler 指向中断服务程序 flags SA_INTERRUPT SA_SHIRQ SA_SAMPLE_RANDOM name dev_id next,Softirq, Tasklet, Bottom Halves,内核对中断的处理方式会极大影响系统的效率。为提高系统效率,内核将一个中断的响应分成2部分: 需要立即处理的部分,称为top half或上半部,一般是不能再被中断的。 可以推后处理的部分,称为bottom half或下半部,是可以再被中断的。 下半部中断的实现机制 Softirq Tasklet Tasklet基于Softirq Bottom Halves Bottom Halves基于Tasklet,中断下半部实现机制的差异,所有的中断下半部都需要顺序执行,Softirq,Linux 2.4内核中只实现了如下4种Softirq:,可以看出,Tasklet是在Softirq基础上实现的。,Tasklet,最常用的中断下半部的实现机制 Tasklet描述符 next: 指向下一个描述符的指针 state: tasklet的状态 TASKLET_STATE_SCHED TASKLET_STATE_RUN count: 锁计数器 func: 指向tasklet函数的指针 data: 一般用于tasklet的私有数据 Tasklet由Softirq启动,Bottom Halves,早期使用的中断下半部的实现机制,被称为BH机制。 BH机制在一些传统的中断响应中仍被广泛使用。 BH在实现方法上缺乏Tasklet的灵活性,一般都使用Tasklet代替BH。,中断的返回,Linux的时钟管理,目标 时钟中断:系统心跳信号 系统时钟:各种时间戳 定时器: 时钟种类 实时钟:RTC 时间戳计数器器:TSC 可编程定时器:PIT,几个常用的变量和概念,HZ 系统时钟中断1秒钟内产生的中断次数,100 tick 系统时钟中断的时间间隔,一个嘀嗒 jiffies 系统启动后所经历的系统时钟嘀嗒数,即tick数,也就是系统时钟中断的次数。 时间片或时间量子(time slice, time quantum) 分配给进程的时间段,以tick为单位。,IRQ0:系统时钟中断,由一个可编程定时器产生系统时钟中断 以HZ为频率产生中断 为系统提供基本的时间事件的驱动 更新系统启动后经历的时间 更新系统时钟的日期和时间 判断一个进程是否已经用完所分配的时间量子,决定是否需要进行进程切换 用于各种系统资源的统计 判断定时器是否到时,IRQ0中断服务程序,首先作为IRQ被初始化:timt_init() 中断服务程序:timer_interrupt() 根据硬件时钟读取各种时间值并保存 调用do_timer_interrupt() 调用do_timer() jiffies+ update_process_times() mark_bh(TIMER_BH) 其他操作,timer_bh(): update_times(): 更新系统时间计算系统负载 run_timer_list(): 负责处理软件定时器,软件定时器,由软件实现的定时器。使用软件定时器可以实现在给定的时间间隔后执行一个函数。 内核提供软件定时器的机制。但这种定时器只能保证定时时刻到时或到时之后才起作用。 硬件定时器,如可编程定时器PIT,在定时时刻到时时就会立即发出中断。 软件定时器是在系统时钟中断的下半部被处理,不能保证实时性。 Linux提供2种定时器 动态定时器 用于内核中的定时应用 时间间隔定时器 可由用户空间的进程建立,动态定时器,当某些内核过程需要推迟运行时,可以使用动态定时器。 动态定时器可以动态建立和撤销。 动态定时器的数量可以有任意多个。 动态定时器到时后会执行指定的函数,动态定时器到时之前可以被撤销。 动态定时器以tick为最小时间单位。 动态定时器的管理由数据结构timer_list保存并形成一个链表。,/* * In Linux 2.4, static timers have been removed from the kernel. * Timers may be dynamically created and destroyed, and should be * initialized by a call to init_timer() upon creation. * * The “data“ field enables use of a common timeout function for several * timeouts. You can use this field to distinguish between the different * invocations. */ struct timer_list struct list_head list; unsigned long expires; unsigned long data; void (*function)(unsigned long); ;,include/linux/timer.h,动态定时器的管理,定时器需要在每个时钟中断时检查是否到期 定时器的定时时间可能有非常大的差异 使用简单链表或排序的链表在管理大量动态定时器时会消耗很多CPU时间 Linux使用分组和链表的方式管理动态定时器 tvecs数组:5个元素,指向5个链表组 根据剩余到期时间将定时器放到相应的链表中 tv1:即将在随后255个tick之后到期的定时器,有256个元素 tv2:即将在随后214-1个tick之后到期的定时器,有64个元素 . tv5:所有即将在232-1个tick之后到期的定时器,动态定时器管理用链表结构,例1:动态定时器应用,假设内核希望当前进程停顿2秒后再继续运行,timeout = 2*HZ; set_current_state(TASK_INTERRUPTIBLE); /* or TASK_UNINTERRUPTIBLE */ remining = schedule_timeout(timeout);,struct timer_list timer; expire = timeout + jiffies; init_timer(,schedule_timeout( ), struct task_struct *p = (struct task_struct *)data; wake_up_process(p); ,void process_timeout(unsigned long data),获得时间,相关系统调用 time() ftime() gettimeofday() 时间信息保存在timeval数据结构中 根据系统上的时钟类型,可精确到tick(10毫秒)或TSC的时间精度(微秒) 用户进程可使用上述系统调用获得时间信息 推荐使用gettimeofday()系统调用获得当前系统时间,在用户进程中使用定时器,系统为进程提供时间间隔定时器 实现机制 基于动态定时器 基于进程自身的时间信息 相关系统调用 setitimer() alarm() 时间间隔定时器通过向进程发送相应的信号使进程实现相应的定时功能,例2:使用setitimer(),SYNOPSIS #include int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);,$ man setitimer,which ITIMER_REAL:以系统实时钟为计时标准,时钟到时后发出SIGALRM信号 ITIMER_VIRTUAL:以进程运行时间为计时标准,时钟到时后发出SIGVTALRM信号 ITIMER_PROF:以进程运行时间和内核以进程身份运行时间之和为计时标准,到时后发出SIGPROF信号 struct itimerval struct timeval it_interval; /* next value */ struct timeval it_value; /* current value */ ; struct timeval long tv_sec; /* seconds */ long tv_usec; /* microseconds */ ;,#include #include #include /* A global variable used to control which string is printed */ int flag = 0; /* The signal handler which runs when the signal is received */ void sighand(int signum) if(flag) flag = 0; else flag = 1; return; int main(void) struct itimerval itimer; /* Assume the itimer expires every 2.7 sec */ itimer.it_interval.tv_usec = 700000; /* 0.7 sec */ itimer.it_interval.tv_sec = 2; /* 2 sec */,mytimer.c,/* The itimer starts after 2 sec */ itimer.it_value.tv_usec = 0; itimer.it_value.tv_sec = 2; /* Register the signal handler */ signal(SIGALRM, ,mytimer.c (续),$ gcc -o mytimer mytimer.c $ ./mytimer BBBB BBBB AAAA AAAA AAAA AAAA BBBB BBBB BBBB AAAA AAAA C,编译和运行,注意:当setitimer使用ITIMER_REAL模式调用时,它与系统调用alarm()和库函数sleep()可能使用相同的动态定时器实现机制,并且都会发出SIGALRM信号。因此不要混合使用上述几种定时函数。,系统调用,系统调用是进程向内核请求资源的唯一手段 系统调用的各种过程是内核的一部分 应用程序接口(API)与系统调用 系统调用是系统以进程身份执行的内核过程 系统调用的实现基于特定的中断指令。中断指令将进程从用户模式切换到内核模式。 i386:int 0x80,系统调用的调用过程,系统调用的实现,sys_call_table 保存系统调用入口地址的数组,共有NR_syscalls(通常为256)个数组元素。 第n个数组元素对应调用号为n的系统调用。 初始化中断门描述符表,使用0x80号中断 set_system_gate(0x80, 每个系统调用都有2个部分 派遣函数或系统调用句柄 系统调用服务程序,系统调用中的参数传递,system_call()是所有系统调用的入口函数,它根据调用号从sys_call_table中调用相应的系统调用服务程序。 系统调用使用寄存器进行参数传递 一般C函数使用堆栈进行参数传递 因为寄存器的大小和数目都是有限的,因此系统调用的参数不能超过寄存器大小并且数目不能超过6个。但可以使用其它技术传递更多参数。 最终的系统调用服务程序由C函数完成,因此调用参数仍然会被放到堆栈中。,系统调用相关源代码析读,.data ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0, old “setup()“ system call*/ .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork) .long SYMBOL_NAME(sys_read) .long SYMBOL_NAME(sys_write) .long SYMBOL_NAME(sys_open) /* 5 */ . .long SYMBOL_NAME(sys_ni_syscall) /* 255 sys_epoll_ctl */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_wait */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */ .long SYMBOL_NAME(sys_set_tid_address),arch/i386/kernel/entry.S: sys_call_table,/* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to * go as quickly as possible which is why some of this is * less clear than it otherwise should be. */ ENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys cmpl $(NR_syscalls),%eax jae badsys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) cli # need_resched and signals atomic test cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return restore_all: RESTORE_ALL,arch/i386/kernel/entry.S: system_call,asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count) ssize_t ret; struct file * file; ret = -EBADF; file = fget(fd); if (file) if (file-f_mode ,系统调用服务程序,以sys_write为例 fs/read_write.c: sys_write,在内核中使用系统调用,系统调用的接口是在库函数中实现的 内核不能使用库函数 内核使用一系列wrapper例程在内核中实现系统调用接口 使用7个宏简化接口定义 _syscall0, _syscall1, _syscall2, . _syscall6 每个宏在编译时展开成相应的汇编函数 例: _syscall3(int,write,int,fd,const char*,buf,unsigned int, count),参考资料,深入理解Linux内核 第二版 第四章,第六章,第九章,

    注意事项

    本文(中断定时和系统调用.ppt)为本站会员(本田雅阁)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开