From 554b73ec9907bdb2be4aa307eeb4be5f31edd0bd Mon Sep 17 00:00:00 2001 From: zzy666-hw <58378196+zzy666-hw@users.noreply.github.com> Date: Sat, 20 Aug 2022 21:47:41 +0800 Subject: [PATCH] add ipc pipe (#28) --- kernel/Makefile | 2 +- kernel/common/wait_queue.c | 17 ++++ kernel/common/wait_queue.h | 9 +++ kernel/ipc/Makefile | 10 +++ kernel/ipc/pipe.c | 162 +++++++++++++++++++++++++++++++++++++ kernel/ipc/pipe.h | 4 + kernel/process/process.c | 21 ++++- kernel/process/process.h | 1 + kernel/syscall/syscall.c | 2 +- kernel/syscall/syscall.h | 9 +++ user/apps/shell/Makefile | 5 +- user/apps/shell/cmd.c | 2 + user/apps/shell/cmd_test.c | 32 ++++++++ user/apps/shell/cmd_test.h | 4 + user/libs/libc/sys/stat.c | 5 ++ user/libs/libc/sys/stat.h | 3 +- 16 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 kernel/ipc/Makefile create mode 100644 kernel/ipc/pipe.c create mode 100644 kernel/ipc/pipe.h create mode 100644 user/apps/shell/cmd_test.c create mode 100644 user/apps/shell/cmd_test.h diff --git a/kernel/Makefile b/kernel/Makefile index ccded971..ddae0775 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,7 +17,7 @@ export ASFLAGS := --64 LD_LIST := head.o -kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest lib +kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest lib ipc diff --git a/kernel/common/wait_queue.c b/kernel/common/wait_queue.c index acd79f4f..86ee7a4e 100644 --- a/kernel/common/wait_queue.c +++ b/kernel/common/wait_queue.c @@ -2,6 +2,7 @@ #include #include #include +#include /** * @brief 初始化等待队列 @@ -30,6 +31,22 @@ void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head) sched_cfs(); } +/** + * @brief 在等待队列上进行等待,同时释放自旋锁 + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head, + void *lock) +{ + wait_queue_node_t *wait = (wait_queue_node_t *)kmalloc(sizeof(wait_queue_node_t), 0); + wait_queue_init(wait, current_pcb); + current_pcb->state = PROC_UNINTERRUPTIBLE; + list_append(&wait_queue_head->wait_list, &wait->wait_list); + spin_unlock((spinlock_t *)lock); + sched_cfs(); +} + /** * @brief 在等待队列上进行等待(允许中断) * diff --git a/kernel/common/wait_queue.h b/kernel/common/wait_queue.h index 4ee63efe..84145b93 100644 --- a/kernel/common/wait_queue.h +++ b/kernel/common/wait_queue.h @@ -1,5 +1,7 @@ #pragma once #include +// #include + // #include /** * @brief 信号量的等待队列 @@ -26,6 +28,13 @@ void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block */ void wait_queue_sleep_on(wait_queue_node_t * wait_queue_head); +/** + * @brief 在等待队列上进行等待,同时释放自旋锁 + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head, + void *lock); /** * @brief 在等待队列上进行等待(允许中断) * diff --git a/kernel/ipc/Makefile b/kernel/ipc/Makefile new file mode 100644 index 00000000..7ee40efa --- /dev/null +++ b/kernel/ipc/Makefile @@ -0,0 +1,10 @@ + +all: pipe.o + +CFLAGS += -I . + +pipe.o: pipe.c + gcc $(CFLAGS) -c pipe.c -o pipe.o + +clean: + echo "Done." \ No newline at end of file diff --git a/kernel/ipc/pipe.c b/kernel/ipc/pipe.c new file mode 100644 index 00000000..bf0fb05f --- /dev/null +++ b/kernel/ipc/pipe.c @@ -0,0 +1,162 @@ +#include "pipe.h" +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PIPE_BUFF_SIZE 512 + +struct pipe_t { + volatile unsigned int valid_cnt; + unsigned int read_pos; + unsigned int write_pos; + wait_queue_node_t read_wait_queue; + wait_queue_node_t write_wait_queue; + char buf[MAX_PIPE_BUFF_SIZE]; + spinlock_t lock; +}; + +long pipe_read(struct vfs_file_t *file_ptr, char *buf, + int64_t count, long *position) +{ + int i = 0; + struct pipe_t *pipe_ptr = NULL; + + kdebug("pipe_read into!\n"); + pipe_ptr = (struct pipe_t *)file_ptr->private_data; + spin_lock(&pipe_ptr->lock); + while (pipe_ptr->valid_cnt == 0) { + /* pipe 空 */ + kdebug("pipe_read empty!\n"); + wait_queue_wakeup(&pipe_ptr->write_wait_queue, PROC_UNINTERRUPTIBLE); + wait_queue_sleep_on_unlock(&pipe_ptr->read_wait_queue, (void *)&pipe_ptr->lock); + spin_lock(&pipe_ptr->lock); + } + for (i = 0; i < pipe_ptr->valid_cnt; i++) { + if (i == count) { + break; + } + copy_to_user(buf + i, &pipe_ptr->buf[pipe_ptr->read_pos], sizeof(char)); + pipe_ptr->read_pos = (pipe_ptr->read_pos + 1) % MAX_PIPE_BUFF_SIZE; + } + pipe_ptr->valid_cnt = pipe_ptr->valid_cnt - i; + spin_unlock(&pipe_ptr->lock); + wait_queue_wakeup(&pipe_ptr->write_wait_queue, PROC_UNINTERRUPTIBLE); + kdebug("pipe_read end!\n"); + + return i; +} +long pipe_write(struct vfs_file_t *file_ptr, char *buf, + int64_t count, long *position) +{ + int i = 0; + struct pipe_t *pipe_ptr = NULL; + + kdebug("pipe_write into!\n"); + pipe_ptr = (struct pipe_t *)file_ptr->private_data; + spin_lock(&pipe_ptr->lock); + while (pipe_ptr->valid_cnt + count >= MAX_PIPE_BUFF_SIZE) { + /* pipe 满 */ + kdebug("pipe_write pipe full!\n"); + wait_queue_wakeup(&pipe_ptr->read_wait_queue, PROC_UNINTERRUPTIBLE); + wait_queue_sleep_on_unlock(&pipe_ptr->write_wait_queue, (void *)&pipe_ptr->lock); + spin_lock(&pipe_ptr->lock); + } + for (i = pipe_ptr->valid_cnt; i < MAX_PIPE_BUFF_SIZE; i++) { + if (i - pipe_ptr->valid_cnt == count) { + break; + } + copy_from_user(&pipe_ptr->buf[pipe_ptr->write_pos], buf + i, sizeof(char)); + pipe_ptr->write_pos = (pipe_ptr->write_pos + 1) % MAX_PIPE_BUFF_SIZE; + } + pipe_ptr->valid_cnt += count; + spin_unlock(&pipe_ptr->lock); + wait_queue_wakeup(&pipe_ptr->read_wait_queue, PROC_UNINTERRUPTIBLE); + kdebug("pipe_write out!\n"); + + return count; +} + +long pipe_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) +{ + return 0; +} + +struct vfs_file_operations_t g_pipe_file_ops = { + .open = NULL, + .close = pipe_close, + .read = pipe_read, + .write = pipe_write, + .lseek = NULL, + .ioctl = NULL, + .readdir = NULL, +}; + +static struct pipe_t *pipe_alloc() +{ + struct pipe_t *pipe_ptr = NULL; + + pipe_ptr = (struct pipe_t *)kmalloc(sizeof(struct pipe_t), 0); + spin_init(&pipe_ptr->lock); + pipe_ptr->read_pos = 0; + pipe_ptr->write_pos = 0; + pipe_ptr->valid_cnt = 0; + memset(pipe_ptr->buf, 0, MAX_PIPE_BUFF_SIZE); + wait_queue_init(&pipe_ptr->read_wait_queue, NULL); + wait_queue_init(&pipe_ptr->write_wait_queue, NULL); + + return pipe_ptr; +} + +/** + * @brief 创建管道 + * + * @param fd(r8) 文件句柄指针 + * @param num(r9) 文件句柄个数 + * @return uint64_t + */ +uint64_t sys_pipe(struct pt_regs *regs) +{ + int *fd = NULL; + struct pipe_t *pipe_ptr = NULL; + struct vfs_file_t *read_file = NULL; + struct vfs_file_t *write_file = NULL; + + fd = (int *)regs->r8; + kdebug("pipe creat into!\n"); + /* step1 申请pipe结构体、初始化 */ + pipe_ptr = pipe_alloc(); + /* step2 申请2个fd文件句柄,1个作为读端、1个作为写端 */ + read_file = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); + memset(read_file, 0, sizeof(struct vfs_file_t)); + fd[0] = process_fd_alloc(read_file); + if (fd[0] == -1) { + kdebug("pipe alloc read fd fail!\n"); + kfree(pipe_ptr); + kfree(read_file); + return -1; + } + write_file = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); + memset(write_file, 0, sizeof(struct vfs_file_t)); + fd[1] = process_fd_alloc(write_file); + if (fd[1] == -1) { + kdebug("pipe alloc write fd fail!\n"); + kfree(pipe_ptr); + kfree(read_file); + kfree(write_file); + return -1; + } + /* step3 绑定pipe和file */ + read_file->private_data = (void *)pipe_ptr; + read_file->file_ops = &g_pipe_file_ops; + read_file->mode = ATTR_READ_ONLY; + write_file->private_data = (void *)pipe_ptr; + write_file->file_ops = &g_pipe_file_ops; + write_file->mode = O_WRONLY; + kdebug("pipe creat end!\n"); + + return 0; +} diff --git a/kernel/ipc/pipe.h b/kernel/ipc/pipe.h new file mode 100644 index 00000000..fc4e81c8 --- /dev/null +++ b/kernel/ipc/pipe.h @@ -0,0 +1,4 @@ +#ifndef __PIPE_H__ +#define __PIPE_H__ + +#endif \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 2d4f9b55..b6974c53 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -1142,4 +1142,23 @@ void process_exit_thread(struct process_control_block *pcb) { } -// #pragma GCC pop_options \ No newline at end of file +/** + * @brief 申请可用的文件句柄 + * + * @return int + */ +int process_fd_alloc(struct vfs_file_t *file) +{ + int fd_num = -1; + struct vfs_file_t **f = current_pcb->fds; + + for (int i = 0; i < PROC_MAX_FD_NUM; ++i) { + /* 找到指针数组中的空位 */ + if (f[i] == NULL) { + fd_num = i; + f[i] = file; + break; + } + } + return fd_num; +} \ No newline at end of file diff --git a/kernel/process/process.h b/kernel/process/process.h index c2a8fbea..8cb93582 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -213,3 +213,4 @@ extern struct mm_struct initial_mm; extern struct thread_struct initial_thread; extern union proc_union initial_proc_union; extern struct process_control_block *initial_proc[MAX_CPU_NUM]; +int process_fd_alloc(struct vfs_file_t *file); diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 2b3fb44d..116e4e50 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -779,7 +779,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = [17] = sys_mkdir, [18] = sys_nanosleep, [19] = sys_clock, - [20] = system_call_not_exists, + [20] = sys_pipe, [21] = sys_mstat, [22 ... 254] = system_call_not_exists, [255] = sys_ahci_end_req}; diff --git a/kernel/syscall/syscall.h b/kernel/syscall/syscall.h index 419f0572..225540ee 100644 --- a/kernel/syscall/syscall.h +++ b/kernel/syscall/syscall.h @@ -79,6 +79,15 @@ uint64_t sys_sbrk(struct pt_regs *regs); */ uint64_t sys_mkdir(struct pt_regs * regs); +/** + * @brief 创建管道 + * 在pipe.c中实现 + * @param fd(r8) 文件句柄指针 + * @param num(r9) 文件句柄个数 + * @return uint64_t + */ +uint64_t sys_pipe(struct pt_regs * regs); + ul sys_ahci_end_req(struct pt_regs *regs); // 系统调用的内核入口程序 diff --git a/user/apps/shell/Makefile b/user/apps/shell/Makefile index b5aae049..66125fd8 100644 --- a/user/apps/shell/Makefile +++ b/user/apps/shell/Makefile @@ -1,4 +1,4 @@ -all: shell.o cmd.o cmd_help.o +all: shell.o cmd.o cmd_help.o cmd_test.o ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell $(shell find . -name "*.o") $(shell find $(sys_libs_dir) -name "*.o") -T shell.lds @@ -9,5 +9,8 @@ shell.o: shell.c cmd.o: cmd.c gcc $(CFLAGS) -c cmd.c -o cmd.o +cmd_test.o: cmd_test.c + gcc $(CFLAGS) -c cmd_test.c -o cmd_test.o + cmd_help.o: cmd_help.c gcc $(CFLAGS) -c cmd_help.c -o cmd_help.o diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index 6d0bf2c0..0c3a9cec 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -12,6 +12,7 @@ #include #include #include "cmd_help.h" +#include "cmd_test.h" // 当前工作目录(在main_loop中初始化) char *shell_current_path = NULL; @@ -34,6 +35,7 @@ struct built_in_cmd_t shell_cmds[] = {"about", shell_cmd_about}, {"free", shell_cmd_free}, {"help", shell_help}, + {"pipe", shell_pipe_test}, }; // 总共的内建命令数量 diff --git a/user/apps/shell/cmd_test.c b/user/apps/shell/cmd_test.c new file mode 100644 index 00000000..a3c0b724 --- /dev/null +++ b/user/apps/shell/cmd_test.c @@ -0,0 +1,32 @@ +#include "cmd_test.h" +#include +#include +#include +#include + +int shell_pipe_test(int argc, char **argv) +{ + int ret = -1; + int fd[2]; + pid_t pid; + char buf[512] = {0}; + char *msg = "hello world"; + + ret = pipe(fd); + if (-1 == ret) { + printf("failed to create pipe\n"); + return -1; + } + pid = fork(); + if (0 == pid) { + // close(fd[0]); + ret = write(fd[1], msg, strlen(msg)); + exit(0); + } else { + // close(fd[1]); + ret = read(fd[0], buf, sizeof(buf)); + printf("parent read %d bytes data: %s\n", ret, buf); + } + + return 0; +} \ No newline at end of file diff --git a/user/apps/shell/cmd_test.h b/user/apps/shell/cmd_test.h new file mode 100644 index 00000000..bdf448a7 --- /dev/null +++ b/user/apps/shell/cmd_test.h @@ -0,0 +1,4 @@ +#pragma once + +#include "cmd.h" +int shell_pipe_test(int argc, char **argv); \ No newline at end of file diff --git a/user/libs/libc/sys/stat.c b/user/libs/libc/sys/stat.c index 6918beb4..b1e5a0b8 100644 --- a/user/libs/libc/sys/stat.c +++ b/user/libs/libc/sys/stat.c @@ -15,4 +15,9 @@ int mkdir(const char *path, mode_t mode) int mstat(struct mstat_t *stat) { return syscall_invoke(SYS_MSTAT, (uint64_t)stat, 0, 0, 0, 0, 0, 0, 0); +} + +int pipe(int *fd) +{ + return syscall_invoke(SYS_PIPE, (uint64_t)fd, 0, 0,0,0,0,0,0); } \ No newline at end of file diff --git a/user/libs/libc/sys/stat.h b/user/libs/libc/sys/stat.h index 2e72c8d4..19382a5d 100644 --- a/user/libs/libc/sys/stat.h +++ b/user/libs/libc/sys/stat.h @@ -24,4 +24,5 @@ int mkdir(const char *path, mode_t mode); * @param stat 传入的内存信息结构体 * @return int 错误码 */ -int mstat(struct mstat_t* stat); \ No newline at end of file +int mstat(struct mstat_t* stat); +int pipe(int *fd); \ No newline at end of file