Browse Source

feat(syscall): add rt_sigprocmask

greatbridf 1 year ago
parent
commit
a52f58ffb4

+ 43 - 4
gblibc/include/signal.h

@@ -7,10 +7,49 @@
 extern "C" {
 #endif
 
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGPIPE 13
-#define SIGSTOP 19
+#define SIGHUP    1
+#define SIGINT    2
+#define SIGQUIT   3
+#define SIGILL    4
+#define SIGTRAP   5
+#define SIGABRT   6
+#define SIGIOT    SIGABRT
+#define SIGBUS    7
+#define SIGFPE    8
+#define SIGKILL   9
+#define SIGUSR1   10
+#define SIGSEGV   11
+#define SIGUSR2   12
+#define SIGPIPE   13
+#define SIGALRM   14
+#define SIGTERM   15
+#define SIGSTKFLT 16
+#define SIGCHLD   17
+#define SIGCONT   18
+#define SIGSTOP   19
+#define SIGTSTP   20
+#define SIGTTIN   21
+#define SIGTTOU   22
+#define SIGURG    23
+#define SIGXCPU   24
+#define SIGXFSZ   25
+#define SIGVTALRM 26
+#define SIGPROF   27
+#define SIGWINCH  28
+#define SIGIO     29
+#define SIGPOLL   29
+#define SIGPWR    30
+#define SIGSYS    31
+#define SIGUNUSED SIGSYS
+
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
+
+typedef void (*sig_t)(int);
+typedef struct sigset_t {
+    unsigned char __sig[8];
+} sigset_t;
 
 int kill(pid_t pid, int sig);
 int raise(int sig);

+ 12 - 8
include/kernel/process.hpp

@@ -70,6 +70,7 @@ public:
     uint32_t pkstack;
     pid_t owner;
     thread_attr attr;
+    signal_list signals;
 
     int* __user set_child_tid {};
     int* __user clear_child_tid {};
@@ -253,7 +254,6 @@ public:
     process_attr attr {};
     filearr files;
     types::path pwd;
-    kernel::signal_list signals;
     mode_t umask { 0022 };
 
     pid_t pid {};
@@ -277,6 +277,8 @@ public:
     { return attr.system; }
     constexpr bool is_zombie(void) const
     { return attr.zombie; }
+
+    void send_signal(kernel::signal_list::signo_type signal);
 };
 
 class proclist final {
@@ -361,16 +363,18 @@ public:
     }
 
     // the process MUST exist, or the behavior is undefined
-    void send_signal(pid_t pid, kernel::sig_t signal)
+    void send_signal(pid_t pid, kernel::signal_list::signo_type signal)
     {
-        auto& proc = this->find(pid);
-        proc.signals.set(signal);
+        auto& proc = find(pid);
+        proc.send_signal(signal);
     }
-    void send_signal_grp(pid_t pgid, kernel::sig_t signal)
+    void send_signal_grp(pid_t pgid, kernel::signal_list::signo_type signal)
     {
+        // TODO: find processes that are in the same session quickly
         for (auto& [ pid, proc ] : m_procs) {
-            if (proc.pgid == pgid)
-                proc.signals.set(signal);
+            if (proc.pgid != pgid)
+                continue;
+            proc.send_signal(signal);
         }
     }
 
@@ -436,6 +440,6 @@ constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)
 void k_new_thread(void (*func)(void*), void* data);
 
 void NORETURN freeze(void);
-void NORETURN kill_current(int exit_code);
+void NORETURN kill_current(int signo);
 
 void check_signal(void);

+ 20 - 58
include/kernel/signal.hpp

@@ -2,84 +2,46 @@
 
 #include <list>
 
+#include <signal.h>
 #include <stdint.h>
