int do_fork(unsigned long clone_flags, unsigned long stack_start,
struct pt_regs *regs, unsigned long stack_size)
{
int retval = -ENOMEM;
struct task_struct *p;
DECLARE_MUTEX_LOCKED(sem);产生同步互斥的信号量
if (clone_flags & CLONE_PID) {如果父子进程共享同一个进程号
if (current->pid)
return -EPERM;
}
current->vfork_sem = &sem;
p = alloc_task_struct();
if (!p)
goto fork_out;
*p = *current;复制父进程的task_struct
retval = -EAGAIN;
if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur)该用户已经拥有的进程数量达到规定值
goto bad_fork_free;
atomic_inc(&p->user->__count);
atomic_inc(&p->user->processes);
/
Counter increases are protected by
the kernel lock so nr_threads can't
increase under us (but it may decrease).
/
if (nr_threads >= max_threads)内核进程数达到规定值
goto bad_fork_cleanup_count;
get_exec_domain(p->exec_domain);对相应模块的计数器操作
if (p->binfmt && p->binfmt->module)
__MOD_INC_USE_COUNT(p->binfmt->module);
p->did_exec = 0;
p->swappable = 0;
p->state = TASK_UNINTERRUPTIBLE;进程如果进入不了临界区就会深度睡眠
copy_flags(clone_flags, p);
p->pid = get_pid(clone_flags);获取新的pid号
p->run_list.next = NULL;
p->run_list.prev = NULL;
if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) {
p->p_opptr = current;
if (!(p->ptrace & PT_PTRACED))
p->p_pptr = current;
}
p->p_cptr = NULL;
init_waitqueue_head(&p->wait_chldexit);初始化进程等待队列
p->vfork_sem = NULL;
spin_lock_init(&p->alloc_lock);
p->sigpending = 0;
init_sigpending(&p->pending);初始化子进程的待处理信号队列以及有关的结构成分
p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;
init_timer(&p->real_timer);
p->real_timer.data = (unsigned long) p;
p->leader = 0;
p->tty_old_pgrp = 0;
p->times.tms_utime = p->times.tms_stime = 0;
p->times.tms_cutime = p->times.tms_cstime = 0;
#ifdef CONFIG_SMP
{
int i;
p->has_cpu = 0;
p->processor = current->processor;
/?? should we just memset this ??/
for(i = 0; i < smp_num_cpus; i++)
p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
spin_lock_init(&p->sigmask_lock);
}
#endif
p->lock_depth = -1; / -1 = no lock /
p->start_time = jiffies;时钟
retval = -ENOMEM;
/* copy all the process information /
if (copy_files(clone_flags, p))
goto bad_fork_cleanup;
if (copy_fs(clone_flags, p))
goto bad_fork_cleanup_files;
if (copy_sighand(clone_flags, p))
goto bad_fork_cleanup_fs;
if (copy_mm(clone_flags, p))
goto bad_fork_cleanup_sighand;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
goto bad_fork_cleanup_sighand;这段代码系统有条件的复制已打开文件的结构
p->semundo = NULL;
/ Our parent execution domain becomes current domain
These must match for thread signalling to apply /
p->parent_exec_id = p->self_exec_id;子进程的执行域给父进程
/ ok, now we should be set up.. /
p->swappable = 1;进程的储存页面可以被换出
p->exit_signal = clone_flags & CSIGNAL;exit时给父进程一个信号
p->pdeath_signal = 0;
/
"share" dynamic priority between parent and child, thus the
total amount of dynamic priorities in the system doesnt change,
more scheduling fairness. This is only important in the first
timeslice, on the long run the scheduling behaviour is unchanged.
/
p->counter = (current->counter + 1) >> 1;
current->counter >>= 1;将时间配额平分,父子进程各一半
if (!current->counter)
current->need_resched = 1;
/
Ok, add it to the run-queues and make it
visible to the rest of the system.
Let it rip!
/
retval = p->pid;
p->tgid = retval;线程
INIT_LIST_HEAD(&p->thread_group);与父进程形成线程组
write_lock_irq(&tasklist_lock);
if (clone_flags & CLONE_THREAD) {
p->tgid = current->tgid;
list_add(&p->thread_group, ¤t->thread_group);
}
SET_LINKS(p);将子进程的task_struct连入内核的进程队列
hash_pid(p);计算杂凑队列
nr_threads++;
write_unlock_irq(&tasklist_lock);
if (p->ptrace & PT_PTRACED)
send_sig(SIGSTOP, p, 1);
wake_up_process(p); / do this last /
++total_forks;
fork_out:
if ((clone_flags & CLONE_VFORK) && (retval > 0))
down(&sem);
return retval;
bad_fork_cleanup_sighand:
exit_sighand(p);
bad_fork_cleanup_fs:
exit_fs(p); / blocking /
bad_fork_cleanup_files:
exit_files(p); / blocking /
bad_fork_cleanup:
put_exec_domain(p->exec_domain);
if (p->binfmt && p->binfmt->module)
__MOD_DEC_USE_COUNT(p->binfmt->module);
bad_fork_cleanup_count:
atomic_dec(&p->user->processes);
free_uid(p->user);
bad_fork_free:
free_task_struct(p);
goto fork_out;
}