Bläddra i källkod

feat(pipe): add syscall pipe

greatbridf 2 år sedan
förälder
incheckning
611384a51b

+ 2 - 0
gblibc/include/unistd.h

@@ -20,6 +20,8 @@ ssize_t write(int fd, const void* buf, size_t count);
 int dup(int oldfd);
 int dup2(int oldfd, int newfd);
 
+int pipe(int pipefd[2]);
+
 int close(int fd);
 
 void __attribute__((noreturn)) _exit(int code);

+ 1 - 0
gblibc/private-include/syscall.h

@@ -19,6 +19,7 @@
 #define SYS_close (0x0d)
 #define SYS_dup (0x0e)
 #define SYS_dup2 (0x0f)
+#define SYS_pipe (0x10)
 
 #ifdef __cplusplus
 extern "C" {

+ 5 - 0
gblibc/src/unistd.c

@@ -21,6 +21,11 @@ int dup2(int oldfd, int newfd)
     return syscall2(SYS_dup2, oldfd, newfd);
 }
 
+int pipe(int pipefd[2])
+{
+    return syscall1(SYS_pipe, (uint32_t)pipefd);
+}
+
 int close(int fd)
 {
     return syscall1(SYS_close, fd);

+ 46 - 12
include/kernel/process.hpp

@@ -163,9 +163,15 @@ public:
         // iter should not be nullptr
         constexpr void _close(container_type::iterator_type iter)
         {
-            if (iter->ref == 1)
+            if (iter->ref == 1) {
+                if (iter->type == fs::file::types::pipe) {
+                    iter->ptr.pp->close_one();
+                    if (iter->ptr.pp->is_free())
+                        delete iter->ptr.pp;
+                }
+
                 files->erase(iter);
-            else
+            } else
                 --iter->ref;
         }
 
@@ -207,6 +213,7 @@ public:
                 return -EBADF;
 
             this->arr.insert(types::make_pair(new_fd, iter->value));
+            ++iter->value->ref;
             return new_fd;
         }
 
@@ -227,6 +234,40 @@ public:
                 return &iter->value;
         }
 
+        int pipe(int pipefd[2])
+        {
+            // TODO: set read/write flags
+            auto* pipe = new fs::pipe;
+
+            auto iter = files->emplace_back(fs::file {
+                fs::file::types::pipe,
+                { .pp = pipe },
+                nullptr,
+                0,
+                1,
+            });
+            int fd = _next_fd();
+            arr.insert(types::make_pair(fd, iter));
+
+            // TODO: use copy_to_user()
+            pipefd[0] = fd;
+
+            iter = files->emplace_back(fs::file {
+                fs::file::types::pipe,
+                { .pp = pipe },
+                nullptr,
+                0,
+                1,
+            });
+            fd = _next_fd();
+            arr.insert(types::make_pair(fd, iter));
+
+            // TODO: use copy_to_user()
+            pipefd[1] = fd;
+
+            return 0;
+        }
+
         // TODO: file opening permissions check
         int open(const char* filename, uint32_t flags)
         {
@@ -237,22 +278,15 @@ public:
                 return -1;
             }
 
-            // TODO: unify file, inode, dentry TYPE
-            fs::file::types type = fs::file::types::regular_file;
-            if (dentry->ind->flags.in.directory)
-                type = fs::file::types::directory;
-            if (dentry->ind->flags.in.special_node)
-                type = fs::file::types::block_dev;
-
             // check whether dentry is a file if O_DIRECTORY is set
-            if ((flags & O_DIRECTORY) && type != fs::file::types::directory) {
+            if ((flags & O_DIRECTORY) && !dentry->ind->flags.in.directory) {
                 errno = ENOTDIR;
                 return -1;
             }
 
             auto iter = files->emplace_back(fs::file {
-                type,
-                dentry->ind,
+                fs::file::types::ind,
+                { .ind = dentry->ind },
                 dentry->parent,
                 0,
                 1 });

+ 77 - 5
include/kernel/vfs.hpp

@@ -1,10 +1,14 @@
 #pragma once
 
+#include <assert.h>
 #include <stdint.h>
 #include <types/allocator.hpp>
+#include <types/buffer.hpp>
+#include <types/cplusplus.hpp>
 #include <types/function.hpp>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
+#include <types/lock.hpp>
 #include <types/map.hpp>
 #include <types/types.h>
 #include <types/vector.hpp>
@@ -193,14 +197,82 @@ public:
     virtual int inode_readdir(inode* dir, size_t offset, filldir_func callback) = 0;
 };
 