+#include <types/types.h>
+
 #include <types/cplusplus.hpp>
 
 namespace kernel {
 
-using sig_t = uint32_t;
-
-constexpr sig_t SIGINT = 2;
-constexpr sig_t SIGQUIT = 3;
-constexpr sig_t SIGSTOP = 13;
-constexpr sig_t SIGPIPE = 19;
-
 class signal_list {
 public:
-    using list_type = std::list<sig_t>;
+    using signo_type = uint32_t;
+    using list_type = std::list<signo_type>;
 
 private:
     list_type m_list;
-    sig_t m_mask;
+    signo_type m_mask;
+    sig_t m_handlers[32];
 
 public:
-    static constexpr bool check_valid(sig_t sig)
+    static constexpr bool check_valid(signo_type sig)
     {
-        switch (sig) {
-        case SIGINT:
-        case SIGQUIT:
-        case SIGSTOP:
-        case SIGPIPE:
-            return true;
-        default:
-            return false;
-        }
+        return sig > 0 && sig < 32;
     }
 
 public:
-    constexpr signal_list(void)
-        : m_mask(0)
-    {
-    }
-    constexpr signal_list(const signal_list& val)
-        : m_list(val.m_list)
-        , m_mask(val.m_mask)
-    {
-    }
+    signal_list();
+    constexpr signal_list(const signal_list& val) = default;
+    constexpr signal_list(signal_list&& val) = default;
 
-    constexpr signal_list(signal_list&& val)
-        : m_list(std::move(val.m_list))
-        , m_mask(val.m_mask)
-    {
-    }
+    void on_exec();
 
-    constexpr bool empty(void) const
-    {
-        return this->m_list.empty();
-    }
+    void get_mask(sigset_t* __user mask) const;
+    void set_mask(const sigset_t* __user mask);
 
-    constexpr void set(sig_t signal)
-    {
-        if (this->m_mask && signal)
-            return;
+    constexpr bool is_masked(signo_type signal) const { return m_mask & (1 << signal); }
+    constexpr bool empty(void) const { return m_list.empty(); }
 
-        this->m_list.push_back(signal);
-        this->m_mask |= signal;
-    }
-
-    constexpr sig_t pop(void)
-    {
-        if (this->empty())
-            return 0;
-
-        auto iter = this->m_list.begin();
-        sig_t signal = *iter;
-        this->m_list.erase(iter);
-
-        this->m_mask &= ~signal;
-
-        return signal;
-    }
+    void set(signo_type signal);
+    signo_type handle();
+    void after_signal(signo_type signal);
 };
 
 } // namespace kernel

+ 3 - 3
src/kernel/interrupt.cpp

@@ -170,7 +170,7 @@ extern "C" void int6_handler(
         "[kernel] int6 data: cs: %x, eflags: %x\n", cs, eflags);
     kmsg(buf);
     if (!current_process->attr.system)
-        kill_current(-1);
+        kill_current(SIGSEGV);
     else
         die(s_regs, eip);
 }
@@ -189,7 +189,7 @@ extern "C" void int13_handler(
         error_code, cs, eflags);
     kmsg(buf);
     if (!current_process->attr.system)
-        kill_current(-1);
+        kill_current(SIGILL);
     else
         die(s_regs, eip);
 }
@@ -219,7 +219,7 @@ static inline void NORETURN _int14_kill_user(void)
     char buf[256] {};
     snprintf(buf, 256, "Segmentation Fault (pid%d killed)\n", current_process->pid);
     kmsg(buf);
-    kill_current(-1);
+    kill_current(SIGSEGV);
 }
 
 // page fault

+ 25 - 26
src/kernel/process.cpp

