Kernel, syscalls

sys_fork()

.align 2
_sys_fork:
  call _find_empty_process
  testl %eax,%eax
  js 1f
  push %gs
  pushl %esi
  pushl %edi
  pushl %ebp
  pushl %eax
  call _copy_process
  addl $20,%esp
1:  ret

FUNCTION find_empty_process()

A:
  IF ++last_pid < 0
    last_pid = 1
  FOR i : 0 -> NR_TASKS
    IF task[i] && task[i].pid == last_pid
      GOTO A
  FOR i : 1 -> NR_TASKS
    IF NOT task[i]
      RETURN i
  RETURN -1
  1. Set last_pid to 1 or more.

  2. From taskid from 0 to max_tasks, if task exists and pid is last_pid then increases pid and again.

  3. From taskid from 1 to max_tasks, if tasks not exists, return.

-> It just iterates through tasks and find last taskid linearly.

FUNCTION copy_process

<- nr, EBP, EDI, ESI, GS, EBX~EDX, CS~FS, EIP, EFLAGS, ESP, SS
-> INT
TASK_STRUCT P
INT I
FILE F

P = (TASK_STRUCT)(GET_FREE_PAGE())

IF NOT P
  RET ERR

SET P 
  START_TIME  = RUNNING
  PID         = LAST_PID
  FATHER      = CURRENT_PID
  COUNTER     = PRIORITY
  START_TIME  = jiffies
  SIGNAL, ALARM, LEADER, UTIME, STIME, CUTIME, CSDTIME, BACK_LINK = 0

  SET TSS
    BACK_LINK = 0
    ESP0      = PAGE_SIZE + ADDR(P)
    SS0       = 0x10
    EAX       = 0
    ES ~ GS   = 0xFFFF
    LDT       = _LDT(nr)

    EIP, EFLAGS   = ARGUMENT 
    ECX ~ EDI     = ARGUMENT

    TRACR_BITMAP  = 0x80000000
  
COPY_MEM (nr, p)
IF <-
  FREE_PAGE ADDR(P)
  RET ERR

FOR i : 0 ~ NR_OPEN
  IF 
    f = P.filp[i]
  THEN
    INCR f.f_count 1

IF 
  CURRENT.PWD
THEN 
  INCR CURRENT.PWD.i_count 1

IF 
  CURRENT.ROOT
THEN
  INCR CURRENT.ROOT.i_count 1

SET_TSS_DESC <- (GDT + nr/2 + FIRST_TSS_ENTRY) , P.TSS
SET_LDT_DESC <- (GDT + nr/2 + FIRST_LDT_ENTRY) , P.LDT

task(nr) <- p

RET last_pid

_sys_fork()

“sys_fork” finds an empty process ID using the search loop in _find_empty_process, then it invokes _copy_process to clone the parent’s kernel context to the new process. This sets up a complete environment for the new process to run independently from the parent, but initially as a nearly identical copy.