Browse Source

feat(syscall): implement sigaction

greatbridf 1 year ago
parent
commit
74c913f994

+ 5 - 0
gblibc/include/signal.h

@@ -48,6 +48,11 @@ extern "C" {
 #define SIG_UNBLOCK 1
 #define SIG_SETMASK 2
 
+#define SA_RESTORER 0x04000000
+#define SA_ONSTACK  0x08000000
+#define SA_RESTART  0x10000000
+#define SA_NODEFER  0x40000000
+
 #define SIG_DFL ((sighandler_t)0)
 #define SIG_IGN ((sighandler_t)1)
 

+ 5 - 1
include/kernel/interrupt.h

@@ -22,7 +22,7 @@ struct regs_32 {
     uint32_t eax;
 };
 
-struct PACKED interrupt_stack {
+struct interrupt_stack {
     struct regs_32 s_regs;
     void* v_eip;
     uint32_t cs;
@@ -31,6 +31,10 @@ struct PACKED interrupt_stack {
     uint32_t ss;
 };
 
+struct mmx_registers {
+    uint8_t data[512]; // TODO: list of content
+};
+
 // present: When set, the page fault was caused by a page-protection violation.
 //          When not set, it was caused by a non-present page.
 // write:   When set, the page fault was caused by a write access.

+ 1 - 2
include/kernel/process.hpp

@@ -90,8 +90,7 @@ public:
         alloc_kstack();
     }
 
-    constexpr void sleep()
-    { attr.ready = 0; }
+    void sleep();
     void wakeup();
     constexpr bool is_ready() const
     { return attr.ready; }

+ 6 - 3
include/kernel/signal.hpp

@@ -9,6 +9,8 @@
 
 #include <types/cplusplus.hpp>
 
+#include <kernel/interrupt.h>
+
 namespace kernel {
 
 using sigmask_type = uint64_t;
@@ -51,10 +53,11 @@ public:
     void set_handler(signo_type signal, const sigaction& action);
     void get_handler(signo_type signal, sigaction& action) const;
 
-    constexpr bool empty(void) const { return m_list.empty(); }
+    signo_type pending_signal();
 
-    void raise(signo_type signal);
-    signo_type handle();
+    // return value: whether the thread should wake up
+    bool raise(signo_type signal);
+    void handle(interrupt_stack* context, mmx_registers* mmxregs);
     void after_signal(signo_type signal);
 };
 

+ 24 - 10
src/asm/interrupt.s

@@ -159,12 +159,14 @@ irqstub:
     and $0xfffffff0, %esp
 
     # save mmx registers
-    subl $512, %esp
-    fxsave (%esp)
+    sub $(512 + 16), %esp
+    fxsave 16(%esp)
 
-    # push irq number
-    sub $16, %esp
-    mov %eax, (%esp)
+    # save irq number and pointers to context and mmx registers
+    mov %eax, (%esp)  # irq number
+    mov %ebx, 4(%esp) # pointer to context
+    lea 16(%esp), %eax
+    mov %eax, 8(%esp) # pointer to mmx registers
 
     call irq_handler
 
@@ -182,14 +184,26 @@ irqstub:
 syscall_stub:
     pushal
 
-    # stack alignment and push *data
-    movl %esp, %ebx
-    subl $0x4, %esp
-    andl $0xfffffff0, %esp
-    movl %ebx, (%esp)
+    # save current esp
+    mov %esp, %ebx
+
+    # stack alignment
+    and $0xfffffff0, %esp
+
+    # save mmx registers
+    sub $(512 + 16), %esp
+    fxsave 16(%esp)
+
+    # save pointers to context and mmx registers
+    mov %ebx, (%esp) # pointer to context
+    lea 16(%esp), %eax
+    mov %eax, 4(%esp) # pointer to mmx registers
 
     call syscall_entry
 
+    # restore mmx registers
+    fxrstor 16(%esp)
+
     # restore stack
     mov %ebx, %esp
 

+ 1 - 0
src/kernel/event/event.cpp

@@ -56,6 +56,7 @@ bool kernel::cond_var::wait(types::mutex& lock)
     bool ret = schedule();
     lock.lock();
 
+    m_subscribers.remove(thd);
     return ret;
 }
 

+ 10 - 1
src/kernel/interrupt.cpp

@@ -310,7 +310,10 @@ extern "C" void int14_handler(int14_data* d)
     }
 }
 
