2019-2020-1 20199316 작업의 아홉 번째 주에 "리눅스 커널 원리 및 분석"

스위칭 시스템 및 프로세스의 과정의 일반 구현

교과서의 첫째, 내용

  • 일정 시간의 과정 실시
    • 스케줄 기능에 의해 리눅스 커널 구현 프로세스 스케줄링, 스케줄 기능은 실행 큐에서 CPU가 할당 프로세스를 찾을 수
    • 함수가 호출 일정 기능을 예약되어 예약 전화, 그것은 일정 시간의 과정이다
    • 커널이 사용자 공간에 복귀하려고 할 때, 커널 확인합니다 need_resched 플래그는, 설정 한 경우, 통화 예약 기능을 설정하고,이 시점에 인터럽트 핸들러에서 예약 기회의 고정 된 지점으로 공간에 대한 사용자 반환했다입니다
    • 커널 스레드가 특별한 과정뿐만 아니라 커널 모드 사용자 모드, 커널 스레드와 인터럽트 핸들러 위치의 실행 경로의 임시 정지를 필요로 할 수있는 직접 호출 일정 ()
    • 프로세스의 특별한 커널 스레드로도 수동 예약을 할 수 있으며, 수업 일정 기능은 CPU를 허용 전화 주도권을 쥐고 있습니다
  • 문맥
    • 또한 프로세스 실행을 제어하기위한 컨텍스트 스위치 수단으로 알려진 프로세스 스위치, 커널은 이전에 실행 프로세스를 중단 재개, CPU에서 실행되는 과정을 중지 할 수 있어야합니다
    • 커널 스레드는 커널 공간에서 프로세스 컨텍스트의 형태로 실행
    • 자신의 주소 공간을 가질 수 있습니다 각 프로세스의 가치,하지만 CPU와 모든 프로세스가 레지스터를 공유해야 할 때, 그래서 프로세스 실행을 다시 시작하기 전에, 커널은 각 레지스터가 일시 중단 된 프로세스에로드되어 있는지 확인해야합니다
    • 데이터 세트를 수행하기 전에 복구 프로세스는 레지스터에로드 하드웨어 컨텍스트 호출되어야
    • 프로세스 문맥은 프로세스 실행에 필요한 모든 정보가 들어 있습니다
      • 사용자 주소 공간 : 사용자 스택에 이렇게 프로그램 코드, 데이터 및 포함
      • 정보 제어 : 공정 기술자, 커널 스택 등
      • 하드웨어 컨텍스트 관련 레지스터의 값
    • 프로세스는 코어가 저장된 여러 키 레지스터를 변환하고, 이상의 가변 프로세스 컨텍스트 스위치로
      • CR3 레지스터는 프로세스 페이지 디렉토리 테이블, 그 주소 공간 데이터를 나타냅니다
      • ESP 레지스터 (커널 모드) 프로세스 커널 스택 구조체 스레드 PCB이고, 8킬로바이트가 연속 영역에 저장된 커널 스택, ESP는 IP 어드레스를 획득
      • EIP 레지스터 및 다른 처리 하드웨어 컨텍스트를 대신하여 등록, 다음 명령이 실행되고, 환경 될
      • 이러한 레지스터는 다른 프로세스의 상태로 한 프로세스의 상태로 전환되고, 전환 프로세스는 심지어 완성
    • 실제 코드는, 전환 과정의 각은 실질적으로 두 단계로 이루어
      • 가상 주소 다른 다른 물리적 주소로 여러 페이지 테이블을 통해 이동합니다 0x8048400과 같은 처리 할 수 ​​있도록 전역 디렉토리 CR3 스위치 페이지, 새 주소 공간을 설치
      • 커널 모드 및 하드웨어 컨텍스트는 새로운 커널 실행을 처리하기 위해 필요한 모든 정보를 제공하기 때문에, 하드웨어 컨텍스트 스위칭 스택은, 상태 레지스터는 CPU를 포함
  • 스위칭 (사용자 모드 프로세스 Y의 실행 프로세스 스위칭 X 사용자 모드 처리)하는 과정
    • 사용자 모드가 실행 X를 처리
    • 중단 (등 예외, 시스템 호출 포함), 하드웨어는 다음과 같은 조치를 완료
      • 저장 CS : EIP / SS는 : ESP / EFLAGS은 : 현재 컨텍스트 CPU 사용자 모드 프로세스 X로 밀어 커널 스택
      • CS를로드 : EIP (특정의 ISR의 항목) 및 SS를 : ESP (커널 스택 점) : 부하 전류 프로세스 커널 스택 정보, 실행 경로의 시작을 중단 인터럽트 핸들러로 점프
    • 공정 X는 X된다 SAVE_ALL은 장면을 보존, 이는 사용자 모드와 커널 모드 프로세스에 대한 인터럽트 문맥 전환, 즉을 완료
    • 키 프로세스 컨텍스트 스위치를 제작 switch_to 반환하기 전에 인터럽트 처리 또는 통화 일정 기능 인터럽트. 현재 사용자 프로세스 X 커널 스택 다음 스위칭 처리 선택 (여기서, 프로세스 Y) 커널 스택, 프로세스 콘텍스트를 완료까지
    • EIP 레지스터 상태처럼 전환하는 데 필요한
    • 런들 후 (\ t 즉, 코드 1의) 사용자 모드 프로세스 번호 1 Y
    • restore_all, 사이트 복원하고, 해당 장면의 보존
    • IRET - CS 팝업 : EIP / SS를 : ESP / EFLAGS는 하드웨어에서 팝업 푸시 내용이 프로세스의 커널 스택 Y.를 완료 이것은 인터럽트 컨텍스트 전환, Y Y 사용자 모드 처리 커널 모드로부터의 복귀 즉 프로세스를 완료
    • 사용자 모드 프로세스 Y를 계속 실행
  • 운영 체제 커널
    • 리눅스 운영 체제 커널 컨텍스트 스위칭 및 프로세스 컨텍스트는 가장 기본적이고 중요한 서비스를 사용자에게 제공하기 위해 다음과 같은 기본 운영 메커니즘을 전환 인터럽트를 통해 리눅스 운영 체제 커널을 보호 할 수 있습니다. 으로는 다음과 같습니다 :
      • 시스템 호출의 형태로 프로세스에 대한 다양한 서비스를 제공
      • 하드웨어의 정상적인 작동에 대한 예외 핸들러 인터럽트 서비스 루틴을 통해 다양한 서비스를 제공한다
      • 커널 스레드와 인터럽트 서비스 작업에 의한 동적 시스템에 대한 유지 보수 서비스를 제공하는 것은 처리가 지연 될 수 있습니다
    • 부분 (커널 모드) 각 논리 비록 더 3기가바이트 볼 모든 프로세스의 일부 콘텐츠 어드레스보다 정확하게보다 더 3기가바이트 모든 프로세스 주소 공간 x86-32 비트 시스템과 동일한 지, 공유 프로세스의 어드레스 공간은 독립적