@@ -153,8 +153,8 @@ int filearr::open(const process &current,
 
 process::process(const process& parent, pid_t pid)
     : mms { parent.mms }, attr { parent.attr } , pwd { parent.pwd }
-    , signals { parent.signals } , umask { parent.umask }, pid { pid }
-    , ppid { parent.pid } , pgid { parent.pgid } , sid { parent.sid }
+    , umask { parent.umask }, pid { pid } , ppid { parent.pid }
+    , pgid { parent.pgid } , sid { parent.sid }
     , control_tty { parent.control_tty }, root { parent.root }
 {
     this->files.dup_all(parent.files);
@@ -164,6 +164,16 @@ process::process(pid_t pid, pid_t ppid)
     : attr { .system = true }
     , pwd { "/" } , pid { pid } , ppid { ppid } { }
 
+void process::send_signal(kernel::signal_list::signo_type signal)
+{
+    for (auto& thd : thds) {
+        if (thd.signals.is_masked(signal))
+            continue;
+        thd.signals.set(signal);
+        break;
+    }
+}
+
 void proclist::kill(pid_t pid, int exit_code)
 {
     auto& proc = this->find(pid);
@@ -174,6 +184,13 @@ void proclist::kill(pid_t pid, int exit_code)
         readythds->remove_all(&thd);
     }
 
+    // if current process is connected to a tty
+    // clear its read buffer
+    // TODO: make tty line discipline handle this
+    tty* ctrl_tty = current_process->control_tty;
+    if (ctrl_tty)
+        ctrl_tty->clear_read_buf();
+
     // write back mmap'ped files and close them
     proc.files.close_all();
 
@@ -395,6 +412,8 @@ void k_new_thread(void (*func)(void*), void* data)
 SECTION(".text.kinit")
 void NORETURN init_scheduler(void)
 {
+    asm_cli();
+
     procs = new proclist;
     readythds = new readyqueue;
 
@@ -473,8 +492,7 @@ bool schedule()
 
 _end:
 
-    check_signal();
-    return current_process->signals.empty();
+    return current_thread->signals.handle() == 0;
 }
 
 void NORETURN schedule_noreturn(void)
@@ -491,28 +509,9 @@ void NORETURN freeze(void)
         ;
 }
 
-void NORETURN kill_current(int exit_code)
+void NORETURN kill_current(int signo)
 {
-    procs->kill(current_process->pid, exit_code);
+    procs->kill(current_process->pid,
+        (signo + 128) << 8 | (signo & 0xff));
     schedule_noreturn();
 }
-
-void check_signal()
-{
-    switch (current_process->signals.pop()) {
-    case kernel::SIGINT:
-    case kernel::SIGQUIT:
-    case kernel::SIGSTOP: {
-        tty* ctrl_tty = current_process->control_tty;
-        if (ctrl_tty)
-            ctrl_tty->clear_read_buf();
-        kill_current(-1);
-        break;
-    }
-    case kernel::SIGPIPE:
-        kill_current(-1);
-        break;
-    case 0:
-        break;
-    }
-}

+ 134 - 0
src/kernel/signal.cpp

@@ -0,0 +1,134 @@
+#include <kernel/process.hpp>
+#include <kernel/signal.hpp>
+
+#include <signal.h>
+
+using kernel::signal_list;
+using signo_type = signal_list::signo_type;
+
+static void continue_process(int) { }
+
+static void stop_process(int)
+{
+    current_thread->attr.ready = 0;
+    current_thread->attr.wait = 1;
+    readythds->remove_all(current_thread);
+
+    schedule();
+}
+
+static void terminate_process(int signo)
+{
+    kill_current(signo);
+}
+
+static void terminate_process_with_core_dump(int signo)
+{
+    terminate_process(signo & 0x80);
+}
+
+static sig_t default_handlers[32] = {
+    nullptr,
+    terminate_process, // SIGHUP
+    terminate_process, // SIGINT
+    terminate_process_with_core_dump, // SIGQUIT
+    terminate_process_with_core_dump, // SIGILL
+    terminate_process_with_core_dump, // SIGTRAP
+    terminate_process_with_core_dump, // SIGABRT, SIGIOT
+    terminate_process_with_core_dump, // SIGBUS
+    terminate_process_with_core_dump, // SIGFPE
+    terminate_process, // SIGKILL
+    terminate_process, // SIGUSR1
+    terminate_process_with_core_dump, // SIGSEGV
+    terminate_process, // SIGUSR2
+    terminate_process, // SIGPIPE
+    terminate_process, // SIGALRM
+    terminate_process, // SIGTERM
+    terminate_process, // SIGSTKFLT
+    nullptr, // SIGCHLD
+    continue_process, // SIGCONT
+    stop_process, // SIGSTOP
+    stop_process, // SIGTSTP
+    stop_process, // SIGTTIN
+    stop_process, // SIGTTOU
+    nullptr, // SIGURG
+    terminate_process_with_core_dump, // SIGXCPU
+    terminate_process_with_core_dump, // SIGXFSZ
+    terminate_process, // SIGVTALRM
+    terminate_process, // SIGPROF
+    nullptr, // SIGWINCH
+    terminate_process, // SIGIO, SIGPOLL
+    terminate_process, // SIGPWR
+    terminate_process_with_core_dump, // SIGSYS, SIGUNUSED
+};
+
+signal_list::signal_list()
+    : m_mask(0)
+{
+    memcpy(m_handlers, default_handlers, sizeof(m_handlers));
+}
+
+void signal_list::on_exec()
+{
+    for (int i = 1; i < 32; ++i) {
+        if (m_handlers[i])
+            m_handlers[i] = default_handlers[i];
+    }
+}
+
+void signal_list::set(signo_type signal)
+{
+    if (m_mask & (1 << signal))
+        return;
+
+    if (!m_handlers[signal])
+        return;
+
+    m_list.push_back(signal);
+    m_mask |= (1 << signal);
+}
+
+signo_type signal_list::handle()
+{
+    if (this->empty())
+        return 0;
+
+    auto signal = m_list.front();
+    m_list.pop_front();
+
+    if (!m_handlers[signal])
+        return 0;
+
+    m_handlers[signal](signal);
+
+    return signal;
+}
+
+void signal_list::after_signal(signo_type signal)
+{
+    this->m_mask &= ~(1 << signal);
+}
+
+void signal_list::get_mask(sigset_t* mask) const
+{
+    if (!mask)
+        return;
+
+    memset(mask, 0x00, sizeof(sigset_t));
+    for (int i = 1; i < 32; ++i) {
+        if (is_masked(i))
+            mask->__sig[(i-1)/4] |= 3 << (i-1) % 4 * 2;
+    }
+}
+
+void signal_list::set_mask(const sigset_t* mask)
+{
+    if (!mask)
+        return;
+
+    m_mask = 0;
+    for (int i = 1; i < 32; ++i) {
+        if (mask->__sig[(i-1)/4] & (3 << (i-1) % 4 * 2))
+            m_mask |= (1 << i);
+    }
+}

+ 50 - 3
src/kernel/syscall.cpp

@@ -176,6 +176,8 @@ int _syscall_execve(interrupt_stack* data)
     data->v_eip = d.eip;
     data->esp = (uint32_t)d.sp;
 
+    current_thread->signals.on_exec();
+
     return 0;
 }
 
