KVMALLOC()


 리눅스 커널 코드에서 메모리 할당에 관련된 패턴중 필요에 의해 만들어진 핼퍼 함수 이다. 이 함수는 아래와 같은 패턴의 메모리 할당에 대해 교체 지원한다.


memory = kmalloc(allocation_size, GFP_KERNEL);
    if (!memory)
        memory = vmalloc(allocation_size);


kvmalloc() 은 내부적으로 kmalloc() 호출을 시도한다. 이는 slab allocator 를 이용한 메모리 압박이 없다면 빠른 메모리 할당을 지원한다. 또한 slab 은 PAGE_SIZE(32비트에서는 4KB) 보다 작은 메모리 할당을 위해 사용하고, 그보다 큰경우에는 물리적으로 연속적인 메모리를 할당하려고 한다. 하지만, 시스템을 운영하다 보면, 할당할 수 있는 메모리 공간은 있지만, 단편화로 인해 물리적으로 연속적인 공간은 할당 받지 못하는 경우가 있다. 물론, 연속적인 공간 확보를 위한 compaction 등의 feature 로 노력은 하지만 연속적인 공간 요청이 크다면 힘들 수도 있다.


 이런 경우 가상주소 공간에서 연속적인 메모리 할당을 vmalloc() 으로 가능하게 한다. vmalloc() 은 가상 주소 공간에서 연속적이지만, 실제 물리적으로는 흩어진 메모리를 관리한다. 이런 할당은 페이지 테이블의 수정이 생기고, TLB cache 의 invalidation 을 갖게 된다.(페이지 폴트) 또한 PAGE_SIZE 보다 작은 메모리 할당은 align 되어 PAGE_SIZE  만큼 할당할 것이다.


 이제 kvmalloc() 내부를 보자.


/**
 * kvmalloc_node - attempt to allocate physically contiguous memory, but upon
 * failure, fall back to non-contiguous (vmalloc) allocation.
 * @size: size of the request.
 * @flags: gfp mask for the allocation - must be compatible (superset) with GFP_KERNEL.
 * @node: numa node to allocate from
 *
 * Uses kmalloc to get the memory but if the allocation fails then falls back
 * to the vmalloc allocator. Use kvfree for freeing the memory.
 *
 * Reclaim modifiers - __GFP_NORETRY and __GFP_NOFAIL are not supported. __GFP_REPEAT
 * is supported only for large (>32kB) allocations, and it should be used only if
 * kmalloc is preferable to the vmalloc fallback, due to visible performance drawbacks.
 *
 * Any use of gfp flags outside of GFP_KERNEL should be consulted with mm people.
 */
