mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-19 09:06:32 +00:00
feat(syscall): 实现syscall restart (#1075)
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用. TODO: 实现wait等需要restart_block的系统调用的重启 Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
@ -62,9 +62,11 @@ int main() {
|
||||
perror("signal");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Signal handler for SIGINT is registered.\n");
|
||||
signal_received = 0;
|
||||
kill(getpid(), SIGINT);
|
||||
sleep(5);
|
||||
|
||||
TEST_ASSERT(signal_received, 1, "SIGINT was received", "SIGINT was not received");
|
||||
signal_received = 0;
|
||||
|
||||
|
1
user/apps/test_signal_restart/.gitignore
vendored
Normal file
1
user/apps/test_signal_restart/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test_signal
|
20
user/apps/test_signal_restart/Makefile
Normal file
20
user/apps/test_signal_restart/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
ifeq ($(ARCH), x86_64)
|
||||
CROSS_COMPILE=x86_64-linux-musl-
|
||||
else ifeq ($(ARCH), riscv64)
|
||||
CROSS_COMPILE=riscv64-linux-musl-
|
||||
endif
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
.PHONY: all
|
||||
all: main.c
|
||||
$(CC) -static -o test_signal_restart main.c
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
mv test_signal_restart $(DADK_CURRENT_BUILD_DIR)/test_signal_restart
|
||||
|
||||
clean:
|
||||
rm test_signal_restart *.o
|
||||
|
||||
fmt:
|
106
user/apps/test_signal_restart/main.c
Normal file
106
user/apps/test_signal_restart/main.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
#define MSG "Hello from parent!\n"
|
||||
|
||||
static int handled_signal = 0;
|
||||
// 子进程的信号处理函数
|
||||
void child_signal_handler(int sig) {
|
||||
printf("Child received signal %d\n", sig);
|
||||
handled_signal = 1;
|
||||
}
|
||||
|
||||
// 父进程的信号处理函数
|
||||
void parent_signal_handler(int sig) {
|
||||
printf("Parent received signal %d\n", sig);
|
||||
}
|
||||
|
||||
int main() {
|
||||
int pipefd[2];
|
||||
pid_t pid;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
// 创建管道
|
||||
if (pipe(pipefd) == -1) {
|
||||
perror("pipe");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// 创建子进程
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// 子进程
|
||||
close(pipefd[1]); // 关闭写端
|
||||
|
||||
// 设置子进程的信号处理函数
|
||||
signal(SIGUSR1, child_signal_handler);
|
||||
|
||||
printf("Child: Waiting for data...\n");
|
||||
|
||||
// 尝试从管道中读取数据
|
||||
ssize_t bytes_read = read(pipefd[0], buffer, BUFFER_SIZE - 1);
|
||||
if (bytes_read == -1) {
|
||||
printf("[FAILED]: Child: read error, errno=%d\n", errno);
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (bytes_read == 0) {
|
||||
printf("Child: End of file\n");
|
||||
}
|
||||
|
||||
if (bytes_read != sizeof(MSG) - 1) {
|
||||
printf("[FAILED]: Child: read error: got %ld bytes, expected %ld\n",
|
||||
bytes_read, sizeof(MSG) - 1);
|
||||
} else {
|
||||
printf("[PASS]: Child: read success: got %ld bytes, expected %ld\n",
|
||||
bytes_read, sizeof(MSG) - 1);
|
||||
}
|
||||
|
||||
buffer[bytes_read] = '\0';
|
||||
printf("Child: Received message: %s", buffer);
|
||||
|
||||
close(pipefd[0]);
|
||||
|
||||
if (!handled_signal)
|
||||
printf("[FAILED]: Parent: child did not handle signal\n");
|
||||
else
|
||||
printf("[PASS]: Parent: child handled signal\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
// 父进程
|
||||
close(pipefd[0]); // 关闭读端
|
||||
|
||||
// 设置父进程的信号处理函数
|
||||
signal(SIGCHLD, parent_signal_handler);
|
||||
|
||||
// 发送信号给子进程,中断它的读操作
|
||||
sleep(1); // 确保子进程已经开始读取
|
||||
// printf("Parent: Sending SIGCHLD to child...\n");
|
||||
// kill(pid, SIGCHLD);
|
||||
printf("Parent: Sending SIGUSR1 to child...\n");
|
||||
kill(pid, SIGUSR1);
|
||||
sleep(1); // 确保子进程已经处理了信号
|
||||
|
||||
write(pipefd[1], MSG, strlen(MSG));
|
||||
|
||||
printf("Parent: Sent message: %s", MSG);
|
||||
|
||||
// 等待子进程结束
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
printf("Parent: Child process finished.\n");
|
||||
|
||||
close(pipefd[1]);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
41
user/dadk/config/test_signal_restart-0.1.0.toml
Normal file
41
user/dadk/config/test_signal_restart-0.1.0.toml
Normal file
@ -0,0 +1,41 @@
|
||||
# 用户程序名称
|
||||
name = "test_signal_restart"
|
||||
# 版本号
|
||||
version = "0.1.0"
|
||||
# 用户程序描述信息
|
||||
description = "一个用来测试signal能够正常运行的app"
|
||||
# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果
|
||||
build-once = false
|
||||
# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装
|
||||
install-once = false
|
||||
# 目标架构
|
||||
# 可选值:"x86_64", "aarch64", "riscv64"
|
||||
target-arch = ["x86_64"]
|
||||
# 任务源
|
||||
[task-source]
|
||||
# 构建类型
|
||||
# 可选值:"build-from_source", "install-from-prebuilt"
|
||||
type = "build-from-source"
|
||||
# 构建来源
|
||||
# "build_from_source" 可选值:"git", "local", "archive"
|
||||
# "install_from_prebuilt" 可选值:"local", "archive"
|
||||
source = "local"
|
||||
# 路径或URL
|
||||
source-path = "user/apps/test_signal_restart"
|
||||
# 构建相关信息
|
||||
[build]
|
||||
# (可选)构建命令
|
||||
build-command = "make install"
|
||||
# 安装相关信息
|
||||
[install]
|
||||
# (可选)安装到DragonOS的路径
|
||||
in-dragonos-path = "/bin"
|
||||
# 清除相关信息
|
||||
[clean]
|
||||
# (可选)清除命令
|
||||
clean-command = "make clean"
|
||||
# (可选)依赖项
|
||||
# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]]
|
||||
# 由于原文件中依赖项为空,此处省略[[depends]]部分
|
||||
# (可选)环境变量
|
||||
# 由于原文件中环境变量为空,此处省略[[envs]]部分
|
Reference in New Issue
Block a user