The Big Picture

froajnzd·2024년 11월 15일
0

how linux works

목록 보기
1/8
post-thumbnail

이 글은 How Linux Works, 3rd edition에서 발췌한 내용을 바탕으로 한다.

abstraction (추상화)를 통해 Operation System이 어떻게 동작하는지 이해할 수 있다.

abstraction으로 대부분의 세부사항을 무시하고 기본 목적과 작동에 집중할 수 있다.

리눅스 시스템의 계층과 추상화 레이어에 대해 알아보자.

리눅스 시스템의 구성 요소를 layer나 level로 분리한다.

세 가지의 주요 level이 있다.

  1. Hardware
    base에 있다. 메모리와 CPU가 포함된다. computation을 수행하고 메모리를 read/write
    Devices 종류: disks, nextwork interfaces

  2. Kernel
    Operating System의 core. 메모리에 상주하는 소프트웨어. CPU가 다음 작업을 찾을 위치를 알려준다.
    mediator(중재자) 역할을 하며, 하드웨어(메인 메모리)를 관리. h/w와 실행 프로그램 사이의 주요 interface.

  3. User Processes
    kernel이 관리하는 실행중인 프로그램.
    user space라고 불리는 시스템의 상위 레벨을 집합 구성한다.

kernel과 user process가 실행되는 상식에는 중요한 차이가 있다. kernel은 kernel mode에서 실행되고, user process는 user mode에서 실행된다!

kernel mode에서 실행되는 코드는 processor & main memory에 제한 없이 접근할 수 있다. : 강력하지만 위험하다. 커널이 전체 시스템을 쉽게 손상/충돌시킬 수 있기 때문이다.

대조적으로, user mode는 매우 작은 메모리 하위 집합, 안전한 CPU 작업에 대한 접근을 제한한다.
user space는 user process가 접근가능한 메인메모리의 한 부분을 가르킨다
만약, process가 실수해 충돌한다면, 결과가 제한되며 kernel에서 정리할 수 있다. => 즉, 웹브라우저가 충돌해도 백그라운드의 다른 연산은 중단되지 않을 것.
이론적으로 user process가 엉망이 돼도, system에는 손상이 없다는 것.
실제로, "심각한 손상"으로 간주하는 것과 프로세스의 특정 권한에 따라 달라짐.(일부 프로세스는 다른 프로세스보다 더 많은 작업을 수행할 수 있기 때문)

리눅스 커널은 프로세스와 매우 비슷함
커널 공간에 액세스할 수 있는 커널 스레드를 실행할 수 있다. (ex. kthreadd, kblockd)

2. Hardware : 메인메모리 이해하기

H/W에서 가장 중요한 것은 메인메모리이다.
가장 원시적인 형테로 0과 1을 위한 storage area이다.
각 슬롯(0 또는 1이 존재함)을 bit라고 한다.
실행 중인 커널과 프로세스가 있는 곳이다.
주변 장치의 모든 I/O는 메인 메모리를 통해 bit 묶음으로 흐른다.
CPU는 단지 메모리의 operator이다. instruction과 data를 memory에서 읽고, 데이터를 다시 memory에 쓴다.

컴퓨터 시스템의 memory, processes, kernel 및 다른 부분과 관련하여 state는 bit의 특정 배열이다.

states를 조금 더 쉽게 설명하자면, 메모리에서 싱글 프로세스가 수백만 bits로 쉽게 구성될 수 있다는 점을 고려해보자.
무언가가 현재 수행됐거나 수행중인 작업을 설명한다면, "프로세스가 입력을 기다리고 있다" 또는 "프로세스가 2단계를 수행하고 있다"라고 설명할 수 있다.

실제 bit가 아닌, 추상적인 용어로 상태를 참조하는 것이 일반적이기에 image라는 용어는 bit의 특정 물리적 배열을 나타낸다.

3. The Kernel

커널의 거의 모든 작업은 메인메모리를 중심으로 이루어진다

커널의 일

  • 메모리를 많은 subdivisions(하위분할)으로 분할
    - 각 subdivisions에 대해 특정 상태 유지

