Browse Source

add ipc pipe (#28)

zzy666-hw 2 years ago
parent
commit
554b73ec99

+ 1 - 1
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
 	
 
 

+ 17 - 0
kernel/common/wait_queue.c

@@ -2,6 +2,7 @@
 #include <sched/sched.h>
 #include <process/process.h>
 #include <mm/slab.h>
+#include <common/spinlock.h>
 
 /**
  * @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 在等待队列上进行等待(允许中断)
  *

+ 9 - 0
kernel/common/wait_queue.h

@@ -1,5 +1,7 @@
 #pragma once
 #include <common/glib.h>
+// #include <common/spinlock.h>
+
 // #include <process/process.h>
 /**
  * @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 在等待队列上进行等待(允许中断)
  * 

+ 10 - 0
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."

+ 162 - 0
kernel/ipc/pipe.c

@@ -0,0 +1,162 @@
+#include "pipe.h"
+#include <common/spinlock.h>
+#include <process/process.h>
+#include <process/ptrace.h>
+#include <filesystem/VFS/VFS.h>
+#include <filesystem/fat32/fat32.h>
+#include <common/atomic.h>
+#include <mm/slab.h>
+
+#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;
+}

+ 4 - 0
kernel/ipc/pipe.h

@@ -0,0 +1,4 @@
+#ifndef __PIPE_H__
+#define __PIPE_H__
+
+#endif

+ 20 - 1
kernel/process/process.c

@@ -1142,4 +1142,23 @@ void process_exit_thread(struct process_control_block *pcb)
 {
 }
 
-// #pragma GCC pop_options
+/**
+ * @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;
+}

+ 1 - 0
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);

+ 1 - 1
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};

+ 9 - 0
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);
 
 // 系统调用的内核入口程序

+ 4 - 1
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

+ 2 - 0
user/apps/shell/cmd.c

@@ -12,6 +12,7 @@
 #include <libc/sys/wait.h>
 #include <libc/sys/stat.h>
 #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},
 
 };
 // 总共的内建命令数量

+ 32 - 0
user/apps/shell/cmd_test.c

@@ -0,0 +1,32 @@
+#include "cmd_test.h"
+#include <libc/stdio.h>
+#include <libc/stdlib.h>
+#include <libc/string.h>
+#include <libc/unistd.h>
+
+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;
+}

+ 4 - 0
user/apps/shell/cmd_test.h

@@ -0,0 +1,4 @@
+#pragma once
+
+#include "cmd.h"
+int shell_pipe_test(int argc, char **argv);

+ 5 - 0
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);
 }

+ 2 - 1
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);
+int mstat(struct mstat_t* stat);
+int pipe(int *fd);