姓名:周毅原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
这篇文章主要分析linux调用fork系统调用时,执行了哪些过程。
一、fork系统调用代码分析
fork()允许用户态下创建新的进程, fork 创造的子进程复制了父亲进程的资源,包括内存的内容和task_struct内容,新旧进程使用同一代码段,复制数据段和堆栈段。在 Linux 内核中,供用户创建进程的系统调用fork()函数的响应函数是 sys_fork()、sys_clone()、sys_vfork()。这三个函数都是通过调用内核函数 do_fork() 来实现的。
do_fork在/linux-3.18.6/kernel/fork.c中定义:

1623long do_fork(unsigned long clone_flags,
1624          unsigned long stack_start,
1625          unsigned long stack_size,
1626          int __user *parent_tidptr,
1627          int __user *child_tidptr)
1628{
1629    struct task_struct *p; //创建新的进程描述符
1630    int trace = 0;
1631    long nr;
1632
1633    /*
1634     * Determine whether and which event to report to ptracer.  When
1635     * called from kernel_thread or CLONE_UNTRACED is explicitly
1636     * requested, no event is reported; otherwise, report if the event
1637     * for the type of forking is enabled.
1638     */
1639    if (!(clone_flags & CLONE_UNTRACED)) {
1640        if (clone_flags & CLONE_VFORK)
1641            trace = PTRACE_EVENT_VFORK;
1642        else if ((clone_flags & CSIGNAL) != SIGCHLD)
1643            trace = PTRACE_EVENT_CLONE;
1644        else
1645            trace = PTRACE_EVENT_FORK;
1646
1647        if (likely(!ptrace_event_enabled(current, trace)))
1648            trace = 0;
1649    }
1650    //复制父进程的进程数据
1651    p = copy_process(clone_flags, stack_start, stack_size,
1652             child_tidptr, NULL, trace);
1653    /*
1654     * Do this prior waking up the new thread - the thread pointer
1655     * might get invalid after that point, if the thread exits quickly.
1656     */
1657    if (!IS_ERR(p)) {
1658        struct completion vfork;
1659        struct pid *pid;
1660
1661        trace_sched_process_fork(current, p);
1662
1663        pid = get_task_pid(p, PIDTYPE_PID);
1664        nr = pid_vnr(pid);
1665
1666        if (clone_flags & CLONE_PARENT_SETTID)
1667            put_user(nr, parent_tidptr);
1668
1669        if (clone_flags & CLONE_VFORK) {
1670            p->vfork_done = &vfork;
1671            init_completion(&vfork);
1672            get_task_struct(p);
1673        }
1674        //将子进程添加到调度器的队列,使得子进程有机会获得CPU
1675        wake_up_new_task(p);
1676
1677        /* forking complete and child started to run, tell ptracer */
1678        if (unlikely(trace))
1679            ptrace_event_pid(trace, pid);
1680
1681        if (clone_flags & CLONE_VFORK) {
1682            if (!wait_for_vfork_done(p, &vfork))
1683                ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
1684        }
1685
1686        put_pid(pid);
1687    } else {
1688        nr = PTR_ERR(p);
1689    }
1690    return nr;
1691}

copy_process是做复制父进程,创建子进程过程:

1182static struct task_struct *copy_process(unsigned long clone_flags,
1183                    unsigned long stack_start,
1184                    unsigned long stack_size,
1185                    int __user *child_tidptr,
1186                    struct pid *pid,
1187                    int trace)
1188{
1189    int retval;
1190    struct task_struct *p;//创建子进程PCB结构体
1191
1192    if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
1193        return ERR_PTR(-EINVAL);
1194
1195    if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
1196        return ERR_PTR(-EINVAL);
1197
1198    /*
1199     * Thread groups must share signals as well, and detached threads
1200     * can only be started up within the thread group.
1201     */
1202    if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
1203        return ERR_PTR(-EINVAL);
1204
1205    /*
1206     * Shared signal handlers imply shared VM. By way of the above,
1207     * thread groups also imply shared VM. Blocking this case allows
1208     * for various simplifications in other code.
1209     */
1210    if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
1211        return ERR_PTR(-EINVAL);
1212
1213    /*
1214     * Siblings of global init remain as zombies on exit since they are
1215     * not reaped by their parent (swapper). To solve this and to avoid
1216     * multi-rooted process trees, prevent global and container-inits
1217     * from creating siblings.
1218     */
1219    if ((clone_flags & CLONE_PARENT) &&
1220                current->signal->flags & SIGNAL_UNKILLABLE)
1221        return ERR_PTR(-EINVAL);
1222
1223    /*
1224     * If the new process will be in a different pid or user namespace
1225     * do not allow it to share a thread group or signal handlers or
1226     * parent with the forking task.
1227     */
1228    if (clone_flags & CLONE_SIGHAND) {
1229        if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
1230            (task_active_pid_ns(current) !=
1231                current->nsproxy->pid_ns_for_children))
1232            return ERR_PTR(-EINVAL);
1233    }
1234
1235    retval = security_task_create(clone_flags);
1236    if (retval)
1237        goto fork_out;
1238
1239    retval = -ENOMEM;
1240    p = dup_task_struct(current);  //current为当前进程,复制当前进程PCB
1241    if (!p)
1242        goto fork_out;
1243
1244    ftrace_graph_init_task(p);
1245
1246    rt_mutex_init_task(p);
1247
1248#ifdef CONFIG_PROVE_LOCKING
1249    DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
1250    DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
1251#endif
1252    retval = -EAGAIN;
1253    if (atomic_read(&p->real_cred->user->processes) >=
1254            task_rlimit(p, RLIMIT_NPROC)) {
1255        if (p->real_cred->user != INIT_USER &&
1256            !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
1257            goto bad_fork_free;
1258    }
1259    current->flags &= ~PF_NPROC_EXCEEDED;
1260
1261    retval = copy_creds(p, clone_flags);
1262    if (retval < 0)
1263        goto bad_fork_free;
1264
1265    /*
1266     * If multiple threads are within copy_process(), then this check
1267     * triggers too late. This doesn't hurt, the check is only there
1268     * to stop root fork bombs.
1269     */
1270    retval = -EAGAIN;
1271    if (nr_threads >= max_threads)
1272        goto bad_fork_cleanup_count;
1273
1274    if (!try_module_get(task_thread_info(p)->exec_domain->module))
1275        goto bad_fork_cleanup_count;
1276
1277    delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
1278    p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
1279    p->flags |= PF_FORKNOEXEC;
1280    INIT_LIST_HEAD(&p->children);
1281    INIT_LIST_HEAD(&p->sibling);
1282    rcu_copy_process(p);
1283    p->vfork_done = NULL;
1284    spin_lock_init(&p->alloc_lock);
1285
1286    init_sigpending(&p->pending);
1287    //复制完后我们需要修改子进程p内部的一系列数据
1288    p->utime = p->stime = p->gtime = 0;
1289    p->utimescaled = p->stimescaled = 0;
1290#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
1291    p->prev_cputime.utime = p->prev_cputime.stime = 0;
1292#endif
1293#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
1294    seqlock_init(&p->vtime_seqlock);
1295    p->vtime_snap = 0;
1296    p->vtime_snap_whence = VTIME_SLEEPING;
1297#endif
1298
1299#if defined(SPLIT_RSS_COUNTING)
1300    memset(&p->rss_stat, 0, sizeof(p->rss_stat));
1301#endif
1302
1303    p->default_timer_slack_ns = current->timer_slack_ns;
1304
1305    task_io_accounting_init(&p->ioac);
1306    acct_clear_integrals(p);
1307
1308    posix_cpu_timers_init(p);
1309
1310    p->start_time = ktime_get_ns();
1311    p->real_start_time = ktime_get_boot_ns();
1312    p->io_context = NULL;
1313    p->audit_context = NULL;
1314    if (clone_flags & CLONE_THREAD)
1315        threadgroup_change_begin(current);
1316    cgroup_fork(p);
1317#ifdef CONFIG_NUMA
1318    p->mempolicy = mpol_dup(p->mempolicy);
1319    if (IS_ERR(p->mempolicy)) {
1320        retval = PTR_ERR(p->mempolicy);
1321        p->mempolicy = NULL;
1322        goto bad_fork_cleanup_threadgroup_lock;
1323    }
1324#endif
1325#ifdef CONFIG_CPUSETS
1326    p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
1327    p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
1328    seqcount_init(&p->mems_allowed_seq);
1329#endif
1330#ifdef CONFIG_TRACE_IRQFLAGS
1331    p->irq_events = 0;
1332    p->hardirqs_enabled = 0;
1333    p->hardirq_enable_ip = 0;
1334    p->hardirq_enable_event = 0;
1335    p->hardirq_disable_ip = _THIS_IP_;
1336    p->hardirq_disable_event = 0;
1337    p->softirqs_enabled = 1;
1338    p->softirq_enable_ip = _THIS_IP_;
1339    p->softirq_enable_event = 0;
1340    p->softirq_disable_ip = 0;
1341    p->softirq_disable_event = 0;
1342    p->hardirq_context = 0;
1343    p->softirq_context = 0;
1344#endif
1345#ifdef CONFIG_LOCKDEP
1346    p->lockdep_depth = 0; /* no locks held yet */
1347    p->curr_chain_key = 0;
1348    p->lockdep_recursion = 0;
1349#endif
1350
1351#ifdef CONFIG_DEBUG_MUTEXES
1352    p->blocked_on = NULL; /* not blocked yet */
1353#endif
1354#ifdef CONFIG_BCACHE
1355    p->sequential_io    = 0;
1356    p->sequential_io_avg    = 0;
1357#endif
1358
1359    /* Perform scheduler related setup. Assign this task to a CPU. */
1360    retval = sched_fork(clone_flags, p);
1361    if (retval)
1362        goto bad_fork_cleanup_policy;
1363
1364    retval = perf_event_init_task(p);
1365    if (retval)
1366        goto bad_fork_cleanup_policy;
1367    retval = audit_alloc(p);
1368    if (retval)
1369        goto bad_fork_cleanup_perf;
1370    /* copy all the process information */
1371    shm_init_task(p);
1372    retval = copy_semundo(clone_flags, p);
1373    if (retval)
1374        goto bad_fork_cleanup_audit;
1375    retval = copy_files(clone_flags, p);
1376    if (retval)
1377        goto bad_fork_cleanup_semundo;
1378    retval = copy_fs(clone_flags, p);
1379    if (retval)
1380        goto bad_fork_cleanup_files;
1381    retval = copy_sighand(clone_flags, p);
1382    if (retval)
1383        goto bad_fork_cleanup_fs;
1384    retval = copy_signal(clone_flags, p);
1385    if (retval)
1386        goto bad_fork_cleanup_sighand;
1387    retval = copy_mm(clone_flags, p);
1388    if (retval)
1389        goto bad_fork_cleanup_signal;
1390    retval = copy_namespaces(clone_flags, p);
1391    if (retval)
1392        goto bad_fork_cleanup_mm;
1393    retval = copy_io(clone_flags, p);
1394    if (retval)
1395        goto bad_fork_cleanup_namespaces;
1396    retval = copy_thread(clone_flags, stack_start, stack_size, p);//此过程复制了一些关键数据,下面介绍
1397    if (retval)
1398        goto bad_fork_cleanup_io;
1399
1400    if (pid != &init_struct_pid) {
1401        retval = -ENOMEM;
1402        pid = alloc_pid(p->nsproxy->pid_ns_for_children);
1403        if (!pid)
1404            goto bad_fork_cleanup_io;
1405    }
1406
1407    p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
1408    /*
1409     * Clear TID on mm_release()?
1410     */
1411    p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
1412#ifdef CONFIG_BLOCK
1413    p->plug = NULL;
1414#endif
1415#ifdef CONFIG_FUTEX
1416    p->robust_list = NULL;
1417#ifdef CONFIG_COMPAT
1418    p->compat_robust_list = NULL;
1419#endif
1420    INIT_LIST_HEAD(&p->pi_state_list);
1421    p->pi_state_cache = NULL;
1422#endif
1423    /*
1424     * sigaltstack should be cleared when sharing the same VM
1425     */
1426    if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)
1427        p->sas_ss_sp = p->sas_ss_size = 0;
1428
1429    /*
1430     * Syscall tracing and stepping should be turned off in the
1431     * child regardless of CLONE_PTRACE.
1432     */
1433    user_disable_single_step(p);
1434    clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
1435#ifdef TIF_SYSCALL_EMU
1436    clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
1437#endif
1438    clear_all_latency_tracing(p);
1439
1440    /* ok, now we should be set up.. */
1441    p->pid = pid_nr(pid);
1442    if (clone_flags & CLONE_THREAD) {
1443        p->exit_signal = -1;
1444        p->group_leader = current->group_leader;
1445        p->tgid = current->tgid;
1446    } else {
1447        if (clone_flags & CLONE_PARENT)
1448            p->exit_signal = current->group_leader->exit_signal;
1449        else
1450            p->exit_signal = (clone_flags & CSIGNAL);
1451        p->group_leader = p;
1452        p->tgid = p->pid;
1453    }
1454
1455    p->nr_dirtied = 0;
1456    p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10);
1457    p->dirty_paused_when = 0;
1458
1459    p->pdeath_signal = 0;
1460    INIT_LIST_HEAD(&p->thread_group);
1461    p->task_works = NULL;
1462
1463    /*
1464     * Make it visible to the rest of the system, but dont wake it up yet.
1465     * Need tasklist lock for parent etc handling!
1466     */
1467    write_lock_irq(&tasklist_lock);
1468
1469    /* CLONE_PARENT re-uses the old parent */
1470    if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {
1471        p->real_parent = current->real_parent;
1472        p->parent_exec_id = current->parent_exec_id;
1473    } else {
1474        p->real_parent = current;
1475        p->parent_exec_id = current->self_exec_id;
1476    }
1477
1478    spin_lock(&current->sighand->siglock);
1479
1480    /*
1481     * Copy seccomp details explicitly here, in case they were changed
1482     * before holding sighand lock.
1483     */
1484    copy_seccomp(p);
1485
1486    /*
1487     * Process group and session signals need to be delivered to just the
1488     * parent before the fork or both the parent and the child after the
1489     * fork. Restart if a signal comes in before we add the new process to
1490     * it's process group.
1491     * A fatal signal pending means that current will exit, so the new
1492     * thread can't slip out of an OOM kill (or normal SIGKILL).
1493    */
1494    recalc_sigpending();
1495    if (signal_pending(current)) {
1496        spin_unlock(&current->sighand->siglock);
1497        write_unlock_irq(&tasklist_lock);
1498        retval = -ERESTARTNOINTR;
1499        goto bad_fork_free_pid;
1500    }
1501
1502    if (likely(p->pid)) {
1503        ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
1504
1505        init_task_pid(p, PIDTYPE_PID, pid);
1506        if (thread_group_leader(p)) {
1507            init_task_pid(p, PIDTYPE_PGID, task_pgrp(current));
1508            init_task_pid(p, PIDTYPE_SID, task_session(current));
1509
1510            if (is_child_reaper(pid)) {
1511                ns_of_pid(pid)->child_reaper = p;
1512                p->signal->flags |= SIGNAL_UNKILLABLE;
1513            }
1514
1515            p->signal->leader_pid = pid;
1516            p->signal->tty = tty_kref_get(current->signal->tty);
1517            list_add_tail(&p->sibling, &p->real_parent->children);
1518            list_add_tail_rcu(&p->tasks, &init_task.tasks);
1519            attach_pid(p, PIDTYPE_PGID);
1520            attach_pid(p, PIDTYPE_SID);
1521            __this_cpu_inc(process_counts);
1522        } else {
1523            current->signal->nr_threads++;
1524            atomic_inc(&current->signal->live);
1525            atomic_inc(&current->signal->sigcnt);
1526            list_add_tail_rcu(&p->thread_group,
1527                      &p->group_leader->thread_group);
1528            list_add_tail_rcu(&p->thread_node,
1529                      &p->signal->thread_head);
1530        }
1531        attach_pid(p, PIDTYPE_PID);
1532        nr_threads++;
1533    }
1534
1535    total_forks++;
1536    spin_unlock(&current->sighand->siglock);
1537    syscall_tracepoint_update(p);
1538    write_unlock_irq(&tasklist_lock);
1539
1540    proc_fork_connector(p);
1541    cgroup_post_fork(p);
1542    if (clone_flags & CLONE_THREAD)
1543        threadgroup_change_end(current);
1544    perf_event_fork(p);
1545
1546    trace_task_newtask(p, clone_flags);
1547    uprobe_copy_process(p, clone_flags);
1548    //返回修改后的子进程
1549    return p;
1550
1551bad_fork_free_pid:
1552    if (pid != &init_struct_pid)
1553        free_pid(pid);
1554bad_fork_cleanup_io:
1555    if (p->io_context)
1556        exit_io_context(p);
1557bad_fork_cleanup_namespaces:
1558    exit_task_namespaces(p);
1559bad_fork_cleanup_mm:
1560    if (p->mm)
1561        mmput(p->mm);
1562bad_fork_cleanup_signal:
1563    if (!(clone_flags & CLONE_THREAD))
1564        free_signal_struct(p->signal);
1565bad_fork_cleanup_sighand:
1566    __cleanup_sighand(p->sighand);
1567bad_fork_cleanup_fs:
1568    exit_fs(p); /* blocking */
1569bad_fork_cleanup_files:
1570    exit_files(p); /* blocking */
1571bad_fork_cleanup_semundo:
1572    exit_sem(p);
1573bad_fork_cleanup_audit:
1574    audit_free(p);
1575bad_fork_cleanup_perf:
1576    perf_event_free_task(p);
1577bad_fork_cleanup_policy:
1578#ifdef CONFIG_NUMA
1579    mpol_put(p->mempolicy);
1580bad_fork_cleanup_threadgroup_lock:
1581#endif
1582    if (clone_flags & CLONE_THREAD)
1583        threadgroup_change_end(current);
1584    delayacct_tsk_free(p);
1585    module_put(task_thread_info(p)->exec_domain->module);
1586bad_fork_cleanup_count:
1587    atomic_dec(&p->cred->user->processes);
1588    exit_creds(p);
1589bad_fork_free:
1590    free_task(p);
1591fork_out:
1592    return ERR_PTR(retval);
1593}