-extern "C" void irq_handler(int irqno)
+extern "C" void irq_handler(
+    int irqno,
+    interrupt_stack* context,
+    mmx_registers* mmxregs)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
     if (irqno >= 8)
@@ -318,4 +321,10 @@ extern "C" void irq_handler(int irqno)
 
     for (const auto& handler : s_irq_handlers[irqno])
         handler();
+
+    if (context->cs != USER_CODE_SEGMENT)
+        return;
+
+    if (current_thread->signals.pending_signal())
+        current_thread->signals.handle(context, mmxregs);
 }

+ 8 - 3
src/kernel/process.cpp

@@ -252,6 +252,12 @@ void process::send_signal(signo_type signal)
         thd.send_signal(signal);
 }
 
+void thread::sleep()
+{
+    attr.ready = 0;
+    readythds->remove_all(this);
+}
+
 void thread::wakeup()
 {
     attr.ready = 1;
@@ -260,9 +266,8 @@ void thread::wakeup()
 
 void thread::send_signal(signo_type signal)
 {
-    if (signal == SIGCONT)
+    if (signals.raise(signal))
         this->wakeup();
-    signals.raise(signal);
 }
 
 void proclist::kill(pid_t pid, int exit_code)
@@ -583,7 +588,7 @@ bool schedule()
 
 _end:
 
-    return current_thread->signals.handle() == 0;
+    return current_thread->signals.pending_signal() == 0;
 }
 
 void NORETURN schedule_noreturn(void)

+ 77 - 24
src/kernel/signal.cpp

@@ -1,5 +1,6 @@
 #include <kernel/process.hpp>
 #include <kernel/signal.hpp>
+#include <kernel/interrupt.h>
 
 #include <signal.h>
 
@@ -29,7 +30,10 @@ static void stop_process(int signal)
 {
     current_thread->sleep();
 
-    schedule();
+    while (true) {
+        if (schedule())
+            break;
+    }
 
     current_thread->signals.after_signal(signal);
 }
@@ -76,37 +80,64 @@ void signal_list::on_exec()
     });
 }
 
-void signal_list::raise(signo_type signal)
+bool signal_list::raise(signo_type signal)
 {
     // TODO: clear pending signals
-    // if (signal == SIGCONT) {
-    //     m_list.remove_if([](signo_type sig) {
-    //         return sig == SIGSTOP || sig == SIGTSTP
-    //             || sig == SIGTTIN || sig == SIGTTOU;
-    //     });
-    // }
-
-    // if (signal == SIGSTOP)
-    //     m_list.remove(SIGCONT);
+    if (signal == SIGCONT) {
+        m_list.remove_if([](signo_type sig) {
+            return sig == SIGSTOP || sig == SIGTSTP
+                || sig == SIGTTIN || sig == SIGTTOU;
+        });
+        return true;
+    }
 
-    if (m_mask & sigmask(signal))
-        return;
+    if (sigmask(signal) & sigmask_stop) {
+        m_list.remove(SIGCONT);
+        return false;
+    }
 
     auto iter = m_handlers.find(signal);
     if (iter != m_handlers.end()) {
         if (iter->second.sa_handler == SIG_IGN)
-            return;
+            return false;
+    } else {
+        if (sigmask(signal) & sigmask_ignore)
+            return false;
     }
 
     m_list.push_back(signal);
     m_mask |= sigmask(signal);
+
+    return true;
 }
 
-signo_type signal_list::handle()
+signo_type signal_list::pending_signal()
 {
-    if (this->empty())
-        return 0;
+    for (auto iter = m_list.begin(); iter != m_list.end(); ++iter) {
+        auto iter_handler = m_handlers.find(*iter);
+
+        // signal default action
+        if (iter_handler == m_handlers.end()) {
+            if (!(sigmask(*iter) & sigmask_ignore))
+                return *iter;
+            iter = m_list.erase(iter);
+            continue;
+        }
+
+        if (iter_handler->second.sa_handler == SIG_IGN) {
+            iter = m_list.erase(iter);
+            continue;
+        }
+
+        return *iter;
+    }
+    
+    return 0;
+}
 
