Support to multi-threading and pthread interface (POSIX.1-2008) (#23)
[lunaix-os.git] / lunaix-os / includes / lunaix / process.h
index 6ef1ff0eed297e13f557963a638ff9c9a44e0449..78756de7ab5f121a1c088e665dc6354ded813e23 100644 (file)
@@ -4,21 +4,22 @@
 #include <lunaix/clock.h>
 #include <lunaix/ds/waitq.h>
 #include <lunaix/fs.h>
 #include <lunaix/clock.h>
 #include <lunaix/ds/waitq.h>
 #include <lunaix/fs.h>
+#include <lunaix/iopoll.h>
 #include <lunaix/mm/mm.h>
 #include <lunaix/mm/mm.h>
+#include <lunaix/mm/page.h>
 #include <lunaix/mm/region.h>
 #include <lunaix/signal.h>
 #include <lunaix/timer.h>
 #include <lunaix/types.h>
 #include <lunaix/mm/region.h>
 #include <lunaix/signal.h>
 #include <lunaix/timer.h>
 #include <lunaix/types.h>
+#include <lunaix/spike.h>
+#include <lunaix/pcontext.h>
 #include <stdint.h>
 #include <stdint.h>
-#include <sys/interrupts.h>
 
 
-// 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。
-#define KERNEL_PID -1
 
 /*
 
 /*
-    |C|Bk|De|Tn|Pu|Rn|
-         \----/
-            Dt
+    |C|Sp|Bk|De|Tn|Pu|Rn|
+            \----/
+              Dt
 
     Group Dt: whether this process is terminated.
 
 
     Group Dt: whether this process is terminated.
 
@@ -27,6 +28,7 @@
     De: Destoryed
     Pu: Paused
     Bk: Blocked
     De: Destoryed
     Pu: Paused
     Bk: Blocked
+    Sp: Stopped
     C : Created
 */
 
     C : Created
 */
 
 #define PS_DESTROY 4
 #define PS_PAUSED 8
 #define PS_BLOCKED 16
 #define PS_DESTROY 4
 #define PS_PAUSED 8
 #define PS_BLOCKED 16
-#define PS_CREATED 32
+#define PS_STOPPED 32
+#define PS_CREATED 64
 
 
-#define PS_GrBP (PS_PAUSED | PS_BLOCKED)
+#define PS_GrBP (PS_PAUSED | PS_BLOCKED | PS_STOPPED)
 #define PS_GrDT (PS_TERMNAT | PS_DESTROY)
 #define PS_GrDT (PS_TERMNAT | PS_DESTROY)
+#define PS_Rn (PS_RUNNING | PS_CREATED)
 
 #define proc_terminated(proc) (((proc)->state) & PS_GrDT)
 #define proc_hanged(proc) (((proc)->state) & PS_BLOCKED)
 
 #define proc_terminated(proc) (((proc)->state) & PS_GrDT)
 #define proc_hanged(proc) (((proc)->state) & PS_BLOCKED)
-#define proc_runnable(proc) (((proc)->state) & PS_PAUSED)
+#define proc_runnable(proc) (!(proc)->state || !(((proc)->state) & ~PS_Rn))
 
 
-struct sigact
-{
-    struct sigact* prev;
-    sigset_t sa_mask;
-    void* sa_actor;
-    void* sa_handler;
-    pid_t sender;
-};
 
 
-struct sighail
-{
-    sigset_t sig_pending;
-    sigset_t sig_mask;
-    struct sigact* inprogress;
-    struct sigact signals[_SIG_NUM];
-};
+#define TH_DETACHED 0b0001
+
+#define thread_detached(th) ((th)->flags & TH_DETACHED)
+#define detach_thread(th) ((th)->flags |= TH_DETACHED)
 
 struct proc_sig
 {
 
 struct proc_sig
 {
@@ -70,68 +63,174 @@ struct proc_sig
     isr_param* saved_ictx;
 } __attribute__((packed));
 
     isr_param* saved_ictx;
 } __attribute__((packed));
 
-struct proc_info
+
+struct proc_info;
+
+struct haybed {
+    struct llist_header sleepers;
+    time_t wakeup_time;
+    time_t alarm_time;
+};
+
+struct thread
 {
     /*
         Any change to *critical section*, including layout, size
         must be reflected in arch/i386/interrupt.S.inc to avoid
         disaster!
      */
 {
     /*
         Any change to *critical section*, including layout, size
         must be reflected in arch/i386/interrupt.S.inc to avoid
         disaster!
      */
+    struct
+    {
+        isr_param* intr_ctx;
+        ptr_t ustack_top;
+    };                              // *critical section
+
+    struct {
+        tid_t tid;
+        time_t created;
+        int state;
+        int syscall_ret;
+        ptr_t exit_val;
+        int flags;
+    };
+
+    struct {
+        ptr_t kstack;               // process local kernel stack
+        struct mm_region* ustack;   // process local user stack (NULL for kernel thread)
+    };
+
+    struct haybed sleep;
+
+    struct proc_info* process;
+    struct llist_header proc_sibs;  // sibling to process-local threads
+    struct llist_header sched_sibs; // sibling to scheduler (global) threads
+    struct sigctx sigctx;
+    waitq_t waitqueue;
+};
 
 
-    /* ---- critical section start ---- */
-
-    pid_t pid;
-    struct proc_info* parent;
-    isr_param* intr_ctx;
-    ptr_t ustack_top;
-    ptr_t page_table;
+struct proc_info
+{
+    // active thread, must be at the very beginning
+    struct thread* th_active;
 
 
-    /* ---- critical section end ---- */
+    struct llist_header threads;
+    int thread_count;
 
     struct llist_header tasks;
 
     struct llist_header tasks;
+
     struct llist_header siblings;
     struct llist_header children;
     struct llist_header grp_member;
     struct llist_header siblings;
     struct llist_header children;
     struct llist_header grp_member;
-    waitq_t waitqueue;
 
 
-    struct
-    {
-        struct llist_header sleepers;
-        time_t wakeup_time;
-        time_t alarm_time;
-    } sleep;
-
-    struct proc_mm mm;
-    time_t created;
-    u8_t state;
-    int32_t exit_code;
-    int32_t k_status;
-    struct sighail sigctx;
+    struct {
+        struct proc_info* parent;
+        pid_t pid;
+        pid_t pgid;
+        time_t created;
+
+        int state;
+        int exit_code;
+    };
+
+    struct proc_mm* mm;
+    struct sigregister* sigreg;
     struct v_fdtable* fdtable;
     struct v_dnode* cwd;
     struct v_fdtable* fdtable;
     struct v_dnode* cwd;
-    pid_t pgid;
+    struct {
+        char* cmd;
+        size_t cmd_len;
+    };
+
+    struct iopoll pollctx;
 };
 
 extern volatile struct proc_info* __current;
 };
 
 extern volatile struct proc_info* __current;
+extern volatile struct thread* current_thread;
+
+/**
+ * @brief Check if current process belong to kernel itself
+ * (pid=0)
+ */
+#define kernel_process(proc) (!(proc)->pid)
+
+#define resume_thread(th) (th)->state = PS_READY
+#define pause_thread(th) (th)->state = PS_PAUSED
+#define block_thread(th) (th)->state = PS_BLOCKED
+
+static inline void must_inline
+set_current_executing(struct thread* thread)
+{
+    current_thread = thread;
+    __current = thread->process;
+}
+
+static inline struct proc_mm* 
+vmspace(struct proc_info* proc) 
+{
+    return proc->mm;
+}
+
+static inline ptr_t
+vmroot(struct proc_info* proc) 
+{
+    return proc->mm->vmroot;
+}
+
+static inline vm_regions_t* 
+vmregions(struct proc_info* proc) 
+{
+    return &proc->mm->regions;
+}
 
 static inline void
 
 static inline void
-block_current()
+block_current_thread()
 {
 {
-    __current->state = PS_BLOCKED;
+    block_thread(current_thread);
 }
 
 static inline void
 }
 
 static inline void
-pause_current()
+pause_current_thread()
 {
 {
-    __current->state = PS_PAUSED;
+    pause_thread(current_thread);
 }
 
 static inline void
 }
 
 static inline void
-resume_current()
+resume_current_thread()
 {
 {
-    __current->state = PS_RUNNING;
+    resume_thread(current_thread);
+}
+
+static inline int syscall_result(int retval) {
+    return (current_thread->syscall_ret = retval);
 }
 
 }
 
+/**
+ * @brief Spawn a process with arbitary entry point. 
+ *        The inherit priviledge level is deduced automatically
+ *        from the given entry point
+ * 
+ * @param created returned created main thread
+ * @param entry entry point
+ * @param with_ustack whether to pre-allocate a user stack with it
+ * @return int 
+ */
+int
+spawn_process(struct thread** created, ptr_t entry, bool with_ustack);
+
+/**
+ * @brief Spawn a process that housing a given executable image as well as 
+ *        program argument and environment setting
+ * 
+ * @param created returned created main thread
+ * @param path file system path to executable
+ * @param argv arguments passed to executable
+ * @param envp environment variables passed to executable
+ * @return int 
+ */
+int
+spawn_process_usr(struct thread** created, char* path, 
+                    const char** argv, const char** envp);
+
 /**
  * @brief 分配并初始化一个进程控制块
  *
 /**
  * @brief 分配并初始化一个进程控制块
  *
@@ -159,8 +258,8 @@ commit_process(struct proc_info* process);
 pid_t
 destroy_process(pid_t pid);
 
 pid_t
 destroy_process(pid_t pid);
 
-void
-copy_kernel_stack(struct proc_info* proc, ptr_t kstack_from);
+void 
+delete_process(struct proc_info* proc);
 
 /**
  * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现)
 
 /**
  * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现)
@@ -181,7 +280,10 @@ new_proc();
  *
  */
 void
  *
  */
 void
-terminate_proc(int exit_code);
+terminate_current(int exit_code);
+
+void 
+terminate_proccess(struct proc_info* proc, int exit_code);
 
 int
 orphaned_proc(pid_t pid);
 
 int
 orphaned_proc(pid_t pid);
@@ -189,16 +291,88 @@ orphaned_proc(pid_t pid);
 struct proc_info*
 get_process(pid_t pid);
 
 struct proc_info*
 get_process(pid_t pid);
 
+/* 
+    ========= Thread =========
+*/
+
+void
+commit_thread(struct thread* thread);
+
+struct thread*
+alloc_thread(struct proc_info* process);
+
 void
 void
-proc_setsignal(struct proc_info* proc, int signum);
+destory_thread(ptr_t vm_mnt, struct thread* thread);
 
 void
 
 void
-proc_clear_signal(struct proc_info* proc);
+terminate_thread(struct thread* thread, ptr_t val);
 
 
-// enable interrupt upon transfer
-#define TRANSFER_IE 1
+void
+terminate_current_thread(ptr_t val);
+
+struct thread*
+create_thread(struct proc_info* proc, ptr_t vm_mnt, bool with_ustack);
 
 void
 
 void
-proc_init_transfer(struct proc_info* proc, ptr_t stop, ptr_t target, int flags);
+start_thread(struct thread* th, ptr_t vm_mnt, ptr_t entry);
+
+static inline void
+spawn_kthread(ptr_t entry) {
+    assert(kernel_process(__current));
+
+    struct thread* th = create_thread(__current, VMS_SELF, false);
+    
+    assert(th);
+    start_thread(th, VMS_SELF, entry);
+}
+
+void 
+exit_thread(void* val);
+
+void
+thread_release_mem(struct thread* thread, ptr_t vm_mnt);
+
+/* 
+    ========= Signal =========
+*/
+
+#define pending_sigs(thread) ((thread)->sigctx.sig_pending)
+#define raise_signal(thread, sig) sigset_add(pending_sigs(thread), sig)
+#define sigact_of(proc, sig) ((proc)->sigreg->signals[(sig)])
+#define set_sigact(proc, sig, sigact) ((proc)->sigreg->signals[(sig)] = (sigact))
+
+static inline struct sigact*
+active_signal(struct thread* thread) {
+    struct sigctx* sigctx = &thread->sigctx;
+    struct sigregister* sigreg = thread->process->sigreg;
+    return sigreg->signals[sigctx->sig_active];
+} 
+
+static inline void 
+sigactive_push(struct thread* thread, int active_sig) {
+    struct sigctx* sigctx = &thread->sigctx;
+    int prev_active = sigctx->sig_active;
+
+    assert(sigact_of(thread->process, active_sig));
+
+    sigctx->sig_order[active_sig] = prev_active;
+    sigctx->sig_active = active_sig;
+}
+
+static inline void 
+sigactive_pop(struct thread* thread) {
+    struct sigctx* sigctx = &thread->sigctx;
+    int active_sig = sigctx->sig_active;
+
+    sigctx->sig_active = sigctx->sig_order[active_sig];
+    sigctx->sig_order[active_sig] = active_sig;
+}
+
+void
+proc_setsignal(struct proc_info* proc, signum_t signum);
+
+void
+thread_setsignal(struct thread* thread, signum_t signum);
+
 
 #endif /* __LUNAIX_PROCESS_H */
 
 #endif /* __LUNAIX_PROCESS_H */