linux系统调用fork()、vfork()、clone()讲解

linux系统调用fork()、vfork()、clone()讲解

clone()主要用来创建一个线程,可以是内核线程和用户线程,也可以创建进程,有选择的复制父进程资源。
fork()用来全面复制父进程资源
vfork()也是用来创建线程,但主要知识作为创建进程的中间步骤。
这三个函数主要是通过配置do_fork()函数来实现的。

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;
}

你可能感兴趣的:(linux内核与编程)