+void signal_list::handle(interrupt_stack* context, mmx_registers* mmxregs)
+{
+    // assume that the pending signal is at the front of the list
     auto signal = m_list.front();
     m_list.pop_front();
 
@@ -116,7 +147,6 @@ signo_type signal_list::handle()
             terminate_process(signal);
         else // SIGSTOP
             stop_process(signal);
-        return signal;
     }
 
     auto iter = m_handlers.find(signal);
@@ -129,14 +159,37 @@ signo_type signal_list::handle()
             terminate_process_with_core_dump(signal);
         else if (!(sigmask(signal) & sigmask_ignore))
             terminate_process(signal);
-        else // signal is ignored by default
-            return 0;
-    }
-    else {
-        iter->second.sa_handler(signal);
+        // signal is ignored by default
+        return;
     }
 
-    return signal;
+    auto& handler = iter->second;
+    if (!(handler.sa_flags & SA_RESTORER))
+        raise(SIGSYS);
+
+    uint32_t esp = (uint32_t)context->esp;
+    esp -= (sizeof(mmx_registers) + sizeof(interrupt_stack) + 16);
+    esp &= 0xfffffff0;
+
+    auto tmpesp = esp;
+    *(uint32_t*)tmpesp = signal; // signal handler argument: int signo
+    tmpesp += 4;
+    *(uint32_t*)tmpesp = context->esp; // original esp
+    tmpesp += 4;
+
+    tmpesp += 8; // padding to align to 16 bytes
+
+    memcpy((void*)tmpesp, mmxregs, sizeof(mmx_registers));
+    tmpesp += sizeof(mmx_registers); // mmx registers
+    memcpy((void*)tmpesp, context, sizeof(interrupt_stack));
+    tmpesp += sizeof(interrupt_stack); // context
+
+    esp -= sizeof(void*);
+    // signal handler return address: restorer
+    *(uint32_t*)esp = (uint32_t)handler.sa_restorer;
+
+    context->esp = esp;
+    context->v_eip = (void*)handler.sa_handler;
 }
 
 void signal_list::after_signal(signo_type signal)

+ 5 - 2
src/kernel/syscall.cpp

@@ -919,7 +919,9 @@ int _syscall_mkdir(interrupt_stack* data)
     return 0;
 }
 
-extern "C" void syscall_entry(interrupt_stack* data)
+extern "C" void syscall_entry(
+    interrupt_stack* data,
+    mmx_registers* mmxregs)
 {
     int syscall_no = SYSCALL_NO;
 
@@ -937,7 +939,8 @@ extern "C" void syscall_entry(interrupt_stack* data)
 
     SYSCALL_RETVAL = ret;
 
-    current_thread->signals.handle();
+    if (current_thread->signals.pending_signal())
+        current_thread->signals.handle(data, mmxregs);
 }
 
 SECTION(".text.kinit")

+ 2 - 5
src/kernel/tty.cpp

@@ -119,16 +119,14 @@ void serial_tty::recvchar(char c)
     // ^C: SIGINT
     case 0x03:
         procs->send_signal_grp(fg_pgroup, SIGINT);
-        this->m_cv.notify();
         break;
     // ^D: EOF
     case 0x04:
         this->m_cv.notify();
         break;
-    // ^Z: SIGSTOP
+    // ^Z: SIGTSTP
     case 0x1a:
-        procs->send_signal_grp(fg_pgroup, SIGSTOP);
-        this->m_cv.notify();
+        procs->send_signal_grp(fg_pgroup, SIGTSTP);
         break;
     // ^[: ESCAPE
     case 0x1b:
@@ -141,7 +139,6 @@ void serial_tty::recvchar(char c)
     // ^\: SIGQUIT
     case 0x1c:
         procs->send_signal_grp(fg_pgroup, SIGQUIT);
-        this->m_cv.notify();
         break;
     default:
         buf.put(c);

+ 2 - 2
src/kernel/vfs.cpp

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