dup_task_struct的具体实现如下:

305static struct task_struct *dup_task_struct(struct task_struct *orig)
306{
307 struct task_struct *tsk;
308 struct thread_info *ti;
309 int node = tsk_fork_get_node(orig);
310 int err;
311
312 tsk = alloc_task_struct_node(node);//分配一个task_struct
313 if (!tsk)
314     return NULL;
315
316 ti = alloc_thread_info_node(tsk, node);//分配堆栈空间
317 if (!ti)
318     goto free_tsk;
319
320 err = arch_dup_task_struct(tsk, orig);//从orig复制task_struct至tsk
321 if (err)
322     goto free_ti;
323
324 tsk->stack = ti;//tsk的堆栈指向ti
325#ifdef CONFIG_SECCOMP
326 /*
327  * We must handle setting up seccomp filters once we're under
328  * the sighand lock in case orig has changed between now and
329  * then. Until then, filter must be NULL to avoid messing up
330  * the usage counts on the error path calling free_task.
331  */
332 tsk->seccomp.filter = NULL;
333#endif
334
335 setup_thread_stack(tsk, orig);//复制堆栈内容
336 clear_user_return_notifier(tsk);
337 clear_tsk_need_resched(tsk);
338 set_task_stack_end_magic(tsk);
339
340#ifdef CONFIG_CC_STACKPROTECTOR
341 tsk->stack_canary = get_random_int();
342#endif
343
344 /*
345  * One for us, one for whoever does the "release_task()" (usually
346  * parent)
347  */
348 atomic_set(&tsk->usage, 2);
349#ifdef CONFIG_BLK_DEV_IO_TRACE
350 tsk->btrace_seq = 0;
351#endif
352 tsk->splice_pipe = NULL;
353 tsk->task_frag.page = NULL;
354
355 account_kernel_stack(ti, 1);
356
357 return tsk;
358
359free_ti:
360 free_thread_info(ti);
361free_tsk:
362 free_task_struct(tsk);
363 return NULL;
364}