각 process는 본인의 own share of memory를 갖고, 커널은 각 프로세스가 해당 share를 유지하도록 보장해야 한다.

커널은 4가지 일반 시스템 영역에서 작업(task)을 관리한다.

  1. Processes : 커널은 CPU를 사용할 수 있는 프로세스를 결정
  2. Memory : 커널은 모든 메모리(즉, 특정 프로세스에 현재 할당된 메모리, 프로세스 간에 공유할 수 있는 메모리/사용가능한 메모리)를 추적
  3. Device drivers : 커널은 하드웨어(ex. disk)와 프로세스 간의 인터페이스 역할. 일반적으로 커널이 하드웨어를 작동함
  4. System calls and support : 프로세스는 일반적으로 system call을 사용해 커널과 통신

각각에 대해서 알아보자

3.1 Process Management

Process management(프로세스 관리)는 프로세스들의 starting(시작), pausing(중지), resuming(재개), scheduling(스케줄링), terminating(종료)을 포함한다.

현대 OS에서는 우리가 컴퓨터에서 동시에 웹브라우저와 excel 등의 프로그램을 실행시키는 것처럼 많은 프로세스들이 동시에 실행될 수 있다.
그러나, 이런 프로그램 이면에 있는 프로세스는 정확히 동시에 실행되지 않는다

1 core CPU를 고려해보자. 많은 프로세스가 CPU를 사용할 수는 있지만, 한 번에 하나의 프로세스만 CPU를 사용할 수 있다.
실제로 각 프로세스는 짧은 몇 초동안 CPU를 사용한 다음 일시중지한다. 그 다음 다른 프로세스가 짧은 몇 초간 CPU를 사용한다. 이런식으로 실행한다.
이렇게, 한 프로세스가 CPU의 제어를 다른 프로세스로 넘기는 행위를 CONTEXT SWITCH라 한다.

Time slice(각 시간의 조각)는 프로세스에 중요한 계산을 위해 충분한 시간을 준다.(실제로, 프로세스는 단일 조각동안 현재 작업을 완료하는 경우가 많다)
그러나, Slice는 매우 작기에, 사람이 인식할 수 없고, 시스템이 동시에 여러 프로세스를 실행하는 것처럼 보여진다(multitasking)

kernel은 context switching을 한다.
context switching의 동작 순서를 보며 kernel이 무엇을 수행하는지 알아보자.

  1. CPU(실제 하드웨어)가 현재 실행 중인 프로세스를 중단하고 kernel에 제어권을 넘긴다
  2. kernel은 CPU와 메모리의 현재 상태(중단된 프로세스 상태)를 저장한다.(프로세스를 다시 시작할 때 필요함)
  3. kernel은 I/O 작업 같은 이전 Time slice동안 발생한 일을 처리한다
  4. kernel은 실행 대기 중인 프로세스 중에서 다음에 실행할 프로세스를 선택한다
  5. 선택된 프로세스를 위한 메모리, CPU를 준비한다
  6. 새 프로세스의 time slice 길이를 CPU에 알린다
  7. CPU를 사용자 모드로 전환하고, 새 프로세스에 제어권을 넘긴다.

보통 CPU는 사용자 프로그램(프로세스)이 주로 사용하지만, 프로세스들이 CPU를 넘겨받는 context switching 순간에 kernel이 잠깐 실행된다. 이때 kernel이 현재 프로세스의 상태를 저장하고, 다음에 실행할 프로세스를 준비하는 등 다음 프로세스가 CPU를 사용할 수 있도록 준비 작업을 한다.

Multi-core CPU 시스템에서는 kernel이 각 CPU마다 프로세스를 독립적으로 실행할 수 있다. 그러나 여러 CPU를 최대한 효율적으로 사용하기 위해 kernel은 context switch 과정을 적용해 각 프로세스가 CPU를 적절히 사용할 수 있도록 조정한다

3.2 Memory Management

