本文共 6216 字,大约阅读时间需要 20 分钟。
/** * copy_semundo,copy_files,copy_fs,copy_sighand,copy_signal * copy_mm,copy_keys,copy_namespace创建新的数据结构,并把父进程相应数据结构的值复制到新数据结构中。 * 除非clone_flags参数指出它们有不同的值。 */ if ((retval = copy_semundo(clone_flags, p))) goto bad_fork_cleanup_audit; //文件描述符 if ((retval = copy_files(clone_flags, p))) goto bad_fork_cleanup_semundo; //文件系统 if ((retval = copy_fs(clone_flags, p))) goto bad_fork_cleanup_files; if ((retval = copy_sighand(clone_flags, p))) goto bad_fork_cleanup_fs; if ((retval = copy_signal(clone_flags, p))) goto bad_fork_cleanup_sighand; //复制进程的地址空间 if ((retval = copy_mm(clone_flags, p))) goto bad_fork_cleanup_signal; if ((retval = copy_keys(clone_flags, p))) goto bad_fork_cleanup_mm; if ((retval = copy_namespace(clone_flags, p))) goto bad_fork_cleanup_keys;
childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; //复制父进程的用户态程序的上下文信息 *childregs = *regs; //设置子进程地eax地值为0,这个是子进程的返回值 childregs->eax = 0; //存放父进程用户态进程栈地起始位置 //这样子进程返回的时候,可以顺着父进程的执行位置开始往下执行 childregs->esp = esp; /* 从esp->esp0的保存用户态的进程的上下文信息 */ //设置子进程的esp p->thread.esp = (unsigned long) childregs; //子进程内核栈的起始位置 p->thread.esp0 = (unsigned long) (childregs+1); //获取父进程的用户栈的偏移地址(eip)的值 p->thread.eip = (unsigned long) ret_from_fork;
从父进程中分出一半的时间片给子进程,然后将父进程与子进程的状态置为就绪态
当时间片轮到父进程与子进程执行的时候,会从两个进程的上下文信息中找到进程的执行位置,开始执行 子进程的eax寄存器的值为0 所以fork()的语句返回0,父进程的eax中保存的是子进程的pid 所以返回值为子进程的pidstruct mm_struct { //mmap指向虚拟区间链表 struct vm_area_struct * mmap; /* list of VMAs *///指向红黑树 struct rb_root mm_rb;//指向最近的虚拟空间 struct vm_area_struct * mmap_cache; /* last find_vma result */// unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); void (*unmap_area) (struct mm_struct *mm, unsigned long addr); unsigned long mmap_base; /* base of mmap area */ unsigned long task_size; /* size of task vm space */ unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ unsigned long free_area_cache; /* first hole of size cached_hole_size or larger *///指向进程的页目录 pgd_t * pgd;//空间中有多少用户 atomic_t mm_users; /* How many users with user space? *///引用计数;描述有多少指针指向当前的mm_struct atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) *///虚拟区间的个数 int map_count; /* number of VMAs */ struct rw_semaphore mmap_sem;//保护任务页表 spinlock_t page_table_lock; /* Protects page tables and some counters *///所有mm的链表 struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung * together off init_mm.mmlist, and are protected * by mmlist_lock */ /* Special counters, in some configurations protected by the * page_table_lock, in other configurations by being atomic. */ mm_counter_t _file_rss; mm_counter_t _anon_rss; unsigned long hiwater_rss; /* High-watermark of RSS usage */ unsigned long hiwater_vm; /* High-water virtual memory usage */ unsigned long total_vm, locked_vm, shared_vm, exec_vm; unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;//start_code:代码段的起始地址//end_code:代码段的结束地址//start_data:数据段起始地址//end_data:数据段结束地址 unsigned long start_code, end_code, start_data, end_data;//start_brk:堆的起始地址//brk:堆的结束地址//start_stack:栈的起始地址 unsigned long start_brk, brk, start_stack;//arg_start,arg_end:参数段的起始和结束地址//env_start,env_end:环境段的起始和结束地址 unsigned long arg_start, arg_end, env_start, env_end; unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ struct linux_binfmt *binfmt; cpumask_t cpu_vm_mask; /* Architecture-specific MM context */ mm_context_t context; /* Swap token stuff */ /* * Last value of global fault stamp as seen by this process. * In other words, this value gives an indication of how long * it has been since this task got the token. * Look at mm/thrash.c */ unsigned int faultstamp; unsigned int token_priority; unsigned int last_interval; unsigned long flags; /* Must use atomic bitops to access the bits */ struct core_state *core_state; /* coredumping support */#ifdef CONFIG_AIO spinlock_t ioctx_lock; struct hlist_head ioctx_list;#endif#ifdef CONFIG_MM_OWNER /* * "owner" points to a task that is regarded as the canonical * user/owner of this mm. All of the following must be true in * order for it to be changed: * * current == mm->owner * current->mm != mm * new_owner->mm == mm * new_owner->alloc_lock is held */ struct task_struct *owner;#endif#ifdef CONFIG_PROC_FS /* store ref to file /proc/vm_area_struct 中包含虚拟地址块的起始地址,结束地址,和next指针。/exe symlink points to */ struct file *exe_file; unsigned long num_exe_file_vmas;#endif#ifdef CONFIG_MMU_NOTIFIER struct mmu_notifier_mm *mmu_notifier_mm;#endif};
每个进程并不是全部使用了4G的虚拟地址空间,可能仅仅使用了其中的很小的一部分,这时候,进程没有必要将所有的虚拟地址空间的地址都保存,只需要保存其中一部分即可。
当虚拟区间较少时,采用单链表即mmap管理这些虚拟区间; 当虚拟区间较多时,采用红黑树管理这些虚拟区间。转载地址:http://tanwi.baihongyu.com/