И родитель, и потомок возвращают разные значения из-за манипулирования регистрами ЦП в контексте дочернего элемента.
Каждый процесс в ядре Linux представлен task_struct. task_struct заключена (указатель) в структуру thread_info, которая находится в конце стека режима ядра. Весь контекст CPU (регистры) хранится в этой структуре thread_info.
struct thread_info {
struct task_struct *task; /* main task structure */
struct cpu_context_save cpu_context; /* cpu context */
}
Все системные вызовы fork / clone () вызывают эквивалентную ядру функцию do_fork ().
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
Вот последовательность выполнения
do_fork () -> copy_process-> copy_thread ()
(copy_thread - это вызов функции для конкретной арки)
copy_thread () копирует значения регистра из родительского элемента и изменяет возвращаемое значение на 0
(В случае руки)
struct pt_regs *childregs = task_pt_regs(p);
*childregs = *regs; /* Copy register value from parent process*/
childregs->ARM_r0 = 0; /*Change the return value*/
thread->cpu_context.sp = (unsigned long)childregs;/*Write back the value to thread info*/
thread->cpu_context.pc = (unsigned long)ret_from_fork;
Когда дочерний элемент назначается по расписанию, он выполняет процедуру сборки ret_from_fork (), которая возвращает ноль.
Для родителя он получает возвращаемое значение от do_fork (), которая является pid процесса
nr = task_pid_vnr(p);
return nr;