Linux系统调用

CPU存在内核模式和用户模式两种模式,只有处于内核模式时才允许访问设备,通过不同模式隔绝进程调动设备的权限。

Linux系统调用是操作系统提供给用户程序或者其他程序与操作系统内核进行交互的接口。这些调用允许程序请求操作系统执行特定的操作,如文件操作、进程管理、网络通信等。

计算机系统中各种进程与OS的关系如下图
在这里插入图片描述
一般来说,由在用户模式在运行的进程通过系统调用向内核发送相应的请求。其中包括了进程独有的代码直接向内核发起请求的情况,也包括了进程所依赖的库向内核发起请求的情况。

进程在执行创建进程、操作硬件等依赖于内核的处理时,必须通过系统调用向内核发起请求,系统调用的种类如下:

  • 进程控制(创建和删除)
  • 内存管理(分配和释放)
  • 进程间通信
  • 网络管理
  • 文件系统操作
  • 文件操作(访问设备)

CPU的模式切换

系统调用需要通过执行特殊的CPU命令来发起。通常进程运行在用户模式下,当通过系统调用向内核发送请求时,CPU会发生名为“中断”的事件。这时,CPU将用户从用户模式下切换到内核模式,然后根据请求内容进行相应的处理。当内核处理完成系统调用后,将重新回到用户模式,继续运行进程。
在这里插入图片描述

发起系统调用的情形

若要了解进程在发生了哪些系统调用,可以strace命令可以对进程进行追踪。
例如对一个C语言hello world程序进行追踪:
先编写代码hello.c

#inclue<stdio.h>
int main(void) 
{
	puts("hello world");
	return 0;
}

输入以下命令

cc -o hello hello.c 

strace -c ./hello

其中第一行命令是编译,第二行是跟踪执行 hello 可执行文件时的系统调用次数

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.08    0.000106          13         8           mmap
 16.40    0.000051          12         4           mprotect
 11.25    0.000035          11         3         3 access
  8.68    0.000027          13         2           open
  6.75    0.000021           7         3           fstat
  5.47    0.000017          17         1           write
  5.47    0.000017          17         1           munmap
  3.22    0.000010           5         2           close
  2.57    0.000008           8         1           read
  2.57    0.000008           8         1           execve
  1.93    0.000006           6         1           arch_prctl
  1.61    0.000005           5         1           brk
------ ----------- ----------- --------- --------- ----------------
100.00    0.000311                    28         3 total

% time:每种系统调用所占用的时间百分比。
seconds:总时间(秒)。
usecs/call:平均每次调用耗时(微秒)。
calls:调用次数。

执行系统调用的一些实验

sar命令由于获取进程分别在用户模式与内核模式下运行时间的比例。

sar -P ALL 1
10:33:22 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
10:33:23 AM     all      0.25      0.00      0.25      0.00      0.00     99.50
10:33:23 AM       0      0.00      0.00      0.00      0.00      0.00    100.00
10:33:23 AM       1      1.00      0.00      0.00      0.00      0.00     99.00
10:33:23 AM       2      0.00      0.00      0.00      0.00      0.00    100.00
10:33:23 AM       3      0.00      0.00      0.00      0.00      0.00    100.00

10:33:23 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
10:33:24 AM     all      0.25      0.00      0.25      0.00      0.00     99.50
10:33:24 AM       0      0.99      0.00      0.00      0.00      0.00     99.01
10:33:24 AM       1      0.00      0.00      0.00      0.00      0.00    100.00
10:33:24 AM       2      1.00      0.00      1.00      0.00      0.00     98.00
10:33:24 AM       3      0.00      0.00      0.00      0.00      0.00    100.00

在每一行中,从%user%idle表示在CPU核心上运行的处理的类型。其中%user表示用户态进程(非内核态)消耗 CPU 时间的百分比,而"%system"表示在内核模式下消耗CPU时间的百分比。“%idle”表示CPU空闲时间的百分比。目前CPU几乎是空闲的。

