第十一章:系统调用

第十一章:系统调用

11.1 系统调用的基本概念

系统调用的作用

系统调用的主要功能:

  1. 进程控制
  2. 文件操作
  3. 设备管理
  4. 内存管理
  5. 网络通信

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
// 进程控制
pid_t pid = getpid();
printf("Process ID: %d\n", pid);

// 文件操作
int fd = open("test.txt", O_CREAT | O_WRONLY, 0644);
if (fd != -1) {
write(fd, "Hello, World!\n", 13);
close(fd);
}

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc syscall_basic.c -o syscall_basic

# 运行
./syscall_basic

系统调用的实现

系统调用的实现方式:

  1. 软中断
  2. 系统调用表
  3. 参数传递
  4. 返回值处理

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

int main() {
// 直接使用系统调用号
long ret = syscall(SYS_getpid);
printf("Process ID (syscall): %ld\n", ret);

// 使用系统调用宏
ret = syscall(SYS_write, STDOUT_FILENO, "Hello\n", 6);
printf("Write bytes: %ld\n", ret);

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc syscall_impl.c -o syscall_impl

# 运行
./syscall_impl

11.2 系统调用的使用

进程控制

进程控制相关的系统调用:

  1. fork
  2. exec
  3. wait
  4. exit

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
// 创建子进程
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return 1;
}

if (pid == 0) {
// 子进程
printf("Child process (PID: %d)\n", getpid());
sleep(1);
return 42;
} else {
// 父进程
printf("Parent process (PID: %d)\n", getpid());

// 等待子进程
int status;
waitpid(pid, &status, 0);

if (WIFEXITED(status)) {
printf("Child exited with status: %d\n",
WEXITSTATUS(status));
}
}

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc process_control.c -o process_control

# 运行
./process_control

文件操作

文件操作相关的系统调用:

  1. open
  2. read
  3. write
  4. close

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main() {
// 打开文件
int fd = open("test.txt", O_CREAT | O_RDWR, 0644);
if (fd == -1) {
perror("open");
return 1;
}

// 写入数据
const char *msg = "Hello, World!\n";
ssize_t n = write(fd, msg, strlen(msg));
if (n == -1) {
perror("write");
close(fd);
return 1;
}

// 定位到文件开始
lseek(fd, 0, SEEK_SET);

// 读取数据
char buf[1024];
n = read(fd, buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
printf("Read: %s", buf);
}

// 关闭文件
close(fd);
return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc file_ops.c -o file_ops

# 运行
./file_ops

11.3 系统调用的优化

性能优化

系统调用性能优化的方法:

  1. 减少系统调用次数
  2. 使用缓冲
  3. 批量操作
  4. 异步I/O

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#define BUFFER_SIZE 4096

int main() {
// 打开文件
int fd = open("large.txt", O_CREAT | O_WRONLY, 0644);
if (fd == -1) {
perror("open");
return 1;
}

// 使用缓冲写入
char buf[BUFFER_SIZE];
memset(buf, 'A', BUFFER_SIZE);

// 批量写入
for (int i = 0; i < 1000; i++) {
if (write(fd, buf, BUFFER_SIZE) == -1) {
perror("write");
break;
}
}

close(fd);
return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc syscall_optimize.c -o syscall_optimize

# 运行
./syscall_optimize

错误处理

系统调用错误处理的方法:

  1. 检查返回值
  2. 使用errno
  3. 错误恢复
  4. 日志记录

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

// 错误处理宏
#define CHECK_ERROR(expr, msg) \
do { \
if ((expr) == -1) { \
fprintf(stderr, "%s: %s\n", msg, strerror(errno)); \
return 1; \
} \
} while (0)

int main() {
// 打开文件
int fd = open("test.txt", O_RDONLY);
CHECK_ERROR(fd, "open failed");

// 读取数据
char buf[1024];
ssize_t n = read(fd, buf, sizeof(buf) - 1);
CHECK_ERROR(n, "read failed");

if (n > 0) {
buf[n] = '\0';
printf("Read: %s", buf);
}

// 关闭文件
CHECK_ERROR(close(fd), "close failed");

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc error_handle.c -o error_handle

# 运行
./error_handle

实践练习

  1. 系统调用实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建测试程序
cat > syscall_test.c << EOL
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
printf("Process ID: %d\n", getpid());
printf("Parent Process ID: %d\n", getppid());
return 0;
}
EOL

# 编译和运行
gcc syscall_test.c -o syscall_test
./syscall_test
  1. 文件操作实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建文件操作测试程序
cat > file_test.c << EOL
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main() {
int fd = open("test.txt", O_CREAT | O_WRONLY, 0644);
if (fd != -1) {
write(fd, "Test message\n", 13);
close(fd);
}
return 0;
}
EOL

# 编译和运行
gcc file_test.c -o file_test
./file_test
  1. 错误处理实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建错误处理测试程序
cat > error_test.c << EOL
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

int main() {
int fd = open("nonexistent.txt", O_RDONLY);
if (fd == -1) {
printf("Error: %s\n", strerror(errno));
}
return 0;
}
EOL

# 编译和运行
gcc error_test.c -o error_test
./error_test

思考题

  1. 系统调用的主要功能是什么?
  2. 系统调用是如何实现的?
  3. 如何优化系统调用的性能?
  4. 系统调用错误处理的方法有哪些?
  5. 进程控制和文件操作的系统调用有哪些?

参考资料

  1. 《程序员的自我修养:链接、装载与库》
  2. Linux 系统调用文档
  3. System V ABI
  4. ELF 文件格式规范
  5. GNU Binutils 文档