arch_dup_task_struct的实现如下:

290int __weak arch_dup_task_struct(struct task_struct *dst,
291                        struct task_struct *src)
292{
293 *dst = *src;  //实际上就是把src的内容复制到dst
294 return 0;
295}

copy_thread定义在linux-3.18.6/arch/x86/kernel/process_32.c 中:

132int copy_thread(unsigned long clone_flags, unsigned long sp,
133 unsigned long arg, struct task_struct *p)
134{
135 struct pt_regs *childregs = task_pt_regs(p);//栈顶地址
136 struct task_struct *tsk;
137 int err;
138
139 p->thread.sp = (unsigned long) childregs;//栈顶地址赋给sp
140 p->thread.sp0 = (unsigned long) (childregs+1);
141 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
142
143 if (unlikely(p->flags & PF_KTHREAD)) {
144     /* kernel thread */
145     memset(childregs, 0, sizeof(struct pt_regs));
146     p->thread.ip = (unsigned long) ret_from_kernel_thread;
147     task_user_gs(p) = __KERNEL_STACK_CANARY;
148     childregs->ds = __USER_DS;
149     childregs->es = __USER_DS;
150     childregs->fs = __KERNEL_PERCPU;
151     childregs->bx = sp; /* function */
152     childregs->bp = arg;
153     childregs->orig_ax = -1;
154     childregs->cs = __KERNEL_CS | get_kernel_rpl();
155     childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
156     p->thread.io_bitmap_ptr = NULL;
157     return 0;
158 }
159 *childregs = *current_pt_regs();//父进程的栈内容复制给子进程
160 childregs->ax = 0;//子进程返回值为0
161 if (sp)
162     childregs->sp = sp;
163
164 p->thread.ip = (unsigned long) ret_from_fork;//子进程的运行入口
165 task_user_gs(p) = get_user_gs(current_pt_regs());
166
167 p->thread.io_bitmap_ptr = NULL;
168 tsk = current;
169 err = -ENOMEM;
170
171 if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
172     p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
173                     IO_BITMAP_BYTES, GFP_KERNEL);
174     if (!p->thread.io_bitmap_ptr) {
175         p->thread.io_bitmap_max = 0;
176         return -ENOMEM;
177     }
178     set_tsk_thread_flag(p, TIF_IO_BITMAP);
179 }
180
181 err = 0;
182
183 /*
184  * Set a new TLS for the child thread?
185  */
186 if (clone_flags & CLONE_SETTLS)
187     err = do_set_thread_area(p, -1,
188         (struct user_desc __user *)childregs->si, 0);
189
190 if (err && p->thread.io_bitmap_ptr) {
191     kfree(p->thread.io_bitmap_ptr);
192     p->thread.io_bitmap_max = 0;
193 }
194 return err;
195}