둘째, 실험 과정

실험실 건물, 구성 menuOS 사용 :

매크로 정의 switch_to입니다 열기 GDB, 세트 중단 점을, 중단 점을 설정할 수 없습니다, 당신은 context_switch 단계 실행 함수 호출에 필요한 :


C 실행 절차, 절차는 일정 기능에 중지 된, pick_next_task 기능 해제 점에서 context_switch

셋째, 코드 분석

  • context_switch 기능 부

static inline void context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
{
    struct mm_struct *mm, *oldmm;

    prepare_task_switch(rq, prev, next);

    mm = next->mm;
    oldmm = prev->active_mm;
    /*
     * For paravirt, this is coupled with an exit in switch_to to
     * combine the page table reload and the switch backend into
     * one hypercall.
     */
    arch_start_context_switch(prev);

    if (!mm) {    //如果被切换进来的进程的mm为空切换,内核线程mm为空
        next->active_mm = oldmm;  //将共享切换出去的进程的active_mm
        atomic_inc(&oldmm->mm_count);  //有一个进程共享,所有引用计数加一
        enter_lazy_tlb(oldmm, next);  //普通mm不为空,则调用switch_mm切换地址空间
    } else
        switch_mm(oldmm, mm, next);

    if (!prev->mm) {
        prev->active_mm = NULL;
        rq->prev_mm = oldmm;
    }
    /*
     * Since the runqueue lock will be released by the next
     * task (which is an invalid locking op but in the case
     * of the scheduler it's an obvious special-case), so we
     * do an early lockdep release here:
     */
    spin_release(&rq->lock.dep_map, 1, _THIS_IP_);

    context_tracking_task_switch(prev, next);
    // Here we just switch the register state and the stack.切换寄存器状态和栈 
    switch_to(prev, next, prev);

    barrier();
    /*
     * this_rq must be evaluated again because prev may have moved
     * CPUs since it called schedule(), thus the 'rq' on its stack
     * frame will be invalid.
     */
    finish_task_switch(this_rq(), prev);
}