@@ -567,7 +569,7 @@ int _syscall_munmap(interrupt_stack* data)
 [[noreturn]] static void not_implemented()
 {
     console->print("\n[kernel] this function is not implemented\n");
-    kill_current(-1);
+    kill_current(SIGSYS);
 }
 
 int _syscall_sendfile64(interrupt_stack* data)
@@ -744,6 +746,50 @@ int _syscall_kill(interrupt_stack* data)
     return 0;
 }
 
+int _syscall_rt_sigprocmask(interrupt_stack* data)
+{
+    SYSCALL_ARG1(int, how);
+    SYSCALL_ARG2(const sigset_t* __user, set);
+    SYSCALL_ARG3(sigset_t* __user, oldset);
+    SYSCALL_ARG4(size_t, sigsetsize);
+
+    if (sigsetsize != sizeof(sigset_t))
+        return -EINVAL;
+
+    sigset_t sigs;
+    current_thread->signals.get_mask(&sigs);
+
+    // TODO: use copy_to_user
+    if (oldset)
+        memcpy(oldset, &sigs, sizeof(sigset_t));
+
+    // TODO: use copy_from_user
+    switch (how) {
+    case SIG_BLOCK:
+        if (!set)
+            break;
+
+        for (size_t i = 0; i < sizeof(sigset_t); ++i)
+            sigs.__sig[i] |= set->__sig[i];
+        current_thread->signals.set_mask(&sigs);
+        break;
+    case SIG_UNBLOCK:
+        if (!set)
+            break;
+
+        for (size_t i = 0; i < sizeof(sigset_t); ++i)
+            sigs.__sig[i] &= ~set->__sig[i];
+        current_thread->signals.set_mask(&sigs);
+        break;
+    case SIG_SETMASK:
+        if (set)
+            current_thread->signals.set_mask(set);
+        break;
+    }
+
+    return 0;
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = SYSCALL_NO;
@@ -754,14 +800,14 @@ extern "C" void syscall_entry(interrupt_stack* data)
         snprintf(buf, 64,
             "[kernel] syscall %x not implemented\n", syscall_no);
         console->print(buf);
-        kill_current(-1);
+        not_implemented();
     }
 
     int ret = syscall_handlers[syscall_no](data);
 
     SYSCALL_RETVAL = ret;
 
