一、实验目的
二、fork系统调用分析
fork()系统调用用于复制父进程从而创建子进程。fork()的特殊之处在于:一次调用,两次返回。如果fork()执行出现了问题则会返回一个负数。如果fork()系统调用正常执行,会给父进程返回子进程的pid,给子进程返回0。实际上出fork、vfork和clone这3个系统调?,以及do_fork和kernel_thread内核函数都可以实现相同的功能,他们最终都是通过调用_do_fork()函数来实现创建子进程的功能。下面我们来分析_do_fork()函数。
_do_fork代码,具体功能见注释
long _do_fork(struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
struct completion vfork;
struct pid *pid;
struct task_struct *p;
int trace = 0;
long nr;
/*
* Determine whether and which event to report to ptracer. When
* called from kernel_thread or CLONE_UNTRACED is explicitly
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
if (!(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if (args->exit_signal != SIGCHLD)
trace = PTRACE_EVENT_CLONE;
else
trace = PTRACE_EVENT_FORK;
if (likely(!ptrace_event_enabled(current, trace)))
trace = 0;
}<br> //copy_process主要通过dup_task_struct()函数进行进程描述符的复制,将父进程的结构体task_struct变量的值复制给子进程<br> //通过copy_thread()函数进行子进程内核栈的初始化
p = copy_process(NULL, trace, NUMA_NO_NODE, args);//复制进程描述符
add_latent_entropy();
if (IS_ERR(p))
return PTR_ERR(p);
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
trace_sched_process_fork(current, p);
pid = get_task_pid(p, PIDTYPE_PID);
nr = pid_vnr(pid);
if (clone_flags & CLONE_PARENT_SETTID)
put_user(nr, args->parent_tid);
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
get_task_struct(p);
}
wake_up_new_task(p);//将已经准备好进程上下文的子进程加入就绪队列<br> //该函数对task_struct结构体中的thread_struct结构体进行了初始化。<br> //将子进程的ax值设置为0,即fork()系统调用最终给子进程的返回值<br> //设置子进程的sp值,即子进程的内核堆栈<br> //将子进程的ip值设置为ret_from_fork,即子进程返回后开始执行的地方 /* forking complete and child started to run, tell ptracer */
if (unlikely(trace)) ptrace_event_pid(trace, pid); if (clone_flags & CLONE_VFORK) { if (!wait_for_vfork_done(p, &vfork)) ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid); } put_pid(pid); return nr;}
三、execve系统调用分析
execve()用来加载可执行程序,linux系统提供了execl、execlp、execle、execv、execvp和execve等6个库函数,这些库函数统称为exec函数,exec函数都是通过execve系统调?进?内核,对应的系统调?内核处理函数为__x64_sys_execve,最终通过调?do_execve来具体执?加载可执??件的?作。
execve()系统调用的执行过程如下:
四、Linux系统的一般执行过程
结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程
原文:https://www.cnblogs.com/xiehuichina/p/13137926.html