일정 기능을 실행하고 통화 context_switch 컨텍스트 스위칭 기능하는 새로운 프로세스를 선택합니다

  • switch_to 기능 부

#define switch_to(prev, next, last)
do {
    /*
     * Context-switching clobbers all registers, so we clobber
     * them explicitly, via unused output variables.
     * (EAX and EBP is not listed because EBP is saved/restored
     * explicitly for wchan access and EAX is the return value of
     * __switch_to())
     */
    unsigned long ebx, ecx, edx, esi, edi;

    asm volatile(
                     "pushfl\n\t"        // 保存当前进程flags
             "pushl %%ebp\n\t"      // 当前进程堆栈基址压栈
             "movl %%esp,%[prev_sp]\n\t"    // 保存ESP,将当前堆栈栈顶保存起来
             "movl %[next_sp],%%esp\n\t"    // 更新ESP,将下一栈顶保存到ESP中
                     // 完成内核堆栈的切换
             "movl $1f,%[prev_ip]\n\t"       // 保存当前进程的EIP
             "pushl %[next_ip]\n\t"       // 将next进程起点压入堆栈,即next进程的栈顶为起点,next_ip一般为$1f,对于新创建的子进程是ret_from_fork
             __switch_canary                    
             "jmp __switch_to\n"    // prve进程中,设置next进程堆栈,jmp与call不同,是通过寄存器传递参数(call通过堆栈),所以ret时弹出的是之前压入栈顶的next进程起点
                     // 完成EIP的切换
             "1:\t"             // next进程开始执行       
             "popl %%ebp\n\t"       // restore EBP
             "popfl\n"          // restore flags

             // 输出量
             : [prev_sp] "=m" (prev->thread.sp),   // 保存当前进程的esp
               [prev_ip] "=m" (prev->thread.ip),     // 保存当前进仓的eip
               "=a" (last),

               // 要破坏的寄存器
               "=b" (ebx), "=c" (ecx), "=d" (edx),
               "=S" (esi), "=D" (edi)

               __switch_canary_oparam

              // 输入量
             : [next_sp]  "m" (next->thread.sp),   // next进程的内核堆栈栈顶地址,即esp
               [next_ip]  "m" (next->thread.ip),     // next进程的eip

               // regparm parameters for __switch_to(): 
               [prev]     "a" (prev),
               [next]     "d" (next)

               __switch_canary_iparam

             : // 重新加载段寄存器
            "memory");
} while (0)

하드웨어 컨텍스트 스위칭 switch_to 매크로 호출 주로 인라인 어셈블리 코드 context_switch

IV 요약

우리는 매크로 pick_next_task () 함수는 프로세스 스케줄링 알고리즘을 캡슐화하는 것을 특징으로 컨텍스트 스위치에 switch_to () 키를 호출, 컨텍스트 스위칭을위한 기능이 실행에 새로운 프로세스를 선택하는 데 사용됩니다 실험적 일정 ()를 발견하고, context_switch 호출 (). need_resched 호출 일정 ()에있어서, 상기 직접 호출 스케줄 (), 또는 사용자 모드로 복귀 (클록 인터럽트, I / O 인터럽트, 시스템 콜 및 예외를 포함), 인터럽트 처리를 마킹, 커널 스레드 ()는 스위칭 프로세스의 직접 예약을 호출 할 또한 클래스 발의 프로세스 스케줄링을 수있는 특별한 커널 스레드를 말을하는 것입니다 인터럽트 처리 일정에서 수행 할 수 있습니다, 일정이 수동적이 될 수 있으며, 사용자 모드 프로세스가 활성 일정을 달성 할 수없는, 그것은 단지 커널 모드 중 하나에 의해 체포 될 수있다 인터럽트 처리 예정된 시점을 스케쥴링.

추천

출처www.cnblogs.com/destiny-love/p/11876815.html