15. 태스크 개념을 추가해 멀티태스킹을 구현하자

들어가기

멀티태스킹 기능을 구현하면서 멀티태스킹이 무엇인지 알고 함수를 작성하자.

본론

15.1 태스크, 멀티태스킹, 성능 향상

15.1.1 태스크, 콘텍스트, 스택

  • 태스크마다 개별적인 콘텍스트만 보장한다면 여러 개의 태스크를 동시에 실행해도 서로 간섭 없이 처리.
  • 독립적인 콘텍스트를 보장한다 해도 스택이 구분되지 않으면 다른 태스크로 인해 스택의 내용이 변경되어 문제가 발생.
  • 태스크에 의존적이지 않은 코드나 데이터는 쓰임에 따라 공유 가능.

15.1.2 멀티태스킹과 성능 향상

  • 하나의 코어는 여러 개의 태스크를 동시에 실행할 수 없으므로 특정 시점에서 실행되는 태스크는 코어당 하나지만, 아주 짧은 주기마다 태스크를 전환.
  • 멀티태스킹을 사용하는 가장 큰 두 가지 이유.
    • 응답 시간이 빨라짐.
    • CPU bound, I/O bound를 구분하여 CPU의 처리량을 극대화 할 수 있음.

15.2 태스크 제어 블록과 태스크 전환 구현

15.2.1 태스크 제어 블록 정의

 typedef struct kTaskControlBlockStruct {
    CONTEXT stContext;

    QWORD qwID;
    QWORD qwFlags;

    void* pvStackAddress;
    QWORD qwStackSize;
}
  • 인터럽트나 예외가 발생했을 때와 같은 순서로 콘텍스트 자료구조에 저장, 같은 순서로 저장하면 인터럽트나 예외 처리에 사용됐던 콘텍스트 저장과 복원 코드를 그대로 태스크 전환.
  • 15.3 코드 참조.

15.2.2 태스크 생성 처리

void kSetUpTask(TCB* pstTCB, QWORD qwID, QWORD qwFlags, QWORD qwEntryPointAddress, void* pvStackAddress, QWORD qwStackSize) {

    kMemSet(pstTCB -> stContext.vqRegister, 0, sizeof(pstTCB -> stContext.vqRegister));

    // TCB 영역을 위한 스택 초기화
    pstTCB -> stContext.vqRegister[TASK_RSPOFFSET] = (QWORD) pvStackAddress + qwStackSize;
    pstTCB -> stContext.vqRegister[TASK_RBPOFFSET] = (QWORD) pvStackAddress + qwStackSize;

    pstTCB -> stContext.vqRegister[TASK_CSOFFSET] = GDT_KERNELCODESEGMENT;
    pstTCB -> stContext.vqRegister[TASK_DSOFFSET] = GDT_KERNELDATASEGMENT;
    pstTCB -> stContext.vqRegister[TASK_ESOFFSET] = GDT_KERNELDATASEGMENT;
    pstTCB -> stContext.vqRegister[TASK_FSOFFSET] = GDT_KERNELDATASEGMENT;
    pstTCB -> stContext.vqRegister[TASK_GSOFFSET] = GDT_KERNELDATASEGMENT;
    pstTCB -> stContext.vqRegister[TASK_SSOFFSET] = GDT_KERNELDATASEGMENT;

    pstTCB -> stContext.vqRegister[TASK_RIPOFFSET] = qwEntryPointAddress;

    pstTCB -> stContext.vqRegister[TASK_RFLAGSOFFSET] |= 0x0200;

    pstTCB -> qwID = qwID;
    pstTCB -> pvStackAddress = pvStackAddress;
    pstTCB -> qwStackSize = qwStackSize;
    pstTCB -> qwFlags = qwFlags;
}
  • RSP와 RBP 레지스터는 스택의 TOP을 나타냄으로 태스크가 생성되었을때 스택은 비어있는 상태, 초기화 필요.
  • RIP는 해당 태스크로 전환했을 때 실행을 시작하는 코드의 어드레스.

15.2.3 태스크 전환 처리

  • 프로세서에서 자동으로 저장하는 SS, RSP, RFLAGS, CS, RIP를 주의해서 저장.
  • SS, RFLAGS, CS 레지스터는 현재 프로세서에 저장된 값을 그대로 저장.
  • 15.3 코드 참조.

15.3 멀티태스킹 기능 통합과 빌드

15.3.1 태스크 파일 추가

15.3.2 어셈블리어 유틸리티 파일 수정

15.3.3 콘솔 셸 파일 수정

15.3.4 빌드와 실행

마치며

끝..

Share