#define UDATA_SEG 0x23
#define TSS_SEG 0x28
+#define USER_START 0x400000
+#define USTACK_SIZE 0x100000
+#define USTACK_TOP 0x9fffffff
+#define USTACK_END (USTACK_TOP - USTACK_SIZE + 1)
+#define UMMAP_AREA 0x4D000000
+
#define SYS_TIMER_FREQUENCY_HZ 2048
#ifndef __ASM__
__LXSYSCALL1(void*, brk, size_t, size)
+__LXSYSCALL(pid_t, getpid)
+
+__LXSYSCALL(pid_t, getppid)
+
+__LXSYSCALL1(void, _exit, int, status)
+
+__LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
+
#endif /* __LUNAIX_UNISTD_H */
*/
#define REGION_WSHARED 0x2
-#define REGION_TYPE_CODE (0)
-#define REGION_TYPE_DATA (1 << 2)
+#define REGION_PERM_MASK 0x1c
+#define REGION_READ (1 << 2)
+#define REGION_WRITE (1 << 3)
+#define REGION_EXEC (1 << 4)
+#define REGION_RW REGION_READ | REGION_WRITE
struct mm_region
{
- struct llist_header* head;
- void* start;
- void* end;
+ struct llist_header head;
+ unsigned long start;
+ unsigned long end;
unsigned int attr;
};
extern void __pg_mount_point;
-/* 三个页挂载点,一个页目录挂载点: 用于临时创建&编辑页表 */
-
-#define PD_MOUNT 0xAFC00000
-#define PG_MOUNT_1 (&__pg_mount_point)
-#define PG_MOUNT_2 (&__pg_mount_point + 0x1000)
-#define PG_MOUNT_3 (&__pg_mount_point + 0x2000)
-#define PG_MOUNT_4 (&__pg_mount_point + 0x3000)
-
+/* 四个页挂载点,两个页目录挂载点: 用于临时创建&编辑页表 */
+
+#define PD_MOUNT_1 0xAFC00000
+#define PD_MOUNT_2 0xAF800000
+#define PG_MOUNT_BASE 0xAF7FF000
+#define PG_MOUNT_1 (PG_MOUNT_BASE)
+#define PG_MOUNT_2 (PG_MOUNT_BASE - 0x1000)
+#define PG_MOUNT_3 (PG_MOUNT_BASE - 0x2000)
+#define PG_MOUNT_4 (PG_MOUNT_BASE - 0x3000)
+#define PD_REFERENCED L2_BASE_VADDR
+
+#define CURPROC_PTE(vpn) (&((x86_page_table*)(PD_MOUNT_1 | (((vpn) & 0xffc00) << 2)))->entry[(vpn) & 0x3ff])
#endif /* __LUNAIX_PAGE_H */
--- /dev/null
+#ifndef __LUNAIX_REGION_H
+#define __LUNAIX_REGION_H
+
+#include <lunaix/mm/mm.h>
+#include <lunaix/process.h>
+
+void region_add(struct proc_info* proc, unsigned long start, unsigned long end, unsigned int attr);
+
+void region_release_all(struct proc_info* proc);
+
+struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr);
+
+
+#endif /* __LUNAIX_REGION_H */
* @return void*
*/
void*
-vmm_mount_pd(void* pde);
+vmm_mount_pd(uintptr_t mnt, void* pde);
/**
* @brief 卸载已挂载的虚拟地址空间
*
*/
void*
-vmm_unmount_pd();
+vmm_unmount_pd(uintptr_t mnt);
#endif /* __LUNAIX_VMM_H */
#include <lunaix/syscall.h>
-__LXSYSCALL1(void, exit, int, status)
-
__LXSYSCALL(void, yield)
#endif /* __LUNAIX_SYS_H */
#include <lunaix/mm/mm.h>
#include <lunaix/types.h>
#include <lunaix/clock.h>
+#include <lunaix/timer.h>
// 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。
#define KERNEL_PID -1
-#define PROC_CREATED 0
+#define PROC_STOPPED 0
#define PROC_RUNNING 1
-#define PROC_STOPPED 2
-#define PROC_TERMNAT 3
+#define PROC_TERMNAT 2
#define PROC_DESTROY 4
+#define PROC_SPOILED 8
+#define PROC_BLOCKED 16
struct proc_mm {
heap_context_t u_heap;
- struct mm_region* region;
+ struct mm_region* regions;
};
struct proc_info {
pid_t pid;
- pid_t parent;
+ struct proc_info* parent;
isr_param intr_ctx;
struct proc_mm mm;
void* page_table;
time_t created;
- time_t parent_created;
uint8_t state;
int32_t exit_code;
int32_t k_status;
+ struct lx_timer* timer;
};
extern struct proc_info* __current;
void destroy_process(pid_t pid);
-void* dup_pagetable(pid_t pid);
+void setup_proc_mem(struct proc_info* proc, uintptr_t kstack_from);
/**
* @brief 复制当前进程(LunaixOS的类 fork (unix) 实现)
* @brief 终止(退出)当前进程
*
*/
-void terminate_process(int exit_code);
+void terminate_proc(int exit_code);
+
+int orphaned_proc(pid_t pid);
struct proc_info* get_process(pid_t pid);
#ifndef __LUNAIX_SCHEDULER_H
#define __LUNAIX_SCHEDULER_H
-#define SCHED_TIME_SLICE 1000
+#define SCHED_TIME_SLICE 200
struct scheduler {
struct proc_info* _procs;
#define LXINVLDPTR -(2)
#define LXOUTOFMEM -(3)
#define LXINVLDPID -(4)
+#define LXSEGFAULT -(5)
#endif /* __LUNAIX_CODE_H */
#include <arch/x86/vectors.h>
-#define __SYSCALL_fork 0x1
-#define __SYSCALL_yield 0x2
-#define __SYSCALL_exit 0x3
-#define __SYSCALL_sbrk 0x4
-#define __SYSCALL_brk 0x5
+#define __SYSCALL_fork 1
+#define __SYSCALL_yield 2
+#define __SYSCALL_sbrk 3
+#define __SYSCALL_brk 4
+#define __SYSCALL_getpid 5
+#define __SYSCALL_getppid 6
+#define __SYSCALL_sleep 7
+#define __SYSCALL__exit 8
#define __SYSCALL_MAX 0x100
);
}
+#define asmlinkage __attribute__((regparm(0)))
+
+#define __PARAM_MAP1(t1, p1) t1 p1
+#define __PARAM_MAP2(t1, p1, ...) t1 p1, __PARAM_MAP1(__VA_ARGS__)
+#define __PARAM_MAP3(t1, p1, ...) t1 p1, __PARAM_MAP2(__VA_ARGS__)
+#define __PARAM_MAP4(t1, p1, ...) t1 p1, __PARAM_MAP3(__VA_ARGS__)
+#define __PARAM_MAP5(t1, p1, ...) t1 p1, __PARAM_MAP4(__VA_ARGS__)
+#define __PARAM_MAP6(t1, p1, ...) t1 p1, __PARAM_MAP5(__VA_ARGS__)
+
#define ___DOINT33(callcode, rettype)\
int v; \
asm volatile ( \
:"i"(LUNAIX_SYS_CALL), "a"(callcode)); \
return (rettype)v; \
+#define __DEFINE_LXSYSCALL(rettype, name) \
+ asmlinkage rettype __lxsys_##name()
+
+#define __DEFINE_LXSYSCALL1(rettype, name, t1, p1) \
+ asmlinkage rettype __lxsys_##name(__PARAM_MAP1(t1, p1))
+
+#define __DEFINE_LXSYSCALL2(rettype, name, t1, p1, t2, p2) \
+ asmlinkage rettype __lxsys_##name(__PARAM_MAP2(t1, p1, t2, p2))
+
+#define __DEFINE_LXSYSCALL3(rettype, name, t1, p1, t2, p2, t3, p3) \
+ asmlinkage rettype __lxsys_##name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3));
+
+#define __DEFINE_LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \
+ asmlinkage rettype __lxsys_##nam (__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4))
+
+
#define __LXSYSCALL(rettype, name) \
rettype name () { \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL1(rettype, name, t1, p1) \
- rettype name (t1 p1) { \
+ rettype name (__PARAM_MAP1(t1, p1)) { \
asm (""::"b"(p1)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL2(rettype, name, t1, p1, t2, p2) \
- rettype name (t1 p1, t2 p2) { \
+ rettype name (__PARAM_MAP2(t1, p1, t2, p2)) { \
asm ("\n"::"b"(p1), "c"(p2)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL3(rettype, name, t1, p1, t2, p2, t3, p3) \
- rettype name (t1 p1, t2 p2, t3 p3) { \
+ rettype name (__PARAM_MAP3(t1, p1, t2, p2, t3, p3)) { \
asm ("\n"::"b"(p1), "c"(p2), "d"(p3)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \
- rettype name (t1 p1, t2 p2, t3 p3, t4 p4) { \
+ rettype name (__PARAM_MAP3(t1, p1, t2, p2, t3, p3, t4, p4)) { \
asm ("\n"::"b"(p1), "c"(p2), "d"(p3), "D"(p4)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
void
timer_init(uint32_t frequency);
-int
+struct lx_timer*
timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags);
+
+struct lx_timer*
timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags);
-int
+struct lx_timer*
timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags);
struct lx_timer_context*
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/mm/page.h>
+#include <lunaix/mm/vmm.h>
LOG_MODULE("intr")
cpu_lcr3(__kernel_ptd);
+ // 将当前进程的页目录挂载到内核地址空间里(页目录挂载点#1),方便访问。
+ vmm_mount_pd(PD_MOUNT_1, __current->page_table);
+
isr_param *lparam = &__current->intr_ctx;
if (lparam->vector <= 255) {
#include <arch/x86/interrupts.h>
#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/mm.h>
+#include <lunaix/mm/region.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/common.h>
#include <lunaix/syslog.h>
+#include <lunaix/status.h>
+#include <lunaix/sched.h>
static void kprintf(const char* fmt, ...) { va_list args; va_start(args, fmt); __kprintf("PFAULT", fmt, args); va_end(args); }
void
intr_routine_page_fault (const isr_param* param)
{
- void* pg_fault_ptr = cpu_rcr2();
- if (!pg_fault_ptr) {
- __print_panic_msg("Null pointer reference", param);
- goto done;
+ uintptr_t ptr = cpu_rcr2();
+ if (!ptr) {
+ goto segv_term;
}
- kprintf("%p", pg_fault_ptr);
- __print_panic_msg("Page fault", param);
+ struct mm_region* hit_region = region_get(__current, ptr);
-done:
- while(1);
+ if (!hit_region) {
+ // Into the void...
+ goto segv_term;
+ }
+
+ if (param->eip == ptr && !(hit_region->attr & REGION_EXEC)) {
+ // Attempt to execute non-executable page
+ goto segv_term;
+ }
+
+ x86_pte_t* pte = CURPROC_PTE(ptr >> 12);
+ if (*pte & PG_PRESENT) {
+ if ((hit_region->attr & REGION_PERM_MASK) == (REGION_RSHARED | REGION_READ)) {
+ // normal page fault, do COW
+ uintptr_t pa = (uintptr_t)vmm_dup_page(__current->pid, PG_ENTRY_ADDR(*pte));
+ pmm_free_page(__current->pid, *pte & ~0xFFF);
+ *pte = (*pte & 0xFFF) | pa | PG_WRITE;
+ return;
+ }
+ else {
+ // impossible cases or accessing privileged page
+ goto segv_term;
+ }
+ } else {
+ if (!(*pte)) {
+ // Invalid location
+ goto segv_term;
+ }
+ // page not present, bring it from disk or somewhere else
+ __print_panic_msg("WIP page fault route", param);
+ while (1);
+ }
+
+segv_term:
+ kprintf(KERROR "(pid: %d) Segmentation fault on %p\n", __current->pid, ptr);
+ terminate_proc(LXSEGFAULT);
+ // should not reach
}
\ No newline at end of file
*/
syscall_table:
1:
- .dc.l 0
- .dc.l dup_proc
- .dc.l schedule
- .dc.l terminate_process
- .dc.l _syscall_sbrk
- .dc.l _syscall_brk
+ .long 0
+ .long __lxsys_fork
+ .long __lxsys_yield
+ .long __lxsys_sbrk
+ .long __lxsys_brk
+ .long __lxsys_getpid
+ .long __lxsys_getppid
+ .long __lxsys_sleep
+ .long __lxsys_exit
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
- .dc.l 0
+ .long 0
.endr
.global syscall_hndlr
struct proc_info kinit;
memset(&kinit, 0, sizeof(kinit));
- kinit.parent = -1;
+ kinit.parent = (void*)0;
kinit.pid = 1;
kinit.intr_ctx = (isr_param) {
.registers.esp = KSTACK_TOP - 20,
.ss = KDATA_SEG,
.eflags = cpu_reflags()
};
- kinit.page_table = dup_pagetable(kinit.pid);
+
+ setup_proc_mem(&kinit, PD_REFERENCED);
// Ok... 准备fork进我们的init进程
/*
KERNEL_PID,
(void*)(VGA_BUFFER_VADDR + (i << PG_SIZE_BITS)),
(void*)(VGA_BUFFER_PADDR + (i << PG_SIZE_BITS)),
- PG_PREM_RW
+ PG_PREM_URW
);
}
{
pid_t pid = 0;
if (!(pid = fork())) {
- while (1)
- {
- // kprintf(KINFO "Process %d\n", i);
- tty_put_char('0'+i);
- yield();
+ sleep(i);
+ if (i == 3) {
+ i = *(int*)0x400000;
}
+ tty_put_char('0'+i);
+ _exit(0);
}
kprintf(KINFO "Forked %d\n", pid);
}
#include <lunaix/status.h>
#include <lunaix/spike.h>
+#include <lunaix/syscall.h>
-int _syscall_sbrk(void* addr) {
+__DEFINE_LXSYSCALL1(int, sbrk, void*, addr) {
heap_context_t* uheap = &__current->mm.u_heap;
mutex_lock(&uheap->lock);
int r = lxsbrk(uheap, addr);
return r;
}
-void* _syscall_brk(size_t size) {
+__DEFINE_LXSYSCALL1(void*, brk, size_t, size) {
heap_context_t* uheap = &__current->mm.u_heap;
mutex_lock(&uheap->lock);
void* r = lxbrk(uheap, size);
return 0;
}
- // 检查权限,保证:1) 用户只能释放用户页; 2) 内核可释放所有页。
- if ((pm->owner & owner) == pm->owner) {
- pm->ref_counts--;
- return 1;
- }
- return 0;
+ // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; 2) 内核可释放所有页。
+ pm->ref_counts--;
+ return 1;
}
int pmm_ref_page(pid_t owner, void* page) {
--- /dev/null
+#include <lunaix/mm/region.h>
+#include <lunaix/mm/kalloc.h>
+#include <lunaix/process.h>
+
+void region_add(struct proc_info* proc,unsigned long start, unsigned long end, unsigned int attr) {
+ struct mm_region* region = lxmalloc(sizeof(struct mm_region));
+
+ *region = (struct mm_region) {
+ .attr = attr,
+ .end = end,
+ .start = start
+ };
+
+ if (!proc->mm.regions) {
+ llist_init_head(®ion->head);
+ proc->mm.regions = region;
+ }
+ else {
+ llist_append(&proc->mm.regions->head, ®ion->head);
+ }
+}
+
+void region_release_all(struct proc_info* proc) {
+ struct mm_region* head = proc->mm.regions;
+ struct mm_region *pos, *n;
+
+ llist_for_each(pos, n, &head->head, head) {
+ lxfree(pos);
+ }
+
+ proc->mm.regions = NULL;
+}
+
+struct mm_region* region_get(struct proc_info* proc, unsigned long vaddr) {
+ struct mm_region* head = proc->mm.regions;
+
+ if (!head) {
+ return NULL;
+ }
+
+ struct mm_region *pos, *n;
+
+ llist_for_each(pos, n, &head->head, head) {
+ if (vaddr >= pos->start && vaddr < pos->end) {
+ return pos;
+ }
+ }
+ return NULL;
+}
}
void*
-vmm_mount_pd(void* pde) {
+vmm_mount_pd(uintptr_t mnt, void* pde) {
x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
- l1pt->entry[(PD_MOUNT >> 22)] = NEW_L1_ENTRY(PG_PREM_RW, pde);
- return PD_MOUNT;
+ l1pt->entry[(mnt >> 22)] = NEW_L1_ENTRY(PG_PREM_RW, pde);
+ return mnt;
}
void*
-vmm_unmount_pd() {
+vmm_unmount_pd(uintptr_t mnt) {
x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
- l1pt->entry[(PD_MOUNT >> 22)] = 0;
+ l1pt->entry[(mnt >> 22)] = 0;
}
\ No newline at end of file
#include <lunaix/process.h>
#include <lunaix/mm/vmm.h>
+#include <lunaix/mm/region.h>
#include <lunaix/clock.h>
#include <lunaix/syslog.h>
#include <lunaix/common.h>
+#include <lunaix/syscall.h>
+#include <lunaix/spike.h>
LOG_MODULE("PROC")
for (size_t j = 0; j < PG_MAX_ENTRIES; j++)
{
- uintptr_t va = ((i << 10) | j) << 12;
- x86_pte_t ppte = ppt->entry[j];
- if (!ppte || !(ppte & PG_PRESENT)) {
- pt->entry[j] = ppte;
- continue;
- }
-
- // FIXME: 根据 mm_region 将读共享的页(如堆)标为只读,而私有的页(如栈),则复制;而写共享的页则无需更改flags
- if (va >= KSTACK_START) {
- void* ppa = vmm_dup_page(pid, PG_ENTRY_ADDR(ppte));
- ppte = ppte & 0xfff | (uintptr_t)ppa;
- }
- pt->entry[j] = ppte;
- // ppte = ppte & ~PG_WRITE;
- // pt->entry[j] = ppte;
- // ppt->entry[j] = ppte;
+ x86_pte_t pte = ppt->entry[j];
+ pmm_ref_page(pid, pte & ~0xfff);
+ pt->entry[j] = pte;
}
ptd->entry[i] = (uintptr_t)pt_pp | PG_PREM_RW;
}
void* dup_pagetable(pid_t pid) {
- return __dup_pagetable(pid, L2_BASE_VADDR);
+ return __dup_pagetable(pid, PD_REFERENCED);
}
-void dup_proc() {
- pid_t pid = alloc_pid();
-
- /*
- FIXME: Problematic! It should mount the page table of process then copy it.
- The current implementation copy the CURRENTLY loaded pgt.
- However, dup_pagetable is designed to copy current loaded pgt.
-
- */
+__DEFINE_LXSYSCALL(void, fork) {
+ dup_proc();
+}
- void* mnt_pt = vmm_mount_pd(__current->page_table);
+__DEFINE_LXSYSCALL(pid_t, getpid) {
+ return __current->pid;
+}
- void* pg = __dup_pagetable(pid, mnt_pt);
+__DEFINE_LXSYSCALL(pid_t, getppid) {
+ return __current->parent->pid;
+}
- vmm_unmount_pd();
+void dup_proc() {
+ pid_t pid = alloc_pid();
struct proc_info pcb = (struct proc_info) {
.created = clock_systime(),
.pid = pid,
.mm = __current->mm,
- .page_table = pg,
.intr_ctx = __current->intr_ctx,
- .parent_created = __current->created
+ .parent = __current
};
+ setup_proc_mem(&pcb, PD_MOUNT_1); //挂载点#1是当前进程的页表
+
+ // 根据 mm_region 进一步配置页表
+ if (__current->mm.regions) {
+ struct mm_region *pos, *n;
+ llist_for_each(pos, n, &__current->mm.regions->head, head) {
+ region_add(&pcb, pos->start, pos->end, pos->attr);
+
+ // 如果写共享,则不作处理。
+ if ((pos->attr & REGION_WSHARED)) {
+ continue;
+ }
+
+ uintptr_t start_vpn = PG_ALIGN(pos->start) >> 12;
+ uintptr_t end_vpn = PG_ALIGN(pos->end) >> 12;
+ for (size_t i = start_vpn; i < end_vpn; i++)
+ {
+ x86_pte_t *curproc = &((x86_page_table*)(PD_MOUNT_1 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+ x86_pte_t *newproc = &((x86_page_table*)(PD_MOUNT_2 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+
+ if (pos->attr == REGION_RSHARED) {
+ // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。
+ *curproc = *curproc & ~PG_WRITE;
+ *newproc = *newproc & ~PG_WRITE;
+ }
+ else {
+ // 如果是私有页,则将该页从新进程中移除。
+ *newproc = 0;
+ }
+ }
+ }
+ }
+
+ vmm_unmount_pd(PD_MOUNT_2);
+
// 正如同fork,返回两次。
pcb.intr_ctx.registers.eax = 0;
__current->intr_ctx.registers.eax = pid;
push_process(&pcb);
+}
+
+extern void __kernel_end;
+
+void setup_proc_mem(struct proc_info* proc, uintptr_t usedMnt) {
+ // copy the entire kernel page table
+ pid_t pid = proc->pid;
+ void* pt_copy = __dup_pagetable(pid, usedMnt);
+
+ vmm_mount_pd(PD_MOUNT_2, pt_copy); // 将新进程的页表挂载到挂载点#2
+
+ // copy the kernel stack
+ for (size_t i = KSTACK_START >> 12; i <= KSTACK_TOP >> 12; i++)
+ {
+ x86_pte_t *ppte = &((x86_page_table*)(PD_MOUNT_2 | ((i & 0xffc00) << 2)))->entry[i & 0x3ff];
+ void* ppa = vmm_dup_page(pid, PG_ENTRY_ADDR(*ppte));
+ *ppte = (*ppte & 0xfff) | (uintptr_t)ppa;
+ }
+
+ // 我们不需要分配内核的区域,因为所有的内核代码和数据段只能通过系统调用来访问,任何非法的访问
+ // 都会导致eip落在区域外面,从而segmentation fault.
+ // 定义用户栈区域,但是不分配实际的物理页。我们会在Page fault handler里面实现动态分配物理页的逻辑。(虚拟内存的好处!)
+ // FIXME: 这里应该放到spawn_proc里面。
+ // region_add(proc, USTACK_END, USTACK_SIZE, REGION_PRIVATE | REGION_RW);
+
+ // 至于其他的区域我们暂时没有办法知道,因为那需要知道用户程序的信息。我们留到之后在处理。
+
+ proc->page_table = pt_copy;
}
\ No newline at end of file
#include <lunaix/spike.h>
#include <lunaix/status.h>
#include <lunaix/syslog.h>
+#include <lunaix/syscall.h>
#define MAX_PROCESS 512
};
}
+void run(struct proc_info* proc) {
+ if (!(__current->state & ~PROC_RUNNING)) {
+ __current->state = PROC_STOPPED;
+ }
+ proc->state = PROC_RUNNING;
+
+ __current = proc;
+
+ cpu_lcr3(__current->page_table);
+
+ apic_done_servicing();
+
+ asm volatile (
+ "pushl %0\n"
+ "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
+}
+
void schedule() {
if (!sched_ctx.ptable_len) {
return;
do {
ptr = (ptr + 1) % sched_ctx.ptable_len;
next = &sched_ctx._procs[ptr];
- } while((next->state != PROC_STOPPED && next->state != PROC_CREATED) && ptr != prev_ptr);
+ } while(next->state != PROC_STOPPED && ptr != prev_ptr);
sched_ctx.procs_index = ptr;
- __current->state = PROC_STOPPED;
- next->state = PROC_RUNNING;
-
- __current = next;
+ run(next);
+}
- cpu_lcr3(__current->page_table);
+static void proc_timer_callback(struct proc_info* proc) {
+ proc->timer = NULL;
+ proc->state = PROC_STOPPED;
+}
- apic_done_servicing();
+__DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) {
+ if (!seconds) {
+ return 0;
+ }
+ if (__current->timer) {
+ return __current->timer->counter / timer_context()->running_frequency;
+ }
- asm volatile (
- "pushl %0\n"
- "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
+ struct lx_timer* timer = timer_run_second(seconds, proc_timer_callback, __current, 0);
+ __current->timer = timer;
+ __current->intr_ctx.registers.eax = seconds;
+ __current->state = PROC_BLOCKED;
+ schedule();
+}
+
+__DEFINE_LXSYSCALL1(void, exit, int, status) {
+ terminate_proc(status);
+}
+
+__DEFINE_LXSYSCALL(void, yield) {
+ schedule();
}
pid_t alloc_pid() {
sched_ctx.ptable_len++;
}
- process->parent = __current->pid;
- process->state = PROC_CREATED;
+ // every process is the parent of first process (pid=1)
+ process->parent = process->parent ? process->parent : &sched_ctx._procs;
+ process->state = PROC_STOPPED;
sched_ctx._procs[index] = *process;
}
void destroy_process(pid_t pid) {
int index = pid - 1;
- if (index < 0 || index > sched_ctx.ptable_len) {
+ if (index <= 0 || index > sched_ctx.ptable_len) {
__current->k_status = LXINVLDPID;
return;
}
// TODO: recycle the physical pages used by page tables
}
-void terminate_process(int exit_code) {
- __current->state = PROC_TERMNAT;
+void terminate_proc(int exit_code) {
+ __current->state = exit_code < 0 ? PROC_SPOILED : PROC_TERMNAT;
__current->exit_code = exit_code;
schedule();
return NULL;
}
return &sched_ctx._procs[index];
+}
+
+int orphaned_proc(pid_t pid) {
+ if(!pid) return 0;
+ if(pid >= sched_ctx.ptable_len) return 0;
+ struct proc_info* proc = &sched_ctx._procs[pid-1];
+ struct proc_info* parent = proc->parent;
+
+ // 如果其父进程的状态是terminated, spoiled 或 destroy中的一种
+ // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程
+ return (parent->state & 0xe) || parent->created > proc->created;
}
\ No newline at end of file
sched_ticks_counter = 0;
}
-int
+struct lx_timer*
timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags)
{
return timer_run(second * timer_ctx->running_frequency, callback, payload, flags);
}
-int
+struct lx_timer*
timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags)
{
return timer_run(timer_ctx->running_frequency / 1000 * millisecond, callback, payload, flags);
}
-int
+struct lx_timer*
timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
{
struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
- if (!timer) return 0;
+ if (!timer) return NULL;
timer->callback = callback;
timer->counter = ticks;
llist_append(timer_ctx->active_timers, &timer->link);
- return 1;
+ return timer;
}
static void
llist_for_each(pos, n, &timer_list_head->link, link)
{
- if (--pos->counter) {
+ if (!pos->counter) {
+ llist_delete(&pos->link);
+ lxfree(pos);
+ continue;
+ }
+
+ if (--(pos->counter)) {
continue;
}
pos->callback ? pos->callback(pos->payload) : 1;
- if (pos->flags & TIMER_MODE_PERIODIC) {
+ if ((pos->flags & TIMER_MODE_PERIODIC)) {
pos->counter = pos->deadline;
- } else {
- llist_delete(&pos->link);
- lxfree(pos);
}
}
}
__kernel_end = ALIGN(4K);
- __pg_mount_point = ALIGN(4K);
- . += 16K;
__proc_table = ALIGN(4K);
. += 128M;
__kernel_heap_start = ALIGN(4K); /* 内核结束的地方即堆开始的地方 */