feat: implement fork system call with deep address space cloning (AI)
- Added paging_clone_directory_from(): deep-copies user-space pages so parent and child have independent memory. Kernel pages are shared. - Fixed process_fork() to accept registers_t* for accurate child state, and to clone from the parent's page directory (not the kernel's). - Refactored process_exit() to properly context-switch to next process using new process_switch_to_user assembly stub (loads full registers_t and performs iret), instead of halting unconditionally. - Fixed sys_waitpid() to use proper blocking: marks process BLOCKED, invokes scheduler, and resumes with exit code when child dies. - Added SYSCALL_SWITCHED mechanism to prevent syscall_handler from clobbering the next process's EAX after a context switch. - Created fork-test user app that validates fork + waitpid. - Added docs/fork.md with architecture documentation. Tested: fork-test creates child, both print messages, parent waits for child exit (code 7), parent reaps and exits (code 0). hello-world also verified to still work correctly after the process_exit refactor.
This commit is contained in:
79
apps/fork-test/fork-test.S
Normal file
79
apps/fork-test/fork-test.S
Normal file
@@ -0,0 +1,79 @@
|
||||
#
|
||||
# fork-test: Tests the fork system call.
|
||||
#
|
||||
# 1. Calls SYS_FORK
|
||||
# 2. Parent prints "Parent: pid=<pid>\n" and waits for child
|
||||
# 3. Child prints "Child: pid=0\n" and exits with code 7
|
||||
# 4. Parent exits with code 0
|
||||
#
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
|
||||
# System call numbers
|
||||
.equ SYS_EXIT, 0
|
||||
.equ SYS_WRITE, 1
|
||||
.equ SYS_FORK, 3
|
||||
.equ SYS_GETPID, 4
|
||||
.equ SYS_WAITPID, 6
|
||||
|
||||
_start:
|
||||
# Fork
|
||||
movl $SYS_FORK, %eax
|
||||
int $0x80
|
||||
|
||||
# EAX = 0 in child, child PID in parent
|
||||
testl %eax, %eax
|
||||
jz .child
|
||||
|
||||
.parent:
|
||||
# Save child PID on the stack
|
||||
pushl %eax
|
||||
|
||||
# Print "Parent\n"
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx # fd = stdout
|
||||
movl $parent_msg, %ecx
|
||||
movl $parent_msg_len, %edx
|
||||
int $0x80
|
||||
|
||||
# Waitpid for child
|
||||
popl %ebx # child PID
|
||||
movl $SYS_WAITPID, %eax
|
||||
int $0x80
|
||||
# EAX now has child's exit code (should be 7)
|
||||
|
||||
# Print "Reaped\n"
|
||||
pushl %eax # save exit code
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx
|
||||
movl $reaped_msg, %ecx
|
||||
movl $reaped_msg_len, %edx
|
||||
int $0x80
|
||||
popl %ebx # exit code (unused, exit with 0)
|
||||
|
||||
# Exit with code 0
|
||||
movl $SYS_EXIT, %eax
|
||||
movl $0, %ebx
|
||||
int $0x80
|
||||
|
||||
.child:
|
||||
# Print "Child\n"
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx # fd = stdout
|
||||
movl $child_msg, %ecx
|
||||
movl $child_msg_len, %edx
|
||||
int $0x80
|
||||
|
||||
# Exit with code 7
|
||||
movl $SYS_EXIT, %eax
|
||||
movl $7, %ebx
|
||||
int $0x80
|
||||
|
||||
.section .rodata
|
||||
parent_msg: .ascii "Parent\n"
|
||||
.equ parent_msg_len, . - parent_msg
|
||||
child_msg: .ascii "Child\n"
|
||||
.equ child_msg_len, . - child_msg
|
||||
reaped_msg: .ascii "Reaped\n"
|
||||
.equ reaped_msg_len, . - reaped_msg
|
||||
Reference in New Issue
Block a user