linux-schedule()学习——002

  一 系统调用和库函数究竟是什么关系(网上的答案汇总)

1.系统调用是为了方便应用使用操作系统的接口,而库函数是为了方便人们编写应用程序而引出的,比如你自己编写一个函数其实也可以说就是一个库函数。

2.系统调用可以理解为内核提供给我们在用户态用的接口函数,可以认为是某种内核的库函数。

3.read就是系统调用,而fread就是C标准库函数.

4.很多c函数库中的函数名与系统调用的名称一样是因为该函数本身其实就是调用的系统调用,放到c函数库就是为了用户态的使用

5.写程序直接使用的是库函数,而库函数内部可能就是调用的同名系统调用

6.首先,现在的OS内核主要采用两种模式,整体的单内核模式(linux)和分层的微内核模式(Windows)。单内核模式的特点就是代码紧凑,执行速度快,各个模块之间是直接的调用关系,可以说最后一点既是优点,也是缺点...有点就是执行速度快,缺点是内核看起来很乱,维护起来困难。

无论是单内核,还是微内核,立体的体系结构从下到上大概都是分成这样几层:物理硬件,OS内核,OS服务,应用程序。这四层结构中,OS内核起到一个“承上启下”的作用,向下管理物理硬件;向上为OS服务和应用程序提供接口。主意,这里的接口实际上是指系统调用(System Call)。

通常OS内核为了考虑实现起来的难度和易于管理,只提供少部分必要的系统调用,这些系统调用通常都是C和汇编混编来实现的。接口用C定义,实现体用汇编来写。这样做的好处是,执行效率高,并且极大的方便了上层的调用。
再说库函数(即API)。库函数可以概括的分为两类,一类是随OS提供的,另一类是第三方的。随系统提供的库函数进一步封装或组合系统调用,实现更多的功能,就像用C语言的许多功能单一的小函数来实现很多很多个功能复杂的大函数一样。这样的API能够执行一些相对内核来说很复杂的操作,比如,read()函数根据参数,直接就能读文件,而背后隐藏的比如文件在硬盘的哪个磁道,哪个扇区,加载到内存的哪个位置等等这些操作,程序员是不必关心的,这些操作里面自然也包含了系统调用。而对于第三方的库,它其实和系统库一样,只是它直接利用系统调用的可能性要小一些,而是利用系统提供的API接口来实现功能。(API的接口是开放的)。

7.高级语言库函数的确是调用系统调用来实现的,所以说系统调用才是真正对硬件操作的。但是大家可能注意到了为什么库函数是通用的(同名),这是正是高级语言不依赖与特定的硬件。其实,都是编译器来负责库函数到系统调用之间的转换的。比如说VC可能通过把fopen()对应到windows的打印系统调用XXX(不知道具体是哪个)上去了,而linux的编译器gcc通过把fopen()对应到linux的系统调用open上去了。

8.系统调用没有库函数的效率高是因为与设置的缓冲池大小有关吧,缓冲池(不知是用户的还是内核的)小的话,系统调用的操作就频繁,缓冲池(不知是用户的还是内核)大的的话,库函数就调用系统调用的次数就少。

9.应用程序可以直接调用库函数来操作。那么linux的源代码C里是不应该使用库函数的吧,你想。编译连接成内核镜像后,安装在裸机上,连个运行环境都没怎么系统调用啊。有的人会说,系统调用在编译连接的时候已经把系统调用弄进去了,那么不是说现在流行的动态连接吗,直到运行需要时才去连接吗。

简单总结可以说:

1.系统调用是内核提供给用户的API,库函数是库提供给用户的API.从使用角度上看,作用是一致的:方便程序编写,隐藏实现.

2.系统调用是内核级别的,库函数是用户层级别的

3.系统调用是某些库函数的实现,但库函数也有未使用系统调用就能够实现的

4.系统调用的效率高于库函数

5.系统调用的移植性高于库函数

  二 linux 系统调用----Schedule()函数

  Schedule()函数Linux的调度程序,由它来决定是否要进行进程的切换,其任务是在run-queue队列中选出一个就绪进程 

  Schedule()函数的调度时机指的是在什么情况下执行调度程序。主要有一下几种状况:

  1、进程状态转换的时刻:进程终止、进程睡眠;

  2、当前进程的时间片用完时(current->counter=0);

  3、设备驱动程序

  4、进程从中断、异常及系统调用返回到用户态时;

  时机1,进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程序进行进程调度。

  时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4是一样的。

  时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查need_resched的值,如果必要,则调用调度程序schedule()主动放弃CPU。

  时机4,如前所述,不管是从中断、异常还是系统调用返回,最终都调用ret_from_sys_call(),由这个函数进行调度标志的检测,如果必要,则调用调用调度程序。那么,为什么从系统调用返回时要调用调度程序呢?这当然是从效率考虑。从系统调用返回意味着要离开内核态而返回到用户态,而状态的转换要花费一定的时间,因此,在返回到用户态前,系统把在内核态该处理的事全部做完。

三  每个时钟中断发生时内核要做的工作

每个时钟中断(timer interrupt)发生时,由三个函数协同工作,共同完成进程的选择和切换,它们是:schedule()、do_timer()及ret_form_sys_call()。

    注释:schedule():进程调度函数,由它来完成进程的选择(调度);

  do_timer():暂且称之为时钟函数,该函数在时钟中断服务程序中被调用,是时钟中断服务程序的主要组成部分,该函数被调用的频率就是时钟中断的频率即每秒钟100次(简称100赫兹或100Hz);

  ret_from_sys_call():系统调用返回函数。当一个系统调用或中断完成时,该函数被调用,用于处理一些收尾工作,例如信号处理、核心任务等等。

    这三个函数是如何协调工作:时钟中断是一个中断服务程序,它的主要组成部分就是时钟函数do_timer(),由这个函数完成系统时间的更新、进程时间片的更新等工作,更新后的进程时间片counter作为调度的主要依据。

    在时钟中断返回时,要调用函数ret_from_sys_call(),

  在这个函数中有如下几行:

  cmpl $0, _need_resched//检测 need_resched 标志

  jne reschedule//如果此标志为非0,那么就转到reschedule处调用调度程序schedule()进行进程的选择

  ……

  restore_all:

  RESTORE_ALL

  reschedule:

  call SYMBOL_NAME(schedule)

  jmp ret_from_sys_call

 代码分析:检测 need_resched 标志,如果此标志为非0,那么就转到reschedule处调用调度程序schedule()进行进程的选择。调度程序schedule()会根据具体的标准在运行队列中选择下一个应该运行的进程。当从调度程序返回时,如果发现又有调度标志被设置,则又调用调度程序,直到调度标志为0,这时,从调度程序返回时由RESTORE_ALL恢复被选定进程的环境,返回到被选定进程的用户空间,使之得到运行。

另注:系统调用返回函数ret_from_sys_call()是从系统调用、异常及中断返回函数通常要调用的函数,但并不是非得调用,对于那些要经常被响应的和要被尽快处理的中断请求信号,为了减少系统开销,处理完成后并不调用 ret_from_sys_call()(因为很显然的,从这些中断处理程序返回到的用户空间肯定是那个被中断的进程,无需重新选择),并且,它们作的工作要尽可能少,因为响应的频率太高了。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值