《Unix系统编程手册》第三章系统编程概念学习

系统调用

系统调用是内核提供的受控的内核入口,通过API的形式,内核提供了一系列服务供程序调用。

系统调用基本特点:
1、系统调用会从用户态切换到核心态,以便CPU访问受到保护的内核内存;
2、系统调用的组成是固定的,每个系统调用都由唯一的数字来标识(程序通过名称标识系统调用);
3、每个系统调用可以使用一套参数,对用户空间和内核空间传递的信息进行规范。

系统调用执行的基本步骤:
1、应用程序通过调用包装后的库函数发起系统调用请求;
2、API函数需要保证传入的参数可用,然后将参数传入到寄存器中;
3、由于系统调用进入内核的方式相同,所以内核需要区分每个系统调用,对此,内核会将系统调用的编号复制到特殊的CPU寄存器中;
4、API函数执行一条中断指令,将用户态切换到核心态,并执行中断所指向的代码;
5、为了响应中断请求,内核会调用system_call()例程来处理中断
6、若系统调用执行结果表明执行出错,API函数会设置errno。

处理中断过程:
1、在内核栈中保存寄存器值;
2、审核系统调用编号的有效性;
3、以系统调用编号对存放的所有调用服务历程的列表进行索引,并调用相应的系统调用服务例程,若有参数,将先检验参数的有效性

处理来自系统调用和库函数的错误

几乎每个系统调用和库函数都会返回某类状态值,用于表明调用成功与否。少数系统函数在调用时不会失败,例如getpid()总能成功返回进程ID,而_exit()总能终止进行,无需对此系统调用的返回值进行检测。

每个系统调用的手册页记录有调用可能的返回值,并指明了哪些值表示错误。系统调用失败时,会将全局整型变量errno设置为一个正值,以标识具体的错误。程序应包含#include<errno.h>头文件。

如果调用系统和库函数成功,errno绝不会被重置为0,如果errno不为0,可能是之前调用失败造成的。因此在错误检查时,必须坚持首先检查函数的返回值是否表明调用出错,然后再检查errno确定错误原因 。此外,少数系统调用在调用成功后,也会返回-1。因此要判断此类系统调用是否发生错误,应在调用前将errno置为0,并在调用后对其检查

解析数值型命令行参数的函数

c 复制代码
#include "tlpi_hdr.h"

int getInt(const char *arg, int flags, const char* name);
long getLong(const char *arg, int flags, const char* name);

与atoi()、atol()和strtol()相比,它们针对数值型参数提供了一些基本的有效性检查。它们会将arg指向的字符串转换成int或long,如果不是一个有效的字符串,那么它们会打印一条错误并终止程序。如果name非空,则将该字符串用于标识arg对应于命令行中相应参数的名称,即如果出现错误,该字符串会出现在打印的错误信息中。函数实现如下:

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include<errno.h>

static void gnFail(const char* fname, const char* msg, const char* arg, const char* name)
{
	fprintf(stderr, "%s error", fname);
	if(name)fprintf(stderr, " (in %s)", name);
	fprintf(stderr, ": %s\n", msg);
	if(arg && *arg != '\0')
		fprintf(stderr, "   offending text: %s\n", arg);
	
	exit(EXIT_FAILURE);
}

static long getNum(const char* fname, const char* arg, int flags, const char* name)
{
	if(!arg ||*arg == '\0')
		gnFail(fname, "null or empty string", arg, name);
	int base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8 : (flags & GN_BASE_16) ? 16 : 10;
	errno = 0;
	char* endptr;
	long res = strtol(arg, &endptr, base);
	
	if(errno != 0)
		gnFail(fname, "strtol() failed", arg, name);
	
	if(*endptr != '\0')
		gnFail(fname, "nonnumeris characters", arg, name);
	
	if((flags & GN_NONNEG) && res < 0)
		gnFail(fname, "negative value not allowed", arg, name);
	
	if((flags & GN_GT_0) && res <= 0)
		gnFail(fname, "value must be > 0", arg, name);
	
	return res;
}

long getLong(const char* arg, int flags, const char* name)
{
	return getNum("getLong", arg, flags, name);
}

int getInt(const char* arg, int flags, const char* name)
{
	long res = getNum("getIng", arg, flags, name);
	if(res >INT_MAX || res < INT_MIN)
		gnFail("getInt", "integer out of rangs", arg, name);
	
	return (int)res;

总结

系统调用允许进程向内核请求服务,与用户空间的函数调用相比,哪怕最简单的系统调用都会产生显著的开销,其原因是在执行系统调用时,系统需要切换到核心态。此外内核还需要验证系统调用的参数、用户内存以及内存之间也有数据需要传递

练习

3-1 使用Linux专有的reboot()系统调用重启系统时,必须将第二个参数magic2定义为一组magic号。这些magic号有什么意义?

答:没太懂就去查了一下,参考链接见参考第二条。

cpp 复制代码
include/linux/reboot.h:#define LINUX_REBOOT_MAGIC1  0xfee1dead 
include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2  672274793 
include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2A 85072278 
include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2B 369367448 
include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2C 537993216 
Here are the answers. 
0xfee1dead ="Feel Dead"

672274793=0x28121969 28/12/1969 is when Linus Torvalds was born. 

These are Linus' daughters' birthdays: 
85072278= 0x5121996     05/12/1996 is when Patricia Miranda was born. 
367369448=0x16041998 16/04/1998 is when Daniela Yolanda was born. 
537993216=0x20122000 20/12/2000 is when Celeste Amanda was born

参考

1、《Unix系统编程手册》上篇

2、https://blog.csdn.net/JohnnyHu90/article/details/50877322

相关推荐
匀泪28 分钟前
云原生(LVS DR模式ipvs实验)
服务器·网络·lvs
RisunJan36 分钟前
Linux命令-lprm(删除打印队列中任务)
linux·运维·服务器
云姜.38 分钟前
TCP协议特性
服务器·网络·tcp/ip
zzzsde38 分钟前
【Linux】进程(5):命令行参数和环境变量
linux·运维·服务器
The森42 分钟前
Linux IO 模型纵深解析 03:同步 IO 与异步 IO
linux·服务器
草莓熊Lotso2 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
七夜zippoe10 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥10 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
Fcy64811 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满11 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器