Browse Source

feat(pipe): send SIGPIPE on read end close

greatbridf 2 years ago
parent
commit
167dd07e9b
4 changed files with 103 additions and 82 deletions
  1. 1 0
      include/kernel/signal.hpp
  2. 8 82
      include/kernel/vfs.hpp
  3. 2 0
      src/kernel/process.cpp
  4. 92 0
      src/kernel/vfs.cpp

+ 1 - 0
include/kernel/signal.hpp

@@ -11,6 +11,7 @@ using sig_t = uint32_t;
 constexpr sig_t SIGINT = 1 << 0;
 constexpr sig_t SIGQUIT = 1 << 1;
 constexpr sig_t SIGSTOP = 1 << 2;
+constexpr sig_t SIGPIPE = 1 << 3;
 
 class signal_list {
 public:

+ 8 - 82
include/kernel/vfs.hpp

@@ -1,7 +1,5 @@
 #pragma once
 
-#include "errno.h"
-
 #include <assert.h>
 #include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
@@ -212,100 +210,28 @@ private:
     uint32_t flags;
 
 public:
-    pipe(void)
-        : buf { PIPE_SIZE }
-        , flags { READABLE | WRITABLE }
-    {
-    }
+    pipe(void);
 
-    void close_read(void)
-    {
-        {
-            types::lock_guard lck(m_cv.mtx());
-            flags &= (~READABLE);
-        }
-        m_cv.notify_all();
-    }
+    void close_read(void);
+    void close_write(void);
 
-    void close_write(void)
-    {
-        {
-            types::lock_guard lck(m_cv.mtx());
-            flags &= (~WRITABLE);
-        }
-        m_cv.notify_all();
-    }
+    int write(const char* buf, size_t n);
+    int read(char* buf, size_t n);
 
-    bool is_readable(void) const
+    constexpr bool is_readable(void) const
     {
         return flags & READABLE;
     }
 
-    bool is_writeable(void) const
+    constexpr bool is_writeable(void) const
     {
         return flags & WRITABLE;
     }
 
-    bool is_free(void) const
+    constexpr bool is_free(void) const
     {
         return !(flags & (READABLE | WRITABLE));
     }
-
-    int write(const char* buf, size_t n)
-    {
-        // TODO: check privilege
-        // TODO: check EPIPE
-        {
-            auto& mtx = m_cv.mtx();
-            types::lock_guard lck(mtx);
-
-            while (this->buf.avail() < n)
-                if (!m_cv.wait(mtx))
-                    return -EINTR;
-
-            for (size_t i = 0; i < n; ++i)
-                this->buf.put(*(buf++));
-        }
-
-        m_cv.notify();
-        return n;
-    }
-
-    int read(char* buf, size_t n)
-    {
-        // TODO: check privilege
-        {
-            auto& mtx = m_cv.mtx();
-            types::lock_guard lck(mtx);
-
-            if (!is_writeable()) {
-                size_t orig_n = n;
-                while (!this->buf.empty() && n--)
-                    *(buf++) = this->buf.get();
-
-                return orig_n - n;
-            }
-
-            while (this->buf.size() < n) {
-                if (!m_cv.wait(mtx))
-                    return -EINTR;
-
-                if (!is_writeable()) {
-                    size_t orig_n = n;
-                    while (!this->buf.empty() && n--)
-                        *(buf++) = this->buf.get();
-
-                    return orig_n - n;
-                }
-            }
-
-            for (size_t i = 0; i < n; ++i)
-                *(buf++) = this->buf.get();
-        }
-
-        m_cv.notify();
-        return n;
-    }
 };
 
 struct file {

+ 2 - 0
src/kernel/process.cpp

@@ -8,6 +8,7 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
+#include <kernel/signal.hpp>
 #include <kernel/vfs.hpp>
 #include <stdint.h>
 #include <stdio.h>
@@ -442,6 +443,7 @@ void check_signal()
     switch (current_process->signals.pop()) {
     case kernel::SIGINT:
     case kernel::SIGQUIT:
+    case kernel::SIGPIPE:
     case kernel::SIGSTOP:
         kill_current(-1);
         break;

+ 92 - 0
src/kernel/vfs.cpp

@@ -1,6 +1,7 @@
 #include <assert.h>
 #include <kernel/errno.h>
 #include <kernel/mem.h>
+#include <kernel/process.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <stdint.h>
@@ -591,6 +592,97 @@ static size_t console_write(fs::special_node*, const char* buf, size_t, size_t n
     return orig_n;
 }
 
+fs::pipe::pipe(void)
+    : buf { PIPE_SIZE }
+    , flags { READABLE | WRITABLE }
+{
+}
+
+void fs::pipe::close_read(void)
+{
+    {
+        types::lock_guard lck(m_cv.mtx());
+        flags &= (~READABLE);
+    }
+    m_cv.notify_all();
+}
+
+void fs::pipe::close_write(void)
+{
+    {
+        types::lock_guard lck(m_cv.mtx());
+        flags &= (~WRITABLE);
+    }
+    m_cv.notify_all();
+}
+
+int fs::pipe::write(const char* buf, size_t n)
+{
+    // TODO: check privilege
+    // TODO: check EPIPE
+    {
+        auto& mtx = m_cv.mtx();
+        types::lock_guard lck(mtx);
+
+        if (!is_readable()) {
+            current_process->signals.set(kernel::SIGPIPE);
+            return -EPIPE;
+        }
+
+        while (this->buf.avail() < n) {
+            if (!m_cv.wait(mtx))
+                return -EINTR;
+
+            if (!is_readable()) {
+                current_process->signals.set(kernel::SIGPIPE);
+                return -EPIPE;
+            }
+        }
+
+        for (size_t i = 0; i < n; ++i)
+            this->buf.put(*(buf++));
+    }
+
+    m_cv.notify();
+    return n;
+}
+
+int fs::pipe::read(char* buf, size_t n)
+{
+    // TODO: check privilege
+    {
+        auto& mtx = m_cv.mtx();
+        types::lock_guard lck(mtx);
+
+        if (!is_writeable()) {
+            size_t orig_n = n;
+            while (!this->buf.empty() && n--)
+                *(buf++) = this->buf.get();
+
+            return orig_n - n;
+        }
+
+        while (this->buf.size() < n) {
+            if (!m_cv.wait(mtx))
+                return -EINTR;
+
+            if (!is_writeable()) {
+                size_t orig_n = n;
+                while (!this->buf.empty() && n--)
+                    *(buf++) = this->buf.get();
+
+                return orig_n - n;
+            }
+        }
+
+        for (size_t i = 0; i < n; ++i)
+            *(buf++) = this->buf.get();
+    }
+
+    m_cv.notify();
+    return n;
+}
+
 SECTION(".text.kinit")
 void init_vfs(void)
 {