zoukankan      html  css  js  c++  java
  • 2019-2020-1 20199313《Linux内核原理与分析》第九周作业

    第九周学习——“进程的描述与进程的创建”

    • 问题描述:

      • 经过上一阶段的学习,我们逐渐了解了计算机操作系统的核心工作机制,构造了一个简单的Linux系统MenuOS,利用了GDB简单分析Start_kernel,我们还学习了使用系统的库函数,并在此基础上,学会了使用系统调用,使用gdb调试系统调用,并观察并观察fork函数是如何工作的函数是如何工作的,进一步学习了译链接的过程和ELF可执行文件格式。
    • 本周学习:

      • 本周在上周学习的基础上继续使用使用gdb调试系统调用,调试断点,分析系统调用运行过程。
      • 对Linux内核装载和启动一个可执行程序
        • 学习跟踪schedule,pick_next_task和context_switch等函数。

    一、理论阐述

    进程调度的时机

    中断处理过程中,直接调用schedule()
    内核线程可以直接调用schedule()进行进程切换

    • schedule是一个内核函数,不是一个系统调用,进程的调度只发生在内核中,进程调度函数schedule()只能在内核中被调用,用户进程无法调用, 因此,进程切换需要用到实现用户态到内核态的切换。
    • 中断处理过程直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule()。内核线程是一个特殊的进程,只有内核态没有用户态,可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度。

    进程上下文切换

    1、进程切换(或称任务切换、上下文切换):为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行。
    2、挂起正在CPU上执行的进程,与中断时保存现场不同。中断前后是在同一个进程上下文中,只是由用户态转向内核态执行。进程上下文包含了进程执行需要的所有信息:

    • 用户地址空间:包括程序代码,数据,用户堆栈等
    • 控制信息:进程描述符,内核堆栈等
    • 硬件上下文

    二分析代码

    • schedule的代码如下:


        asmlinkage__visible void __sched schedule(void)
        {
        struct task_struct *tsk = current;
             sched_submit_work(tsk);  
             __schedule();  
        }
        static void __sched __schedule(void)
        {
        struct task_struct prev, next;
        unsigned long switch_count;
        struct rq rq;
        int cpu;
        need_resched:
        preempt_disable();
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
        rcu_note_context_switch(cpu);
            prev = rq->curr;
            schedule_debug(prev);
        if (sched_feat(HRTICK))
        hrtick_clear(rq);
        /*
        Make sure that signal_pending_state()->signal_pending() below
            can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
        done by the caller to avoid the race with signal_wake_up().
        */
        smp_mb__before_spinlock();
        raw_spin_lock_irq(&rq->lock);
        switch_count = &prev->nivcsw;
        if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
        if (unlikely(signal_pending_state(prev->state, prev))) {
        prev->state = TASK_RUNNING;
        } else {
        deactivate_task(rq, prev, DEQUEUE_SLEEP);
        prev->on_rq = 0;
        /*
        If a worker went to sleep, notify and ask workqueue
        whether it wants to wake up a task to maintain
        concurrency.
        */
          if (prev->flags & PF_WQ_WORKER) {
        struct task_struct *to_wakeup;
        to_wakeup = wq_worker_sleeping(prev, cpu);
        if (to_wakeup)
        try_to_wake_up_local(to_wakeup);
        }
        }
        switch_count = &prev->nvcsw;
        }
        if (task_on_rq_queued(prev) || rq->skip_clock_update < 0)
        update_rq_clock(rq);
        next = pick_next_task(rq, prev);
        clear_tsk_need_resched(prev);
        clear_preempt_need_resched();
        rq->skip_clock_update = 0;
        if (likely(prev != next)) {
        rq->nr_switches++;
        rq->curr = next;
        ++*switch_count;
        context_switch(rq, prev, next); /* unlocks the rq */
        /*
         * The context switch have flipped the stack from under us
         * and restored the local variables which were saved when
         * this task called schedule() in the past. prev == current
         * is still correct, but it can be moved to another cpu/rq.
         */
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
        } else
        raw_spin_unlock_irq(&rq->lock);
        post_schedule(rq);
        sched_preempt_enable_no_resched();
        if (need_resched())
        goto need_resched;
        }
    
    


    next = pick_next_task(rq, prev),封装了进程调度算法,使用某种进程调度策略选择下一个进程。
    之后用context_switch(rq, prev, next),实现进程上下文的切换。
    然后switch_to(prev,next, prev),切换堆栈和寄存器的状态。

    Linux运行的几种特殊情况:

    ①通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
    ②内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,比最一般的情况略简略;
    ③创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork一个子进程时;
    ④加载一个新的可执行程序后返回到用户态的情况,如execve系统调用加载新的可执行程序;

    三、实验

  • 相关阅读:
    HDU 4069 Squiggly Sudoku
    SPOJ 1771 Yet Another NQueen Problem
    POJ 3469 Dual Core CPU
    CF 118E Bertown roads
    URAL 1664 Pipeline Transportation
    POJ 3076 Sudoku
    UVA 10330 Power Transmission
    HDU 1426 Sudoku Killer
    POJ 3074 Sudoku
    HDU 3315 My Brute
  • 原文地址:https://www.cnblogs.com/dhr9313/p/11878566.html
Copyright © 2011-2022 走看看