-    check_signal();
+    current_thread->signals.handle();
 }
 
 SECTION(".text.kinit")
@@ -795,6 +841,7 @@ void init_syscall(void)
     syscall_handlers[0x92] = _syscall_writev;
     syscall_handlers[0x93] = _syscall_getsid;
     syscall_handlers[0xac] = _syscall_prctl;
+    syscall_handlers[0xaf] = _syscall_rt_sigprocmask;
     syscall_handlers[0xb7] = _syscall_getcwd;
     syscall_handlers[0xc0] = _syscall_mmap_pgoff;
     syscall_handlers[0xc7] = _syscall_getuid;

+ 3 - 3
src/kernel/tty.cpp

@@ -118,7 +118,7 @@ void serial_tty::recvchar(char c)
         break;
     // ^C: SIGINT
     case 0x03:
-        procs->send_signal_grp(fg_pgroup, kernel::SIGINT);
+        procs->send_signal_grp(fg_pgroup, SIGINT);
         this->m_cv.notify();
         break;
     // ^D: EOF
@@ -127,7 +127,7 @@ void serial_tty::recvchar(char c)
         break;
     // ^Z: SIGSTOP
     case 0x1a:
-        procs->send_signal_grp(fg_pgroup, kernel::SIGSTOP);
+        procs->send_signal_grp(fg_pgroup, SIGSTOP);
         this->m_cv.notify();
         break;
     // ^[: ESCAPE
@@ -140,7 +140,7 @@ void serial_tty::recvchar(char c)
         break;
     // ^\: SIGQUIT
     case 0x1c:
-        procs->send_signal_grp(fg_pgroup, kernel::SIGQUIT);
+        procs->send_signal_grp(fg_pgroup, SIGQUIT);
         this->m_cv.notify();
         break;
     default:

+ 2 - 2
src/kernel/vfs.cpp

@@ -883,7 +883,7 @@ int fs::pipe::write(const char* buf, size_t n)
         types::lock_guard lck(mtx);
 
         if (!is_readable()) {
-            current_process->signals.set(kernel::SIGPIPE);
+            current_thread->signals.set(SIGPIPE);
             return -EPIPE;
         }
 
@@ -892,7 +892,7 @@ int fs::pipe::write(const char* buf, size_t n)
                 return -EINTR;
 
             if (!is_readable()) {
-                current_process->signals.set(kernel::SIGPIPE);
+                current_thread->signals.set(SIGPIPE);
                 return -EPIPE;
             }
         }

+ 13 - 11
src/types/elf.cpp

@@ -99,23 +99,25 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
         auto flen = align_up<12>(phent.vaddr + phent.filesz) - vaddr;
         auto fileoff = align_down<12>(phent.offset);
 
-        auto ret = mmap(
-            (char*)vaddr,
-            phent.filesz + (phent.vaddr & 0xfff),
-            ent_exec->ind,
-            fileoff,
-            1,
-            d->system);
+        if (flen) {
+            auto ret = mmap(
+                (char*)vaddr,
+                phent.filesz + (phent.vaddr & 0xfff),
+                ent_exec->ind,
+                fileoff,
+                1,
+                d->system);
 
-        if (ret != GB_OK)
-            kill_current(-1);
+            if (ret != GB_OK)
+                kill_current(SIGSEGV);
+        }
 
         if (vlen > flen) {
-            ret = mmap((char*)vaddr + flen, vlen - flen,
+            auto ret = mmap((char*)vaddr + flen, vlen - flen,
                 nullptr, 0, true, d->system);
 
             if (ret != GB_OK)
-                kill_current(-1);
+                kill_current(SIGSEGV);
         }
 
         if (vaddr + vlen > data_segment_end)