- 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.
80 lines
1.7 KiB
ArmAsm
80 lines
1.7 KiB
ArmAsm
#
|
|
# 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
|