📜  os 中的系统调用 (1)

📅  最后修改于: 2023-12-03 15:33:20.905000             🧑  作者: Mango

系统调用

在操作系统(OS)中,系统调用(System Call)是指应用程序通过操作系统提供的接口请求操作系统内核执行某些特权操作的过程。系统调用是用户态程序访问核心态的途径。

系统调用提供了许多供用户程序调用的函数,如文件读写、网络通信、进程管理等,并且这些函数需要特别权限。如果程序想进行这些操作,就需要调用操作系统提供的系统调用,以此获得这些特别权限。

系统调用的分类
  1. 进程控制:进程创建、撤销、等待、退出等
  2. 文件操作:打开、关闭、读取、写入等
  3. 设备操作:读写设备、控制设备等
  4. 通信:管道、信号量、消息队列、共享内存等
  5. 网络通信:Socket等
系统调用的实现

系统调用需要切换用户态和核心态的运行权限,以便能够执行某些操作,例如访问 I/O 设备、管理内存等。当用户程序调用系统调用时,操作系统会通过中断机制将用户程序从用户态切换到核心态,并由操作系统内核来执行系统调用代码。

System call implementation

系统调用的调用方式

在不同的操作系统中,系统调用的调用方式也可能不同。常见的系统调用调用方式有:

1. 普通函数调用

在 Linux 中,系统调用可以通过 C 标准库函数库(如 glibc)来调用。在应用程序中,我们通过 include 头文件调用相应的函数,如调用 close 函数关闭文件描述符,就是通过调用库函数 close(...) 来实现的。

#include <unistd.h>
...
int close(int fd);
...
2. 软中断

在 Linux 中,使用 0x80 软中断指令(int 0x80)触发系统调用。当用户程序希望执行系统调用时,可以通过这个中断来触发。这个中断会将 CPU 从用户态切换到核心态,并且将寄存器中的参数传递给内核执行。

mov eax, 1       ; syscall number
mov ebx, 0       ; fd to close
int 0x80         ; trigger system call
3. 系统 V IPC

System V IPC 是一种方法,可以在不同进程和不同主机之间进行通信。系统 V IPC 中提供了多种机制,包括信号量、共享内存和消息队列等。在调用这些系统调用时,需要使用 IPC 相关的函数。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun {
    int val;               /* Value for SETVAL */
    struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
    unsigned short *array; /* Array for GETALL, SETALL */
};

int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semctl(int semid, int semnum, int cmd, union semun arg);
系统调用的返回值

系统调用的返回值通常是一个整数,表示系统调用是否成功,以及错误码。在 Linux 中,返回值一般是-1表示错误,errno 保存了错误码。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    char *filename = "non_existent_file";
    FILE *fp = fopen(filename, "r");
    if(fp == NULL) {
        printf("Error: %d\n", errno);
        exit(EXIT_FAILURE);
    } else {
        printf("File opened successfully\n");
    }
    return 0;
}
结论

系统调用是操作系统提供的功能,允许应用程序从用户态访问核心态,以执行某些需要特权的操作。在不同的操作系统中,系统调用的调用方式可能不同。程序员必须了解系统调用的机制和调用方式,并正确处理错误码,以保证程序的正确性和健壮性。