第五章 系统调用

  • 内核提供了用户进程与内核进行交互的一组接口。
  • 应用程序发出请求->内核负责满足
  • 目的:保证系统稳定可靠

5.1 与内核通信

系统调用在用户空间进程和硬件设备之间添加了一个中间层,其作用:

  • 为用户空间提供一种硬件的抽象接口
  • 保证系统稳定和安全
  • 为了实现多任务和虚拟内存

系统调用是用户空间访问内核的唯一手段

5.2 API、POSIX和C库

应用程序通过应用编程接口API而不是系统调用来编程,且API并不和系统调用一一对应。

API、POSIX、C库和系统调用之间的关系:

  • POSIX是标准,API基于POSIX,POSIX定义的API函数和系统调用有直接关系。
  • 系统调用作为C库的一部分提供。C库实现看POSIX的主要API。
  • 程序员只和API打交道,内核只和系统调用打交道。

提供机制而不是策略:系统调用抽象出用于完成某种确定目的的函数,而内核不关心函数怎么用。

5.3 系统调用

系统调用(syscall)通常通过C库中的函数调用来进行。

系统调用有一个long类型返回值:通常负值表明错误,0表明成功。

出现错误时C库把错误码写入errno全局变量,通过perror()库函数翻译成错误字符串。

举例:getpid()

注意:没有规定过程是什么方式,只要结果正确就行。

SYSCALL_DEFINEO(getpid) //SYSCALL_DEFINEO是一个宏,定义一个无参数的系统调用,如下

asmlinkage long sys_getpid(void)
#asmlinkage限定词是编译指令,通知编译器仅从栈中提取该函数的参数,所有系统调用都要用到这个限定词。
#函数返回long。用户空间为int,内核空间为long。
#命名规则:getpid->sys_getpid

系统调用号

系统调用被赋予一个独一无二的系统调用号,进程通过系统调用号指明执行哪一个系统调用。

系统调用号很重要:一旦分配不能有任何更改。系统调用被删除,系统调用号不允许被回收利用。

sys_ni_syscall():未实现的系统调用,只返回-ENOSYS,专门针对无效的系统调用,负责“填补空缺”。

sys_call_table:记录已注册的系统调用,为每一个有效的系统调用指定唯一的系统调用号。

系统调用的性能

Linux系统调用执行快:

  • 上下文切换时间短,进出内核简洁高效。
  • 系统调用处理程序和系统调用本身都非常简洁。

5.4 系统调用处理程序

用户空间的程序不能直接执行内核代码,需要通知系统切换到内核态,由内核执行系统调用。

机制:软中断:引发一个异常使系统切换到内核态执行异常处理程序,而这个异常处理程序就是系统调用处理程序(system_call),中断号为128,通过int $0x80触发该中断。

指定恰当的系统调用

把系统调用号传给内核:通过eax寄存器

检查系统调用号有效性:与NR_syscalls做比较:

大于或等于,函数就返回-ENOSYS

否则就执行相应的系统调用:call *sys_call_table(,%rax,8) //表项为8字节存储

参数传递

外部参数输入:可存放在寄存器里,ebx,ecx,edx,esi,edi按顺序存放前五个参数,需要6个参数时:用寄存器存放指向这些参数的指针。

返回值:存放在eax中。

5.5系统调用的实现

给内核添加一个新的系统调用是相对容易的,但是设计和实现一个系统调用是难题。

实现系统调用

  • 第一步决定用途,要明确。
  • 新系统调用的参数、返回值、错误码、接口力求简洁,语义和行为稳定不做改动。
  • 为将来多做考虑,注意可移植性和健壮性。

参数验证

系统调用必须检查参数是否合法有效,进程不能让内核去访问它本身无权访问的资源。

重要检查:指针是否有效:

  • 指针指向的内存区域属于用户空间,且在进程地址空间里。
  • 标记为可读/写/执行,才能进行读/写/执行。

内核空间和数据空间之间的数据拷贝:

写入数据:copy_to_user()
读取数据:copy_from_user()
//都有三个参数,进程空间中的目的内存地址+内核空间内的源地址+数据长度(字节数)
//执行失败:返回没有拷贝的数据字节数 成功:返回0 错误:返回标准-EFAULT

是否有合法权限:

使用capable()函数来检查是否有权对指定资源进行操作:返回非0:有权,返回0:无权。

5.6 系统调用上下文

内核在执行系统调用时处于进程上下文。current指针指向引发系统调用的进程。

在进程上下文中:

  • 内核可以休眠
  • 内核可以被抢占:保证系统调用是可重入的

系统调用返回时:system_call负责切换到用户空间。

绑定一个系统调用的最后步骤

编写完一个系统调用后,注册步骤:

  • 在系统调用表的最后加入一个表项。从0算起,在该表位置为其系统调用号。
  • 对于所支持的所有体系结构,系统调用号都必须定义在<asm/unistd.h>中。每种体系结构不需要对应相同的系统调用号。系统调用号专属于体系结构ABI。
  • 系统调用必须被编译进内核映象(不能被编译成模块)。可放在kernel/sys.c中(包含各种系统调用)

从用户空间访问系统调用

一般系统调用靠C库支持,Linux提供了一组宏可直接对系统调用进行访问,会将系统调用号和参数压入寄存器并触发软中断来陷入内核。

这些宏是_syscalln():n为0到6,代表参数个数。举例open():

定义:long open (const char *filename,int flags,int mode)