kernel은 context switch 동안 memory를 관리하는데, 이때 다음의 조건들을 만족해야 한다.

  • kernel은 사용자 프로세스가 접근할 수 없는 개인 영역이 있어야 한다
  • 각 사용자 프로세스에는 고유한 메모리 섹션이 필요하다
  • 한 사용자 프로세스가 다른 프로세스의 개인 메모리에 접근하지 못할 수 있다
  • 사용자 프로세스는 메모리를 공유할 수 있다
  • 사용자 프로세스의 메모리의 일부는 읽기 전용이다
  • 시스템은 디스크 공간을 보조로 사용하여 물리적으로 존재하는 것보다 더 많은 메모리를 사용할 수 있다.

kernel에는 virtual memory(메모리 액세스 체계)를 가능하게 하는 MMU(Memory Management Unit)가 포함된다.
가상 메모리를 사용하는 경우, 프로세스는 하드웨어의 물리적 위치를 통해 메모리에 직접 접근하지 않는다.
대신, kernel은 각 프로세스가 마치 전체 머신을 가진 것처럼 작동한다.

가상 메모리를 사용할 때는 각 프로세스가 실제 컴퓨터 전체를 혼자 쓰는 것처럼 보인다.
즉, 프로세스는 물리적인 메모리 위치에 직접 접근하지 않고, 가상의 메모리 주소를 사용해 메모리에 접근한다.

이 과정에서 MMU라는 장치가 중요하다.
MMU는 프로세스가 메모리에 접근하려고 할 때 가상 메모리 주소를 물리 메모리 주소로 변환해주는 장치이다.(프로세스의 접근을 가로챈 후 memory address map을 사용해 실제 메모리 위치를 안다) 이렇게 함으로써 각 프로세스는 다른 프로세스와 격리된 상태에서 자신만의 메모리를 사용하고 있다고 느끼게 된다.
이 시스템이 작동하려면 kernel이 가상 메모리 주소와 물리 메모리 주소를 연결해주는 memory address map을 설정하고 유지해야 한다.
예를 들어, context switch가 발생할 때 kernel은 이전 프로세스의 메모리 매핑을 새로운 프로세스의 매핑으로 바꿔야한다.

memory address map을 구현한 것을 page table이라고 한다.

3.3 Device Drivers and Management

device에서 kernel의 역할은 간단하다. 장치는 일반적으로 kernel모드에서만 액세스할 수 있는데, 부적절한 액세스(ex. 전원을 끄는 사용자 프로세스)로 인해 컴퓨터가 충돌할 수 있기 때문이다.
어려운 점은, device가 동일한 작업(ex. 두 개의 서로 다른 네트워크 카드)을 수행하더라고 서로 다른 장치가 동일한 프로그래밍 인터페이스를 거의 갖지 않는다는 것이다
따라서, device driver은 전통적으로 kernel의 일부였고, 소프트웨어 개발자의 작업을 단순화가기 위해 사용자 프로세스에 일관된 인터페이스를 제공하고자 한다.

3.4 System Calls and Support

user process에서 사용할 수 있는 몇가지 종류의 kernel 기능이 있다.
예로, system calls(syscalls)은 user process만으로는 잘 수행할 수 없는 특정 task를 수행한다. 또 다른 예로, 파일을 열고, 읽고, 쓰는 작업에는 모두 시스템 호출이 포함된다.

fork()와 exec(). 두 개의 system calls은 프로세스가 어떻게 시작하는지 이해하는 것이 중요하다.

  • fork() : process가 fork()를 호출하면, kernel은 프로세스와 거의 동일한 복사본을 만든다.
  • exec() : process가 exec(program)을 호출하면, kernel은 program을 로드하고 시작하여 현재 프로세스를 대체한다.

init을 제외한 리눅스 시스템의 모든 user process는 fork()의 결과로 시작되며, 대부분 기존 프로세스의 복사본을 실행하는 대신 exec()를 실행하여 새 프로그램을 시작한다.
예를 들어, ls를 실행하면, 터미널 창에서 실행중인 셸이 fork()를 호출하여 셸의 복사본을 만든다음, 셸의 새 복사본이 exec(ls)를 호출하여 ls를 실행한다.