+class pipe : public types::non_copyable {
+private:
+    static constexpr size_t PIPE_SIZE = 4096;
+    static constexpr uint32_t READABLE = 1;
+    static constexpr uint32_t WRITABLE = 2;
+
+private:
+    types::buffer<types::kernel_allocator> buf;
+    types::mutex mtx;
+    uint32_t flags;
+
+public:
+    pipe(void)
+        : buf { PIPE_SIZE }
+        , flags { READABLE | WRITABLE }
+    {
+    }
+
+    void close_read(void)
+    {
+        flags &= (~READABLE);
+    }
+
+    void close_write(void)
+    {
+        flags &= (~WRITABLE);
+    }
+
+    void close_one(void)
+    {
+        if (flags & READABLE)
+            close_read();
+        else
+            close_write();
+    }
+
+    bool is_free(void) const
+    {
+        return (flags & (READABLE | WRITABLE)) == 0;
+    }
+
+    int write(const char* buf, size_t n)
+    {
+        // TODO: check privilege
+        for (size_t i = 0; i < n; ++i) {
+            if (this->buf.full())
+                assert(false);
+            this->buf.put(*(buf++));
+        }
+
+        return n;
+    }
+
+    int read(char* buf, size_t n)
+    {
+        // TODO: check privilege
+        for (size_t i = 0; i < n; ++i) {
+            if (this->buf.empty())
+                assert(false);
+            *(buf++) = this->buf.pop();
+        }
+
+        return n;
+    }
+};
+
 struct file {
     enum class types {
-        regular_file,
-        directory,
-        block_dev,
-        char_dev,
+        ind,
+        pipe,
+        socket,
     } type;
-    inode* ind;
+    union {
+        inode* ind;
+        pipe* pp;
+    } ptr;
     vfs::dentry* parent;
     size_t cursor;
     size_t ref;

+ 47 - 15
src/kernel/syscall.cpp

@@ -17,7 +17,7 @@
 #include <types/elf.hpp>
 #include <types/status.h>
 
-#define SYSCALL_HANDLERS_SIZE (16)
+#define SYSCALL_HANDLERS_SIZE (32)
 syscall_handler syscall_handlers[SYSCALL_HANDLERS_SIZE];
 
 extern "C" void _syscall_stub_fork_return(void);
@@ -73,12 +73,25 @@ int _syscall_write(interrupt_stack* data)
     if (!file)
         return -EBADF;
 
-    if (file->type == fs::file::types::directory)
-        return -EBADF;
+    switch (file->type) {
+    case fs::file::types::ind: {
+        if (file->ptr.ind->flags.in.directory)
+            return -EBADF;
+
+        int n_wrote = fs::vfs_write(file->ptr.ind, buf, file->cursor, n);
+        if (n_wrote >= 0)
+            file->cursor += n_wrote;
+        return n_wrote;
+    }
+    case fs::file::types::pipe:
+        return file->ptr.pp->write(buf, n);
 
-    int n_wrote = fs::vfs_write(file->ind, buf, file->cursor, n);
-    file->cursor += n_wrote;
-    return n_wrote;
+    case fs::file::types::socket:
+        // TODO
+        return -EINVAL;
+    default:
+        assert(false);
+    }
 }
 
 int _syscall_read(interrupt_stack* data)
@@ -92,14 +105,26 @@ int _syscall_read(interrupt_stack* data)
     if (!file)
         return -EBADF;
 