现在我们运行一个循环程序loop.c

int main(void)
{
	for(;;);
}

编译并运行程序

cc -o loop loop.c
./loopc &

sar -P ALL 1 1

运行结果如下:

10:42:42 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
10:42:43 AM     all     25.13      0.00      0.25      0.00      0.00     74.62
10:42:43 AM       0      0.00      0.00      1.00      0.00      0.00     99.00
10:42:43 AM       1      0.00      0.00      1.00      0.00      0.00     99.00
10:42:43 AM       2      0.00      0.00      0.00      0.00      0.00    100.00
10:42:43 AM       3    100.00      0.00      0.00      0.00      0.00      0.00

Average:        CPU     %user     %nice   %system   %iowait    %steal     %idle
Average:        all     25.13      0.00      0.25      0.00      0.00     74.62
Average:          0      0.00      0.00      1.00      0.00      0.00     99.00
Average:          1      0.00      0.00      1.00      0.00      0.00     99.00
Average:          2      0.00      0.00      0.00      0.00      0.00    100.00
Average:          3    100.00      0.00      0.00      0.00      0.00      0.00

我们可以发现运行loop程序的进程始终处于用户模式

我们关闭之前的程序,修改循环,执行getppid()这个由于获取父进程的进程id的系统调用的程序进行相同的操作。
代码ppidloop.c:

#include <sys/types.h>
#include <unistd.h>
int main(void)
{
for(;;)
getppid();
}

执行命令

cc -o ppid ppidloop.c
./ppidloop &

sar -P ALL 1 1

执行结果如下:

10:49:59 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
10:50:00 AM     all      6.00      0.00     19.50      0.75      0.00     73.75
10:50:00 AM       0      0.00      0.00      0.00      2.02      0.00     97.98
10:50:00 AM       1      0.00      0.00      1.00      0.00      0.00     99.00
10:50:00 AM       2     28.00      0.00     72.00      0.00      0.00      0.00
10:50:00 AM       3      0.00      0.00      1.01      0.00      0.00     98.99

Average:        CPU     %user     %nice   %system   %iowait    %steal     %idle
Average:        all      6.00      0.00     19.50      0.75      0.00     73.75
Average:          0      0.00      0.00      0.00      2.02      0.00     97.98
Average:          1      0.00      0.00      1.00      0.00      0.00     99.00
Average:          2     28.00      0.00     72.00      0.00      0.00      0.00
Average:          3      0.00      0.00      1.01      0.00      0.00     98.99

我们可以发现CPU核心3运行ppidloop程序占用了28%的运行时间,ppidloop程序发起请求来获取父进程id这一内核处理占用了72%的运行时间。
在这里插入图片描述

相关推荐

  1. linux系统调用介绍

    2024-07-16 01:10:02       59 阅读
  2. Linux 系统调用

    2024-07-16 01:10:02       30 阅读
  3. Linux系统调用mmap

    2024-07-16 01:10:02       31 阅读
  4. linux系统调用

    2024-07-16 01:10:02       22 阅读
  5. OpenHarmony—Linux系统调用

    2024-07-16 01:10:02       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-16 01:10:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-16 01:10:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-16 01:10:02       58 阅读
  4. Python语言-面向对象

    2024-07-16 01:10:02       69 阅读

热门阅读

  1. Websocket发一条阻塞了,后面的消息会怎么样

    2024-07-16 01:10:02       21 阅读
  2. 网络编程part2

    2024-07-16 01:10:02       21 阅读
  3. typora图片问题以及快捷键问题汇总

    2024-07-16 01:10:02       21 阅读
  4. [Selenium]C#语言中的等待策略的应用与实现

    2024-07-16 01:10:02       18 阅读
  5. 刷题——有效括号序列

    2024-07-16 01:10:02       24 阅读
  6. Ningx配置前端http缓存

    2024-07-16 01:10:02       23 阅读