kernel은 기존 system call이외의 기능을 사용해 user process를 지원하며, 그 중 가장 일반적인 것은 pseudodevices이다.
Pseudodevices는 user device 장치같아 보이지만, 순수 소프트웨어이다.
즉, 기술적으로 kernel에 있을 필요가 없지만, 일반적으로 실용적인 이유로 kernel에 있다.
예를 들어, kernel random number generator device(/dev/random)는 user process로 안전하게 구현하기 어렵다.

기술적으로, 의사 장치에 접근하는 user process는 system call를 사용해 장치를 열어야 하기에 프로세스는 시스템 호출을 완전히 피할 수 없다.

4. User Space

kernel이 user process에 할당하는 주 메모리를 user space라 한다.
프로세스는 단순히 메모리의 상태(또는 이미지)이기에 user space는 실행 중인 프로세스의 전체 컬렉션에 대한 메모리를 참조하기도 한다.(사용자 공간에 사용되는 비공식적인 용어인 userland를 들을 수 있다.)

리눅스에서 대부분의 실제 동작은 user space에서 일어난다.

Basic services => 하위 수준(kernel에 가까움)
Utility services => 중간 수준
Applications => 상위 수준

최하위 수준은 단순한 작업을 하는 작은 구성요소로 이루어져 있고, 중간 레벨은 메일, 인쇄, 데이터베이스 서비스와 같은 더 큰 구성요소가 위치한다. 최상위 수준은 사용자가 직접 제어하는 복잡한 작업으로 이루어져 있다.
컴포넌트들은 또한 다른 컴포넌트들을 사용한다.
일반적으로 하나의 컴포넌트가 다른 컴포넌트를 사용하기 원한다면, 두 번째 컴포넌트는 같은 서비스 레벨이거나 아래의 레벨에 있을 것이다.

실제로는, user space에는 규칙이 없다. 예를 들어, 대부분의 application과 service는 로그(진단 메세지)를 쓴다.
대부분 프로그램들은 표준 syslog 서비스를 로그 메세지를 출력하는 데 사용하지만, 몇몇은 자체적으로 로그를 기록하는 것을 선호한다.

게다가, user space 구성요소를 분류하기 어려운 경우도 있다.
웹, 데이터베이스 서버와 같은 서버 컴포넌트들은 복잡한 작업을 수행하므로 고수준 애플리케이션이라고 할 수 있다.
또, 다른 application의 작업을 지원하기도 하기에 중간 레벨로 볼 수도 있다.

5. Users

linux kernel은 Unix 사용자의 기본 개념을 차용한다. user는 프로세스를 실행하고 파일을 소유할 수 있는 entity이다.
user는 username과 연결된다. 예로, 시스템에 billyjoe라는 user가 있다. 그러나 kernel은 username을 관리하지 않는다. 대신, user를 userId라고 하는 간단한 숫자 식별자로 식별한다.

user는 주로 permission, boundary를 지원하기 위해 존재한다.
모든 user space 프로세스에는 소유한 사용자가 있고, 그 사용자 이름으로 프로세스가 실행된다.
사용자는 특정 한도 내에서 자신의 프로세스 동작을 종료하거나 수정할 수 있지만 다른 사용자의 프로세스를 방해할 수는 없다.
user는 (특정 한도 내에서) 자신의 프로세스를 종료/수정할 수 있지만, 다른 user의 프로세스를 방해할 수 없다.
또, user는 파일을 소유하고 다른 사용자와 공유할지 여부를 선택한다.

linux system 안에는 여러 명의 사용자가 존재한다. 가장 대표적이고 중요한 user는 root이다. root는 예외적으로 다른 사람의 프로세스를 수정/종료할 수 있고 시스템의 모든 파일에 접근할 수 있다. 이 이유로, root는 superuser로도 불린다.

Groups는 user의 집합이다. group은 user가 같은 그룹의 user들에게 파일을 공유하기 위하는 데 목적이 있다.

profile
Hi I'm 열쯔엉

0개의 댓글

관련 채용 정보