-    if (file->type == fs::file::types::directory)
-        return -EBADF;
+    switch (file->type) {
+    case fs::file::types::ind: {
+        if (file->ptr.ind->flags.in.directory)
+            return -EBADF;
 
-    // TODO: copy to user function !IMPORTANT
-    int n_wrote = fs::vfs_read(file->ind, buf, n, file->cursor, n);
-    if (n_wrote >= 0)
-        file->cursor += n_wrote;
-    return n_wrote;
+        // TODO: copy to user function !IMPORTANT
+        int n_wrote = fs::vfs_read(file->ptr.ind, buf, n, file->cursor, n);
+        if (n_wrote >= 0)
+            file->cursor += n_wrote;
+        return n_wrote;
+    }
+    case fs::file::types::pipe:
+        return file->ptr.pp->read(buf, n);
+
+    case fs::file::types::socket:
+        // TODO
+        return -EINVAL;
+    default:
+        assert(false);
+    }
 }
 
 int _syscall_sleep(interrupt_stack* data)
@@ -213,11 +238,11 @@ int _syscall_getdents(interrupt_stack* data)
     size_t cnt = data->s_regs.edx;
 
     auto* dir = current_process->files[fd];
-    if (dir->type != fs::file::types::directory)
+    if (dir->type != fs::file::types::ind || !dir->ptr.ind->flags.in.directory)
         return -ENOTDIR;
 
     size_t orig_cnt = cnt;
-    int nread = dir->ind->fs->inode_readdir(dir->ind, dir->cursor,
+    int nread = dir->ptr.ind->fs->inode_readdir(dir->ptr.ind, dir->cursor,
         [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
             if (!len)
                 len = strlen(fn);
@@ -313,6 +338,12 @@ int _syscall_dup2(interrupt_stack* data)
     return current_process->files.dup2(old_fd, new_fd);
 }
 
+int _syscall_pipe(interrupt_stack* data)
+{
+    auto& pipefd = *(int(*)[2])data->s_regs.edi;
+    return current_process->files.pipe(pipefd);
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = data->s_regs.eax;
@@ -345,4 +376,5 @@ void init_syscall(void)
     syscall_handlers[13] = _syscall_close;
     syscall_handlers[14] = _syscall_dup;
     syscall_handlers[15] = _syscall_dup2;
+    syscall_handlers[16] = _syscall_pipe;
 }

+ 26 - 26
user-space-program/sh.c

@@ -111,11 +111,12 @@ struct cmd *parsecmd(char*);
 void
 runcmd(struct cmd *cmd)
 {
-//   int p[2];
+  int p[2];
+  int code;
   struct backcmd *bcmd;
   struct execcmd *ecmd;
   struct listcmd *lcmd;
-//   struct pipecmd *pcmd;
+  struct pipecmd *pcmd;
   struct redircmd *rcmd;
 
   if(cmd == 0)
@@ -148,34 +149,33 @@ runcmd(struct cmd *cmd)
     lcmd = (struct listcmd*)cmd;
     if(fork1() == 0)
       runcmd(lcmd->left);
-    int code;
     wait(&code);
     runcmd(lcmd->right);
     break;
 
-//   case PIPE:
-//     pcmd = (struct pipecmd*)cmd;
-//     if(pipe(p) < 0)
-//       panic("pipe");
-//     if(fork1() == 0){
-//       close(1);
-//       dup(p[1]);
-//       close(p[0]);
-//       close(p[1]);
-//       runcmd(pcmd->left);
-//     }
-//     if(fork1() == 0){
-//       close(0);
-//       dup(p[0]);
-//       close(p[0]);
-//       close(p[1]);
-//       runcmd(pcmd->right);
-//     }
-//     close(p[0]);
-//     close(p[1]);
-//     wait();
-//     wait();
-//     break;
+   case PIPE:
+     pcmd = (struct pipecmd*)cmd;
+     if(pipe(p) < 0)
+       panic("pipe");
+     if(fork1() == 0){
+       close(1);
+       dup(p[1]);
+       close(p[0]);
+       close(p[1]);
+       runcmd(pcmd->left);
+     }
+     if(fork1() == 0){
+       close(0);
+       dup(p[0]);
+       close(p[0]);
+       close(p[1]);
+       runcmd(pcmd->right);
+     }
+     close(p[0]);
+     close(p[1]);
+     wait(&code);
+     wait(&code);
+     break;
     
   case BACK:
     bcmd = (struct backcmd*)cmd;