1 #include <lunaix/process.h>
2 #include <lunaix/sched.h>
3 #include <lunaix/mm/vmm.h>
5 #include <arch/x86/interrupts.h>
8 #include <lunaix/spike.h>
9 #include <lunaix/status.h>
10 #include <lunaix/syslog.h>
11 #include <lunaix/syscall.h>
13 #define MAX_PROCESS 512
15 struct proc_info* __current;
16 struct proc_info dummy;
18 extern void __proc_table;
20 struct scheduler sched_ctx;
25 size_t pg_size = ROUNDUP(sizeof(struct proc_info) * MAX_PROCESS, 0x1000);
27 vmm_alloc_pages(KERNEL_PID, &__proc_table, pg_size, PG_PREM_RW, PP_FGPERSIST),
28 "Fail to allocate proc table"
31 sched_ctx = (struct scheduler) {
32 ._procs = (struct proc_info*) &__proc_table,
38 void run(struct proc_info* proc) {
39 if (!(__current->state & ~PROC_RUNNING)) {
40 __current->state = PROC_STOPPED;
42 proc->state = PROC_RUNNING;
46 cpu_lcr3(__current->page_table);
48 apic_done_servicing();
52 "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
56 if (!sched_ctx.ptable_len) {
60 struct proc_info* next;
61 int prev_ptr = sched_ctx.procs_index;
63 // round-robin scheduler
65 ptr = (ptr + 1) % sched_ctx.ptable_len;
66 next = &sched_ctx._procs[ptr];
67 } while(next->state != PROC_STOPPED && ptr != prev_ptr);
69 sched_ctx.procs_index = ptr;
74 static void proc_timer_callback(struct proc_info* proc) {
76 proc->state = PROC_STOPPED;
79 __DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) {
83 if (__current->timer) {
84 return __current->timer->counter / timer_context()->running_frequency;
87 struct lx_timer* timer = timer_run_second(seconds, proc_timer_callback, __current, 0);
88 __current->timer = timer;
89 __current->intr_ctx.registers.eax = seconds;
90 __current->state = PROC_BLOCKED;
94 __DEFINE_LXSYSCALL1(void, exit, int, status) {
95 terminate_proc(status);
98 __DEFINE_LXSYSCALL(void, yield) {
104 for (; i < sched_ctx.ptable_len && sched_ctx._procs[i].state != PROC_DESTROY; i++);
106 if (i == MAX_PROCESS) {
107 __current->k_status = LXPROCFULL;
113 void push_process(struct proc_info* process) {
114 int index = process->pid - 1;
115 if (index < 0 || index > sched_ctx.ptable_len) {
116 __current->k_status = LXINVLDPID;
120 if (index == sched_ctx.ptable_len) {
121 sched_ctx.ptable_len++;
124 // every process is the parent of first process (pid=1)
125 process->parent = process->parent ? process->parent : &sched_ctx._procs;
126 process->state = PROC_STOPPED;
128 sched_ctx._procs[index] = *process;
131 void destroy_process(pid_t pid) {
133 if (index <= 0 || index > sched_ctx.ptable_len) {
134 __current->k_status = LXINVLDPID;
138 sched_ctx._procs[index].state = PROC_DESTROY;
140 // TODO: recycle the physical pages used by page tables
143 void terminate_proc(int exit_code) {
144 __current->state = exit_code < 0 ? PROC_SPOILED : PROC_TERMNAT;
145 __current->exit_code = exit_code;
150 struct proc_info* get_process(pid_t pid) {
152 if (index < 0 || index > sched_ctx.ptable_len) {
155 return &sched_ctx._procs[index];
158 int orphaned_proc(pid_t pid) {
160 if(pid >= sched_ctx.ptable_len) return 0;
161 struct proc_info* proc = &sched_ctx._procs[pid-1];
162 struct proc_info* parent = proc->parent;
164 // 如果其父进程的状态是terminated, spoiled 或 destroy中的一种
165 // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程
166 return (parent->state & 0xe) || parent->created > proc->created;