struct pt_regs定义在linux-3.18.6/arch/x86/include/uapi/asm/ptrace.h

17struct pt_regs {
18  long ebx;
19  long ecx;
20  long edx;
21  long esi;
22  long edi;
23  long ebp;
24  long eax;
25  int  xds;
26  int  xes;
27  int  xfs;
28  int  xgs;
29  long orig_eax;
30  long eip;
31  int  xcs;
32  long eflags;
33  long esp;
34  int  xss;
35};
36

二、使用GDB跟踪fork调用
根据上面的分析,我们分别在sys_clone、do_fork、copy_process、copy_thread、ret_from_fork处设置断点(实验为前几篇文章用到的menu系统)

使用fork调用后,执行到sys_clone处:

接着执行到do_fork处:

copy_process:

copy_thread:

ret_from_fork:

发现最终只能追踪到syscall_exit处:

三、总结
linux创建一个新的进程是从复制父进程内核栈、页表项开始的,在系统内核里首先是将父进程的进程描述符进行拷贝,然后再根据自己的情况修改相应的参数,获取自己的进程号,再开始执行。

6、分析Linux内核创建一个新进程的过程相关推荐

  1. 实验六:分析Linux内核创建一个新进程的过程

    20135108 李泽源 阅读理解task_struct数据结构http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h ...

  2. linux内核创建用户,分析Linux内核创建一个新进程的过程

    谢文杰 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验目的 阅 ...

  3. linux搭建一个的过程,Linux内核创建一个新进程的过程

    此文仅用于MOOCLinux内核分析作业 task_struct数据结构 根据wiki的定义,进程是计算机中已运行程序的实体.在面向线程设计的系统(Linux 2.6及更新的版本)中,进程本身不是基本 ...

  4. Linux内核创建一个新进程的过程

    作者:王鹤楼 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 操作系统的三大功 ...

  5. 6. Linux内核创建一个新进程的过程分析

    ##################################### 作者:张卓 原创作品转载请注明出处:<Linux操作系统分析>MOOC课程 http://www.xuetang ...

  6. Linux内核协议栈-一个socket的调用过程,从用户态接口到底层硬件

    用户创建socket 调用内核__sock_create int __sock_create(struct net *net, int family, int type, int protocol,s ...

  7. linux内核启动分析 三,Linux内核分析 实验三:跟踪分析Linux内核的启动过程

    贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...

  8. 《深入理解Linux内核》-3.3. 进程切换

    3.3. 进程切换 为了控制进程的执行,内核必须能够挂起正在运行的进程并恢复运行其他之前被挂起的进程.这个活动通过进程切换,任务切换或上下文切换执行这种各样的操作.接下来的章节介绍Linux系统上的进 ...

  9. linux内核调度 0号进程,Linux内核源代码情景分析---第四章 进程与进程调度

    4.1 进程四要素 什么是进程? 1:有一段代码段供其执行,这代码段不一定是进程所专用,可以与其他进程公用. 2:每个进程有其专用的系统空间的堆栈(栈)[这个栈是进程起码的"私有财产&quo ...

最新文章

  1. 3D MinkowskiEngine稀疏模式重建
  2. Bootstrap4 更新笔记
  3. 安全获取QueryString的值类库下载
  4. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(配置显示均值、中位数)实战
  5. HTTP方法:幂等性和安全性
  6. html 微博下拉菜单,jQuery实现模仿微博下拉滚动条加载数据效果
  7. 360浏览器 ajax取缓存,web开发遇到的坑之360浏览器缓存问题
  8. 【LeetCode】【HOT】234. 回文链表(存入数组)
  9. 微课|中学生可以这样学Python(2.1.2节):常量与变量
  10. python判断正负零_【译】格式字符串语法
  11. 一个事务复制的bug--更新丢失 续
  12. 免费证件照制作的软件有哪些?来看看这几个好用的软件
  13. 搜索中的深度匹配模型
  14. centos安装unrar并使用
  15. 4、Gantt 任务节点部分
  16. springcloud分布式配置中心(二)-阿波罗apollo
  17. 苹果即将量产microLED,将迫使三星等加快该项技术的进展
  18. 自动化构建工具Grunt、Gulp
  19. win10网页找不到服务器dns,教你win10打开网页提示无法解析服务器dns地址的解决教程。...
  20. U-Boot 图形化配置

热门文章

  1. 【华为OD机试真题 python】最优资源分配【2023 Q1 | 100分】
  2. OpenCV笔记—进阶篇(图像效果处理)
  3. mysqldump 忽略视图_mysqldump 使用说明
  4. vue3 中使用图片播放器
  5. [GDG CTF 2022] 几个小题,等WP
  6. Cling基础教程 - 用户手册(入门)
  7. Java多线程分批处理数据
  8. 合数双线性群(Composite Order Bilinear Groups)
  9. 【转】各大公司样片申请指南
  10. 董事会、董事长、CEO,听上去很美