1. Process의 생성
지금까지 OS의 필요성과 기본적인 구조를 배웠다. 이제 조금 더 자세히 OS가 어떻게 작동하는 지 살펴보자. 이번에는 OS에서 가장 중요한 Abstraction인 Process에 대해 배워보자. 일련의 작업을 하는 프로세스를 만들기 위해서는 프로그램이 사전에 존재해야 한다. 이 프로그램은 소스코드로 부터 컴파일러와 링커를 통해 만들어지고, 이렇게 만들어진 프로그램이 Loader에 의해 프로세스가 되어 메모리에 올라가고, 실행된다. 이 변환 과정의 특징을 간단하게 알아보자.
-1. Compliler [Source code --(Assembler)--(Compiler)--> Object file]
Object file? : 기계어로 구성된 파일, 실행은 불가능 하지만 프로세스로 변환되기 위한 정보가 존재함. 따라서 Relocatable Address로 표현됨
-2. Linker [Object file + Library --(Linker)--> Executable]
Executable? : 특정 환경에서만 실행될 수 있는 파일, Header, Text, Data등을 포함, Absolute address로 표현된다.
여기서 특정환경이란 특정 OS와 CPU를 명시한다.
-3. Loader[Executable --(Loader)--> Memory]
로드 과정 : Executable의 헤더 읽고 Text와 Data의 크기, 위치등을 결정한다. ->VM Space를 생성한다 -> Excutable로 부터 Data를 VM으로 복사한다 -> 실행 때 받은 Argument를 Stack에 복사한다 -> CPU Register를 초기화 + Start-up routine(약속된 메모리 주소로)으로 점프한다
여기서 Start-up routine을 포함한 Runtime system에 대해서 알아보자.
-4. Runtime system?
프로그램과 연결하여 상호작용하는 시스템으로, 응용프로그램의 효율적인 실행을 지원한다. Memory에 올라간 Executable을 감싼 형태로 함께 로드됨
C의 Runtime system은 C Runtime system program execution으로, 몇가지 규칙을 갖는다
(1). GCC때 아까 나온 start-up code object를 함께 컴파일하고, 기본 라이브러리들을 동적으로 링크한다.
(2). Process 시작을 위해 PC를 _start함수의 주소로 초기화한다
(3). _start함수에서 동적으로 링크된 C라이브러리 및 쓰레드 환경 초기화를 위해 _lib_start_main함수를 호출한다
(4). 초기화 이후 main함수를 호출한다
2. 프로세스 관리
프로세스는 New, Running, Waiting, Ready, Terminated와 같은 5가지의 상태로 나뉘어 진다. 그리고 이 상태를 바탕으로 Ready queue, Waiting queue, Running queue로 나누어 프로세스를 상태에 따라 관리한다. 그리고 그 queue를 조작하는 규칙에 의해 프로세스의 상태가 변하며 concurrent하게 실행된다.
이렇게 프로세스를 queue에 넣어 관리하기 위해서는 각 프로세스를 데이터로써 표현할 수 있어야 한다. 이를 Proccess Control Block(PCB)라고 한다. 그럼 이 블록에는 어떠한 정보들이 존재할까? 다음 그림을 통해서 살펴보자.
모두 프로그램의 context switching을 지원하기 위해 필요한 정보들이다. 가령 어디까지 읽었는지, 그 당시에 어떠한 데이터(레지스터값)을 가지고 있었는지 등을 포함한다. 눈여겨 볼만한 부분은 스케줄링 방식도 저장한다는 것이다. 각 프로세스의 특징과 용도에 따라서 다른 스케줄러를 사용할 수 있기 때문에 이를 명시해야하기 때문이다. 이러한 정보들을 바탕으로 Context switching을 지원하는 것이다. Context switching이라는게 뭐고 왜 중요할까?
3. Context switching
문맥 전환은 old process상태를 저장하고, new process를 로드하는 커널의 작업이다. 이 작업은 concurrent한 실행흐름을 위해 필수적인데, 어떻게 context switching하냐에 따라 효율성이 달라지게 된다. 하지만 동일한 것은 Context switching time이 overhead라는 점과 hardware support에 의존한다는 특성이다. 예를 들어 인텔과 같은 CISC(Complex Instruction Set Computer)구조의 프로세서라면 복잡한 명령어 Set을 가지기 때문에 효율이 높고 클럭 속도가 낮다는 특성이 있다. 그리고 복잡한 회로를 갖기 때문에 차지하는 물리적 공간이 많아서 레지스터 용량이 작다. 그러므로 context switching의 속도가 빠르다는 특징을 갖는다.
반면에 ARM과 같은 RISC(Reduced Instruction Set Computer) 프로세서는 간단한 명령어 Set을 갖기 때문에 클럭 속도가 높아 빠른 수행 속도를 갖는다. 회로가 차지하는 공간이 비교적 작아 register가 많이 적제되어 context switching 시 레지스터 내용 변경에 큰 오버해드를 갖는다.
이는 단순히 Context switching의 관점에서 바라본 프로세서 구조의 차이이다. 즉, 오버해드는 RISC가 더 클 수 있지만 전체적인 성능은 더 좋을 수도 있다.
4. 프로세스 생성과 종료
프로세스는 동적으로 실행되고 종료된다. OS는 이 메카니즘을 제공해야 하는데, 이 방식은 효율적이어야 할 것이다.
따라서 프로세스 생성 때 fork를 통한 Resource sharing을 한다. fork를 통해 프로세스를 duplicate하고, 이후 exec명령을 통해 실행하고자 하는 프로세스를 로드한다. 굳이 이렇게 하는 이유는 kernel이나 library등 모든 프로세스가 공통적으로 사용하는 부분을 공유하여 효율적으로 로드하기 위함이다. 모든 프로세스는 이와 같은 순서를 갖는데, 예를 들어 UNIX시스템의 모든 프로세스는 init process(User process환경에 만드는 최초의 process)를 기반으로 만들어 진다.
그렇다면 이제 프로세스의 종료에 대해서 알아보자. 프로세스는 exit system call을 통해 OS에 리소스를 해제해주고, parent에게 output을 signal형태로 전달한다.
'학교 공부 > OS' 카테고리의 다른 글
운영 체제 (Operating System) - Kernel System Call 이해와 구현 (0) | 2021.11.28 |
---|---|
운영 체제 (Operating System) - Computer Architecture (0) | 2021.11.28 |
운영 체제 (Operating System) - 운영체제 구조 (2) (0) | 2021.11.28 |
운영 체제 (Operating System) - 운영체제 구조 (0) | 2021.11.27 |
운영 체제 (Operating System) - 개요 (0) | 2021.11.27 |