void *kvmalloc_node(size_t size, gfp_t flags, int node)
{
    gfp_t kmalloc_flags = flags;
    void *ret;

    /*
     * vmalloc uses GFP_KERNEL for some internal allocations (e.g page tables)
     * so the given set of flags has to be compatible.
     */
    WARN_ON_ONCE((flags & GFP_KERNEL) != GFP_KERNEL);

    /*
     * Make sure that larger requests are not too disruptive - no OOM
     * killer and no allocation failure warnings as we have a fallback
     */
    if (size > PAGE_SIZE) {
        kmalloc_flags |= __GFP_NOWARN;

        /*
         * We have to override __GFP_REPEAT by __GFP_NORETRY for !costly
         * requests because there is no other way to tell the allocator
         * that we want to fail rather than retry endlessly.
         */
        if (!(kmalloc_flags & __GFP_REPEAT) ||
                (size <= PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
            kmalloc_flags |= __GFP_NORETRY;
    }

    ret = kmalloc_node(size, kmalloc_flags, node);

    /*
     * It doesn't really make sense to fallback to vmalloc for sub page
     * requests
     */
    if (ret || size <= PAGE_SIZE)
        return ret;

    return __vmalloc_node_flags(size, node, flags);
}
EXPORT_SYMBOL(kvmalloc_node);

간단히, 메모리 할당이 8 개 페이지 크기보다 같거나 작다면, vmalloc() 은 쓰지 않을 것이다. 그냥 될때까지(oom killer 도 돌고 요청완료할 때까지) 진행을 하고, 그 크기보다 클때는 vmalloc() 으로 메모리 할당을 대체 하겠다는 것이다.


이와 관련된 헬퍼 함수는 다음과 같다.

void *kvmalloc(size_t size, gfp_t flags); void *kvzalloc(size_t size, gfp_t flags); void *kvmalloc_node(size_t size, gfp_t flags, int node); void *kvzalloc_node(size_t size, gfp_t flags, int node);

 커널 코드를 보다가 이 헬퍼 함수로 교체 가능한 코드가 있다면 수정 하면 좋겠다.


Beginner Guide to Linux Kernel Hacking


막상 kernel 에 관련된 책도 보고 어떻게 개발에 참여할 수 있는지 고민만 많이 하지 딱히 문제가 있는 부분을 찾는 것도 수정하는 것도 어렵다.(다 잘되어 있는 code 처럼 보이기도 하고 ^^)


이래 저래 초보자(?)를 위한 blog 나 site 를 찾아봤지만 뭘 해야하는지 콕 찝어 얘기해주는 것도 아니고..

암튼, 이 제목을 가진 글은 조금 쉬운 접근 방법인 것 같기도 하고 번역도 쉬울 듯 하여 시작해본다.


시작.


Linux kernel 은 굉장히 복잡한 software 이며 누구나 참여가능하지만 hacking 을 쉽게 하고 개발에 기여하기는 어렵다. 다른게 얘기하면 하루 이틀만에 시작하여 hacking 할 수 있는 것은 아니라는 것이다. 개발자는 kernel 에 대한 지식이 필요한데 모든 kernel 내부는 배울 수 있다는 점이 장점이다.


간단한 kernel 에 대한 note 가 있는데 The workings of the Linux kernel 를 참조하면 된다.(이부분도 번역을..)


개발자 스스로 질문을 해보자, kernel 이 나에게 있어 완벽하게 동작하고 내가 고칠 수 있는 부분은 있는 것인가?

(내가 하고 싶었던 질문이다.) 여기 blog 에서는 이런 부분에 대해서는 미리 단념할 필요가 없다고 한다. 커널 개발자들은 도움이 필요한 상세한 list(정리가 필요한 무수한 code들) 를 갖고 있다. 예를 들어, 이런 code들은 /drivers/staging 디렉토리 내부에서 찾을 수 있다. 이 디렉토리 내부에 있는 driver 들은 일반적인 linux kernel coding guideline 을 만족하지 못하는 code 들이 많다. 여기에 위치한 code들은 다른 개발자들에 의해 mainline 에 merge 되기 전에 정리를 도움받고자 하는 것이다. staging 디렉토리 하위에 있는 모든 driver 는 TODO list를 갖고 있는 것도 참고하면 좋다고 한다.


여기 driver 들의 대부분이 그것들의 TODO list 에 다음과 같은 line을 갖고 있다:

- fix checkpatch.pl issues


이것은 어떤 의미를 가지며 어떻게 해야 하는지에 대한 의문이 있을 것이다. 모든 큰 code 의 내용은 여러 개발자들이 참여하여 개발하기 위한 일정한 coding rule 을 갖고 있다. 어떤 kernel 개발자의 목표는 다른 개발자들에게 code의 error를 찾도록 도움을 받고 싶어 한다. 이런 coding rule 은 이런 error를 찾는 것에 도움을 줄 수 잇다는 것이다. 그래서 kernel 에 code가 들어가기 전에 적어도 두명의 개발자가 code에 대한 review 를 하기 때문에 이런 coding style guildline 은 매우 중요한 덕목(?)이다. 그리고 개발자는 kernel source tree 에 Documentation/CodingStyle 에서 관련 사항을 볼 수 있다. coding style 및 error를 빨리 찾기 위해 scripts/checkpatch.pl 이라는 것이 개발되어 졌고, 기본적이 coding style 이 지켜지지 않아 다른 개발자들의 시간을 낭비하는 일을 줄여주는 역할을 해준다.


암튼, drivers/staging 에 위치하는 driver 들은 거의 항상 styling issue 를 갖고 있을 것이다.(guildline 에 익숙치 않은 개발자가 개발하는 경우가 있기 때문이다.) 일단 처음으로 해볼 것이 이런 것들을 kernel coding style guildline 에 맞춰 수정해주는 것이다. 그래서 처음 시작하는 kernel 개발자는 checkpatch.pl 을 수행하고 관련사항을 수정해주므로 해서 도움을 줄 수 있다는 것이다.


Specific Coding Rules

Documentation/CodingStyle 에 모두 나와있지만 개발자가 시작하는데 있어 간략한 부분을 overview 한다.


Whitespace


대부분이 code를 개발함에 있어 indentation(들여쓰기)를 space 가 아닌 tab 을 사용한다. tab은 대게 8 의 길이의 space 를 갖는다. (kernel code 는 tab 을 space 가 아닌 하나의 tab 문자-4 or 8길이의-를 사용한다.) 커널 code를 보고 tab 이 어떻게 되어 있는지 맞춰 주면 될 듯 하다. 또한 한 line 을 80자 이상 넘겨서는 안된다. 80자는 개발자들이 logic을 더 작고 쉽게 인지 할 수 있도록 도와준다.


Braces


Brace 의 사용에 대한 rule 은 꾀 까다롭다. brace를 여는 것은 한 문장의 마지막에 붙여서 쓰고, brace를 닫는 것은 마지막 문장의 다음 line 으로 넘어가서 사용한다. 예제를 보자    


만약 if else 문의 구조라면 다음고 같이 한다.



아래와 같은 경우는 brace 를 사용하지 않는다.



checkpatch.pl

이제 위의 기본적인 coding style을 이해하고 checkpatch.pl script 를 수행 준비하자.
(이 script  가 무엇을 얘기해줄 수 있는지에 대해)

Download 받은 kernel 에서
   $ ./scripts/checkpatch.pl --help
// Image


위의 option 중에 두 개의 common 한 option 이 있는데 --terse 와 --file 이다. 특정 파일에 대한 문제를 간단하게 보여주는 option들이다. 하나의 file을 선택하여 테스트 해보자.

아무런 file을 선택하려고 했더니, 그닥 많이 나오는 파일이 drivers/staging 하위에 선택되지 않았다.
암튼 아무거나 선택해서
   $ ./scripts/checkpatch.pl --file --terse drivers/staging/bcm/Qos.c
를 돌려봤다.
// Image


위에서 보듯이 한 line 에 80자가 넘어간 것이거나, brace 를 rule 에 맞게 쓰지 않은 경우 등을 보여준다.

하나의 예를 들어 수정해보자.

drivers/staging/bcm/Qos.c:821: ERROR: that open brace { should be on the previous line


소스를 위의 rule 에 맞게 고치면,


위와 같이 수정 가능하다.


그럼 제대로 수정이 되었는지 확인하면,

$ ./scripts/checkpatch.pl --file --terse drivers/staging/bcm/Qos.c | grep 821

해서 아무런 message 도 나오지 않으면 성공한 것이다.


수정 후, build 해서 확인 해야 한다.


빌드 방법은 다른 site 에서 찾아 보면 된다.

간단히 그 파일만 빌드 하는 방법을 보면, 물론 full build 가 되어있다는 것을 가정하는 것이다.


$ make drivers/staging/bcm/Qos.o

만약 위와 같이 해서 error 발생하지 않는다면, 변경사항을 patch로 만들고 적용가능한 상황까지 만든 것이다.

일단 이것까지 해왔다면 kernel을 download 받았다는 것이지만, 간략하게 kernel 을 받고 patch를 만들고 전달하는 과정을 적어본다.


// 참고로 /path/to/linux/kernel은 아무대나 kernel이라는 directory를 만들면 된다.

$ mkdir /path/to/linux/kernel

$ cd /path/to/linux/kernel

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


준비 되었다면 다음 단계로 넘어간다.


수정을 한 상태라면 git 을 이용해 local commit 을 만들고 그것을 patch set 으로 변환한 뒤, 관계자(?) 에게 review 메일을 보내면 된다.


commit 을 어떻게 했는지 확인해 보자.


$ cd drivers/staging/bcm

$ git log Qos.c

맨 위의 commit 을 보자

commit c5485e9ca70b5bd5eabfc7c298f7e367062d4f56

Author: Kevin McKinney <klmckinney1@gmail.com>

Date:   Sat Dec 22 14:27:56 2012 -0500


    Staging: bcm: Remove typedef for TransportHeaderT and call directly. // 제목

    // new line + 추가 설명

    This patch removes typedef for TransportHeaderT, and

    changes the name of the struct to bcm_transport_header.

    In addition, any calls to struct "xporthdr" are

    changed to call directly.


    Signed-off-by: Kevin McKinney <klmckinney1@gmail.com>

    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


patch 만드는 방법은, 

수정 완료 후,

$ git add drivers/staging/bcm/Qos.c

$ git commit 

하면 당신의 editor로 comment 를 입력받는 화면이 나온다.

// image



위에 처럼 comment 를 달고(영어를 못하니 일단 대충..) 저장하면 된다.

첫번째 line은 수정사항에 대한 제목 같은 것을 적고 추가적으로 적으려면 새 line(엔터)을 두개 넣고

적으면 된다. 참고하여 위의 commit 처럼 만든다.

Signed-off-by : Your Name <youremail@email.com> 을 추가한뒤 저장.(저는 안했음. 지금 보낼것이 아니라서..)


이제 당신의 첫번째 patch를 완성했다.


Getting Your Change into the Kernel Tree


위에서 수정한 사항을 patch로 만들어 커널 개발자에게 review 및 전달을 요청해야 한다. 일단 patch를 일단 만들어 보자.


$ git log

당신의 commit 이 제일 위에 있을 것이다.

바로 밑에 있는 commit 의 hashid 를 parameter 로 넣어준다.


$ git format-patch <hashid> -o ~/

이렇게 하면 만들어진 commit 이 0001-XXX.patch라는 이름으로 만들어 진다.


이것을 다시한번 checkpatch.pl 을 수행해서 정상적으로 반영가능한지 확인을 해보자.

내가 위에서 했던 수정했던 것은 또다른 문제를 갖고 있어 error를 출력했지만 정상적으로 되었다면

total :0 errors, 0 warnnings, XX lines checked 가 보일 것이다.


이제 메일을 보내보자.


Now to Send it Off


이제 완정된 patch를 누구에게 보내야 하는지 알아야 한다. 커널 개발자들은 script 로 누구에게 알려야 되는지 쉽게 알수 있다. 그 script는 get_maintainer.pl 이고 이것은 scripts directory에 위치한다. 이 script는 파일을 확인하고 내가 수정한 파일이 kernel source tree의 maintainer 들에 대한 정보를 알려준다. 


$ ./scripts/get_maintainer.pl /path/to/0001-your-patch.patch

devel@driverdev.osuosl.org (open list:STAGING SUBSYSTEM)

linux-kernel@vger.kernel.org (open list)


위와 같이 나오더라.


이것은 일반적인 e-mail client 로 전송하면 patch format에 space및 tab 등 변형이 되기 때문에 Documentation/email-clients.txt 를 확인하여 그 email client 를 이용하여 전송하면 된다. 하지만 git commit 로도 지원이 되는데, 그 방법은,


$ git send-email -to email@email.com -to email2@email.com -cc devel@driverdev.osuosl.org -cc linux-kernel@vger.kernel.org 0001-your-patch.patch 하면 된다.


사실 to 를 누구로 해야하는지는 안나와 있어서 나중에 내가 용기가 나면 시도 해보고 다시 알려주겠다.

또 한가지 git send-email command 가 없다고 나오는 경우도 있는데, 그 때는

// ubuntu 의 경우

$ sudo apt-get install git-email


하면된다.


이렇게 해서 적절한 CC로 메일이 일단 전달되면 몇일 내로 개발자에게 답변이 온다고 한다. 답변은 accept 해주거나 comment 를 포함해서 온다고 한다. (comment 가 날아오면 그것을 해결하고 다시 보내면 될 듯.)


이상 여기까지 초보 개발자가 kernel 에 contribution을 하는 방법을 알리는 blog 를 나름 번역을 해봤다.

원문 : http://lotphelp.com/lotp/beginner-guide-linux-kernel-hacking


Kernel을 분석한답시고, 갖고 있는 책은 많은데 꾸준히 하질 못했는데 블로그를 쓰면서 
조금씩이나마 정리를 해보려고 한다. 

우선은 "Professional Linux Kernel Architecture" 책을 번역하며 Comment 정도만 작성하는 식으로 진행을 해 볼까 한다. 

물론 영문을 번역하며 오역이나 내용의 헛점이 있을 수 있음을 알려드립니다. 꾸벅.

Chapter 2, Process Management and Scheduling


요즘 나오는 Operating System은 한번에 여러 개의 Process들을 실행 할 수 있다.(이것은 User 입장에서 그렇게 수행되는 것처럼 느껴지는 것이다.)  만약 하나의 시스템에 하나의 CPU를 가지고 있다면, 주어진 시간에 하나의 Process만을 실행 시킬수 있다. Multi-Processor 시스템에서는 물리적인 CPU 개수 만큼 Process들을 병렬적으로 수행 시킬 수 있다. 

Kernel과 Processor는 매우 빠른 간격으로 서로 다른 Application간에 번갈아가며 실행함으로써 시스템이 Multi-tasking(병렬적으로 여러 operation을 수행하는 능력)을 하는 것처럼 만들어 준다. 번갈아 실행하는 간격이 매우 짧기 때문에 User들은 Process가 일정 시간동안 활동하지 않는 상태임을 알지 못하고, 컴퓨터가 실제로 한번에 여러 일을 하는 듯한 느낌을 받게 된다. 

Kernel에서 해결해야할 중요한 시스템 관리 이슈들이 이 있고 이중 중요한 것은,
□ Application들은 일부러 그렇게 만들어 지지 않는 이상, 다른 Application을 간섭할 수 없다. 예를 들어, error를 가지고 실행하는 application A는 Application B에게 영향을 줄 수 없다. Linux는 multi-user 시스템이기 때문에, 프로그램들이 다른 프로그램의 메모리 영역을 읽거나 쓰게 할 수 없도록 해야 한다. 만약 그렇지 않으면, 다른 user들의 개인 data를 쉽게 접근할 수 있는 문제점이 있다. 

□ CPU 사용시간은 다양한 Application 사이에 최대한 공평하게 주어져야 하며, 이것은 어떤 프로램이 다른 것들 보다 더 중요한지 결정하는 것 중요한 포인트가 된다. 

 이 장에서는 kernel이 CPU 사용 시간을 어떻게 공유하고 process간 switch하는 방법을 설명한다.
이 두가지 작업은 각각 독립적으로 수행되는 두개의 부분으로 나누어져있다. 
□ kernel은 반드시 각 process들에게 얼마나 수행해야 하는지 그리고 언제 다른 process와 교체되어야 하는지 결정해야한다. 이것은 실제로 어떤 process가 다음에 수행되어야하는지에 대한 논점과는 다른 것이다. (다음 수행되어야 하는 것이 미리 결정되어 있진 않다) 이런 종류의 결정은 platform에 의존적이지 않다.(알고리즘에 결정된다는 뜻?)

□ process A에서 process B로 교체가 될 때, process B가 CPU 자원을 마지막으로 놓았던(release) 시점의 환경과 동일해야 한다.(당연한 얘기지만 B가 수행되었던 자원 등 상태를 어딘가에 저장해두어야 한다는 의미인듯) 예를 들어, CPU register 값과 virtual address의 구조등의 것들이 교체된 process가 가지고 있었던 것이어야 한다. 

후자의 내용은 CPU type에 매우 의존적이다.(가상 메모리의 구조나 cpu의 register 운영은 cpu architecture 마다 다른게 가지고 있다)그것은 C 언어 만으로 구현되기 어려우며 architecture의 assembler 에 도움을 받아야한다. (register 내용을 저장하고 복구하는 내용들은 순수 assembler로 구현되어 있다)

위의 두가지 작업은 scheduler라는 kernel의 subsystem이 관장하고 있다. scheduler 정책에 의해 각 process에게 CPU 시간을 할당하고 수행하게 한다. 이것은 process 교체 메카니즘과는 완전히 분리된 작업인 것이다. (task switch 관련해서는 다른 포인트인 듯)

2.1 Process Priorities
모든 process들이 똑같이 중요한 것은 아니다. process 우선순위는 여러 요구사항을 만족시키기 위한 임계점(Criticality classes)이 다르다. 임계점을 고려하는 부분에서 크게 두 분류로 나누어 보면, real time process와 non-real time process가 있다. 

Hard real-time process는 Process가 수행 완료되는 시간이 엄격히 제한적이다. 만약 항공기의 비행 조종 명령이 컴퓨터에 의해 처리된다면, 그 명령들은 최대한(물론 최대한이라고는 하지만 dead line이내에 수행이 되어야 한다는 뜻) 빨리 기계에 전달되어야 한다. 예를 들어, 만얀 항공기가 착륙지점에 다달았고, 조종사는 기수를 끌어내리기를 시도할 때, 컴퓨터가 몇초 늦게 명령을 전달하여 그 작은(?) 일을 진행했다. 그 때, 항공기는 아마도 땅에 뭍혀버리고 말것이다. Hard real-time process의 중요한 key point는 보장된 시간내에 그 명령이나 행동을 무조건 처리해야한다. 물론 이 보장된 시간은 특별히 짧은 시간만을 말하는 것이 아니다. 그 보다 더 시스템은 주어진 시간을 절대로 초과하지 않는다는 것을 보장해야 한다. 

Linux는 hard real-time processing을 지원하지 않는다.(적어도 vanilla kernel에서는..) 그렇지만, 수정된 리눅스 버전에서 지원되고 있다(RTLinux, Xenomai, RATI 등). 수정된Linux는 process를 분리하여 수행한다. 이는 kernel이 덜 중요한 software(process)를 real-time process 작업이 kernel 외부에서 수행되는 동안 처리하도록 한다.

Linux는 throughput(처리량)을 위해 최적화 되어 있고 가능한한 일반적인 경우를 처리하려고 노력한다. Linux에서는 보장된 응답 시간을 맞추는 것은 어려운 일이다. 그럼에도 불구하고 kernel 전체의 지연시간(요청하고 이행하는 사이의 시간)의 감소는 아주 조금씩 진전이 있어왔다. 이런 진전은 preemptible kernel mechanism(선점 커널 메카니즘), real-time mutexes, 새로운 completely fair scheduler 등으로 이루어 졌다. 이 책의 뒷 부분에 더 자세히 설명되어 있다. 

Soft real-time process는 hard real-time 보다 덜 강압적인(?) 형태이다. 비록 빠른 결과를 요구되는 것은 변함이 없지만, 조금 늦게 처리 된다고 하더라도 문제 될 것이 없는 것이다. CD에 data 쓰기를 하는 작업을 예로 들 수 있다. Data는 반드시 CD writer에게 연속적으로 기록해야하는 매체인 만큼 정해진 비율로 지속적으로 전달되어야 한다. 만약 시스템의 부하가 높아져서 Data 전송에 방해를 받게 된다면, CD를 사용할 수 없게 될 수도 있다. (이것은 위에 hard time의 예로 들은 비행기 추락보다는 낫다는 얘기이다). 이것 때문에라도(CD 를 못쓰게 하는 것을 방지) CD write process는 다른 process보다 그것이 요구하는 시간만큼 보장을 받게 해준다.

□ 대부분의 Process들은 특별한 시간 제한이 없는 "normal process"이다. 하지만 그것들에게 더 중요하고 덜 중요하다는 의미의 우선순위로 분류 하고 있다. 
예를 들면, 긴 시간의 컴파일 작업과 숫자 계산을 하는 process는 상대적으로 매우 낮은 우선순위는 가진다. 이유는, 1초 혹은 2초 동안 때때로 진행을 방해받더라도 결과에는 영향을 거의 미치지 않기 때문이다. 반대로 대화형 application(VIM 같은 편집기)는 가능한 빠르게 사용자 명령에 대한 응답을 보내줘야하기 때문에(사용자는 인내심이 없기로 유명하덴다) 높은 우선순위를 가진다. 

application의 CPU 시간은 그림 2-1에서 간단하게 보여 줄 수 있다. Process들은 하나의 시간 조각(time slice)에 나누어 위치하고 있고 각각 중요도에 따라 조각의 크기는 다르게 설정된다. 시스템의 시간 흐름에 따라 원을 돌며 Process를 실행하고 모든 process가 수행되기는 하지만, 중요한 Process들은 상대적으로 많은 시간을 얻어 수행시간이 길다. 

<그림 2-1>

선점 멀티태스킹(preemptive multitasking)이라고 알려진 방법은, 각 process는 수행되는 일정한 시간을 할당 받는다. 일단 그 시간이 만료되면, kernel은 process로 부터의 control을 그만두고 다른 process를 수행시킨다(여기서 다른 process는 이전 process에 의해 마지막으로 실행된 작업과는 무관하다). 시간의 만료된 process의 환경(특히, CPU register와 page table의 내용)은 꼭 저장되어 나중에 다시 복귀하여 실행 시 완전히 이전 상태로 돌아갈 수 있어야 한다. time slice의 길이는 process의 중요도에 따라 다르게 정해지게 된다. 그림 2-1과 같이 각각의 process들은 다른 크기의 slice를 가지고 있는 것을 확인 할 수 있을 것이다. 

이 단순화된 모델(그림 2-1)은 몇 가지 중요한 문제를 다루지 않은 것이다. 예를 들어, process들이 아직 실행 할 것이 없어 준비되지 않은 경우이다. 이 경우에 CPU 시간을 할당 했다고 해서 실행을 하면 아무 것도 하지 않고 시간만 까먹는 것이므로 효율적으로 사용하기 위해서는 이런 process들은 실행을 안 시키는 것이 좋다. <그림 2-1>에서는 모든 process가 실행 가능한 상태에서 CPU 자원을 대기중이라는 가정하에 시행한 것임을 알려드린다. 또 한가지는 Linux는 두가지의 scheduling class를 제공한다.(Completely Fair Scheduling, Real-time Scheduling) 

kernel 개발자들 사이에서는 scheduling의 일부인 다음 수행될 process를 선택하는 알고리즘에 대한 논의가 활발하다.(그만큼 중요하고 개발의 여지가 많아서 인듯). scheduler의 질적 향상에 대한 측정은 거의 불가능 하다. scheduler는 Linux System이 직면한 다른 많은 workload에 의해 생긴 요구사항을 해결 하기 위한 도전적인 과제일 것이다. 자동화된 조작을 위한 작은 embedded system에서는 대형 컴퓨터에서 요구되는 사항과는 많이 다를 것이다. 사실, scheduler code는 최근 두 가지 형태로 알아볼 수 있다. 

1. 2.5 version에서 개발 되는 동안, 기존의 scheduler를 대체하는 O(1) 대체하는 소위 O(1) scheduler 가 있다. 이 scheduler의 한가지 특별한 점은 System에 수행되고 있는 process 개수에 관계없이 상수시간에 다음 실행할 process를 선택할 수 있다. 이런 설계는 기존 scheduling 구조를 완벽히 바꾼 계기라고 할 수 있다.
2. Completely fair scheduling 은 kernel 2.6.23 버전까지 개발 진행되어 추가되었다. 이 새로운 코드는 기존의 원칙을 버리고 완벽한 시도가 되는 출발점이 된다.예를 들면, 이전 scheduler에서 요구된 것을 바탕으로 대화식의(vim program 등의 편집기) process는 응답시간을 빠르게 해주는 것이 된다. 이 scheduler의 중요한 포인트는 이상적인 fair scheduling 을 가능한 가깝게 구현하도록 노력했다는 것이다. 게다가 그것은 각각의 task들을 scheduling 할 뿐만 아니라, 더 일반적인 scheduling 단위에서도 잘 동작한다. 이는 다른 사용자들의 모든 process 간의 시간 분배와 각 사용자들이 사용하고 있는 process들 사이에서도 가능한 시간을 분배할 수 있도록 고려되어 있다. 

2-1 을 마무리 합니다. 틈틈히 읽어보고 수정사항이 있다면 변경하도록 하겠습니다.

+ Recent posts