宏:
#define NR_open 5 //系统调用号
_syscall3(long,open,const char *,filename,int,flags,int,mode)
//第一个参数是返回值类型,第二个是系统调用名称,后面是按照参数顺序排列的每个参数的类型和名称

为什么不通过系统调用的方式实现

虽然新建一个系统调用很容易且使用方便,性能高,但是不提倡。

替代方法:实现一个设备节点,并对此实现read()和write()。使用ioctl()对特定的设置进行操作或对特定的信息进行检索。

  • 信号量这样的接口可用文件描述符表示。
  • 把增加的信息作为一个文件放在sysfs的合适位置。

20135220谈愈敏Linux Book_5的更多相关文章

  1. 20135220谈愈敏Linux Book_17

    第17章 设备与模块 关于设备驱动和设备管理的四种内核成分: 设备类型:在所有 Unix 系统中为了统一普通设备的操作所采用的分类. 模块: Linux 内核中用于按需加载和卸载目标码的机制. 内核对 ...

  2. 20135220谈愈敏Linux Book_4

    进程调度 进程:程序的运行态表现形式 进程调度程序:确保进程能有效工作的一个内核子系统,决定将哪个进程投入运行.何时运行以及运行多长时间,在可运行态进程之间分配有限的处理器时间资源. 最大限度的利用处 ...

  3. 20135220谈愈敏Linux Book_3

    第3章 进程管理 进程是Unix操作系统抽象概念中最基本的一种,进程管理是操作系统的心脏所在. 3.1 进程 进程:处于执行期的程序以及相关的资源的总称. 线程:在进程中活动的对象,拥有独立的程序计数 ...

  4. 20135220谈愈敏Linux Book_18

    第18章 调试 调试内核艰难且风险高,关键在于对内核的深刻理解. 18.1 准备开始 需要的是: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 内核中的bug不是很清晰,调试成功的关 ...

  5. 20135220谈愈敏Linux Book_1&2

    第一章 Linux内核简介 从unix的历史视角来认识Linux内核与Linux操作系统的前世今生. Unix历史 贝尔实验室设计的一个文件系统原型逐渐演化而成Unix,而后Unix操作系统用C语言重 ...

  6. 20135220谈愈敏Blog3_构造一个简单的Linux系统MenuOS

    构造一个简单的Linux系统MenuOS 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1 ...

  7. 20135220谈愈敏Blog8_进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-100002 ...

  8. 20135220谈愈敏Blog7_可执行程序的装载

    可执行程序的装载 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. ...

  9. 20135220谈愈敏Blog6_进程的描述和创建

    进程的描述和创建 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 进程 ...

随机推荐

  1. Gitkraken的使用

    一个优秀的团队合作离不开git,一个优秀的程序员也离不开git.gitkraken是我在进行软工实践这门课接触到的git的UI界面的工具,它给我留下的印象就是非常好用和方便 怎么个方便法呢? 方便的安 ...

  2. Redis系列一:reids的单机版安装

    环境:VM+centos6+xshell 1.准备好linux的虚拟机,这里用的是centos6,具体方法百度 2.进入software目录,创建一个redis的目录来存放下载的redis包 cd s ...

  3. [POI2007]MEG-Megalopolis

    传送门:嘟嘟嘟 第一反应是树链剖分,但是太长懒得写,然后就想出了一个很不错的做法. 想一下,如果我们改一条边,那么影响的只有他的子树,只要先搞一个dfs序,为什么搞出这个呢?因为有一个性质:一个节点的 ...

  4. 飞冰ICE

    一. 飞冰目标与愿景(同时也概况飞冰是什么) 飞冰是一套基于 React 的中后台应用解决方案,在阿里巴巴内部,已经有 270 多个来自几乎所有 BU 的项目在使用.经过 2 年的发展,飞冰已经是中后 ...

  5. 分享一个excel根据文件超链接获取链接文档的最后更新时间

    #获取制定单元格内超链接对应的链接地址Sub geturi() For Each cell In Range("E3:E43") If cell.Hyperlinks.Count ...

  6. 回调函数ros::spin()与ros::spinOnce()

    ros::spin() 这句话的意思是循环且监听反馈函数(callback).循环就是指程序运行到这里,就会一直在这里循环了.监听反馈函数的意思是,如果这个节点有callback函数,那写一句ros: ...

  7. JS动态生成表格后 合并单元格

    JS动态生成表格后 合并单元格 最近做项目碰到表格中的单元格合并的问题,需求是这样的,首先发ajax请求 请求回来后的数据 动态生成表格数据,但是生成后如果编号或者(根据其他的内容)有相同时,要合并单 ...

  8. JAVA框架 Mybaits 一对一、一对多

    一:阐述 我们在日常操作的时候,很多时候会遇到多表联合查询,由于参照物的不通 ,会出现一对一.一对多的情况.比如说:账号信息和订单表,从订单表角度和账号信息是一对一的情况(一个订单只能是一个用户的情况 ...

  9. excel中散点图和折线图的区别(散点图时间均匀分布)

    折线图可以显示随单位(如:单位时间)而变化的连续数据,因此非常适用于显示在相等时间间隔下数据的趋势.散点图显示若干数据系列中各数值之间的关系,或者将两组数绘制为 xy 坐标的一个系列.-------- ...

  10. Delphi DBGrid类控件定位到某一行,并更改为选中状态。

    Delphi中,可以使用数据集控件提供的 Locate 成员方法快速定位至某条记录, 然后通过清除数据集控件的选中状态,并重新赋值达到我们的目的. grDirectory.DataSource.Dat ...