CS/operating system

Program Execution: 프로그램의 실행(메모리 로드) 2/2

superbono 2021. 2. 8. 15:04

4. 사용자 프로그램이 사용하는 함수

 * 사용자 정의 함수

   자신의 프로그램에서 정의한 함수(프로그래머 본인이 직접 작성한 함수). 함수 호출시에 프로세스 자신의 주소 공간 스택을 이용한다. 프로세스 자신의 address space의 코드 공간에 기계어 명령으로 있다.

 * 라이브러리 함수

  자신의 프로그램에서 정의하지 않고 갖다 쓴 함수, 자신의 프로그램 실행 파일에 포함, 함수 호출시에 프로세스 자신의 주소 공간 스택을 이용한다. 프로세스 자신의 address space의 코드 공간에 기계어 명령으로 있다. 

 * 커널 함수

운영체제 프로그램의 함수, 커널 함수의 호출 = 시스템 콜, 하드웨어 및 소프트웨어가 cpu의 서비스를 요청하기 위해 발생시키는 인터럽트 처리 함수 함수. 커널의 주소 공간 중 코드 공간에 정의된다. 사용자 프로그램이 이 커널 함수를 호출하는 시스템콜을 동반하여 호출하는 것임 운영체제 내부에는 시스템 콜 함수로 read() 함수와 write()가 정의되어 있다.

? 일반적인 함수 호출 vs 시스템 콜

일반적인 함수 호출: 사용자 프로그램 내에 존재하는 코드를 실행하는 것

시스템 콜: 사용자 프로그램이 아닌 운영체제라는 별개의 프로그램에 cpu를 넘겨서 실행하는 것. cpu를 운영체제에 넘기기 위해 시스템 콜은 인터럽트와 동일한 메커니즘, 즉 cpu의 인터럽트 라인을 세팅하는 명렁을 사용함.

 

5. 인터럽트

CPU는 매번 프로그램 카운터(program counter)가 가리키는 곳에 있는 명령을 수행하는 일밖에 하지 않기 때문에, 다른 일을 시키려면 인터럽트 매커니즘이 필요하다. cpu는 pc가 가리키고 있는 지점의 명령을 하나씩 수행하고 나서, 다음 명령을 수행하기 전에 인터럽트 라인을 체크한다. 인터럽트 라인 체크를 통해 인터럽트가 발생했는지 유무를 파악하고 발생했다면 cpu는 현재 수행하던 프로세스를 pcb에 저장한 뒤 멈추고 인터럽트 벡터, 인터럽트 처리 루틴으로 이동해서 인터럽트를 처리하고 마치고 나면 인터럽트가 발생하기 직전의 프로세스에게 cpu 제어권이 넘어가게 된다.

인터럽트 처리 중 우선순위가 더 높은 인터럽트가 발생한다면? 원칙적으로는 데이터의 일관성이 해쳐질 수 도 있기에 인터럽트 처리 중에 또다른 인터럽트가 발생하는 것을 허용하지 않는다. 그렇지만 모든 일에는 예외가 있는 법이고 인터럽트마다 중요도가 다르기 때문에 상대적으로 낮은 중요도를 가진 인터럽트 수행 중에 우선순위가 더 높은 인터럽트가 발생한다면 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트를 처리한 뒤 끝나면 저장된 주소로 복귀하여 상대적으로 낮은 우선순위를 가진 인터럽트를 마저 수행한다. 

 

6. 시스템 콜

시스템 콜이란 자신의 프로그램이 아닌, 커널이라는 다른 프로그램의 주소 공간에 존재하는 함수를 호출하는 것이다. 일반적인 함수호출이 자신의 스택에 복귀 주소를 저장한 수 호출된 함수 위치로 점프하는 것이다. 그러나 시스템콜은 프로그램 자신이 인터럽트 라인에 인터럽트를 세팅하는 명령을 통해 이루어진다. 프로그램이 스스로 인터럽트 라인을 세팅하는 점만 다를 뿐 일반적인 인터럽트의 발생과 동일한 방법이라 할 수 있다. 일반적인 인터럽트는 하드웨어 인터럽트로 디바이스 컨트롤러가 세팅하지만 시스템 콜은 소프트웨어 인터럽트로 프로그램 자신이 인터럽트 라인을 세팅한다. 

프로그램이 cpu를 할당받고 명령을 수행하다가 중간에 cpu를 빼앗기는 경우는 크게 두 가지가 있다. 하나는 타이머에 의해 인터럽트가 발생하는 경우이고, 다른 하나는 입출력 요청을 위해 시스템 콜을 하는 경우이다. 입출력 작업은 시간이 오래 걸리기 때문에 입출력 작업을 하는 동안 cpu는 다른 사용자 프로세스에게 넘어가게 된다. 입출력 작업이 완료되어 컨트롤러가 인터럽트를 발생시키면 그 때 다시 cpu를 잡을 수 있는 권한을 소유하게 된다. 

디스크 파일 i/o를 통해 시스템 콜 사용의 예를 살펴보자면 먼저 사용자 프로그램이 사용자 모드에서 cpu를 잡고 수행하던 중 파일을 디스크에서 읽어와야 할 경우 시스템 콜을 한다. 이것을 하여 인터럽트 라인에 인터럽트를 세팅하면 cpu는pc가 가리키는 intruction을 하나 수행한 뒤 다른 intruction을 수행하기 전에 인터럽트 라인을 체크하는데 이 때 인터럽트 라인에 인터럽트가 들어와있으므로 cpu는 커널 모드로 전환되고 cpu는 운영체제에게 이양된다. 운영체제는 인터럽트라인을 읽고 인터럽트 처리 루틴으로 이동하여 디스크 컨트롤러에게 파일을 읽어오라는 명령을 내린다. 그러나 i/o작업은 시간이 오래 걸리므로 완료될 때까지 기다리면 cpu가 놀고 있게 된다. 따라서 cpu는 다른 프로세스에게 넘어가며 디스크 컨트롤러가 로컬 버퍼에 파일을 다 읽어오면 인터럽트를 발생시켜 작업의 완료를 알린다. 그럼 다시 cpu는 커널 모드로 넘어가서 인터럽트 처리 루틴으로 가고 메모리에 로컬버퍼의 내용을 복사한다. 그리고 아까 i/o를 요청했던 프로세스는 cpu를 기다리는 큐에 줄서게 되고 cpu는 아까 디스크 컨트롤러가 발생시킨 인터럽트 때문에 작업이 끊겼던 프로세스로 돌아간다. 이 때 i/o 작업이 완료되었다고 바로 cpu를 획득할 수 있는 것이 아님을 명심해야 한다.

 

7. 프로세스의 두 가지 실행 상태

 

사용자모드와 커널모드를 통해 프로그램이 수행되는 과정

프로세스 A가 cpu에서 실행되고 있다고 하면 자신의 주소 공간에 정의된 코드를 실행하는 것과 커널의 시스템 콜 함수를 실행하는 것으로 나누어 볼 수 있는데, 전자를 사용자모드에서의 실행상태(user mode runnint)이라 명칭하며, 후자를 커널 모드에서 실행상태(kernel mode running)이라 한다.

이때 프로세스 A가 커널모드에서 실행 중인 상황이더라도, 시스템 콜이 수행되는 동안 커널이 실행 상태(running state)에 있다고 하지 않고, 프로세스 A가 실행 상태에 있다고 말한다. 왜냐하면 사실 커널이라는 명칭 자체가 항상 메모리에 올라가 있는 운영체제 부분을 가리키는 말이기 때문이다. 또한 프로세스 A입장에서는 Cpu를 운영체제 커널에 빼앗긴 것으로 생각할 수도 있지만 커널의 코드가 사실상 프로세스 A가 해야할 일을 대행하는 것이기 때문에 시스템 콜이 실행중일 때에도 여전히 프로세스 A는 실행 중인 것으로 간주한다는 것이다.

정리하자면 프로그램이 시작되어 종료될 때 까지 다양한 함수 호출을 하며 실행되는데, 이를 사용자모드와 커널모드의 실행 상태로 구분 지을 수 있다. 사용자 정의함수/라이브러리 함수를 호출할 때에는 모드의 변경 없이 사용자 모드에서의 실행을 지속하고, 커널 함수를 호출할 때는 시스템 콜을 하여 커널 모드로 진입해 커널의 주소공간에 있는 함수를 실행한다. 시스템 콜의 실행이 끝나면 다시 사용자모드로 복귀해서 시스템 콜 이후의 명령들을 계속 실행한다. 프로그램의 실행이 끝날 때에는 커널 모드로 진입해 프로그램을 종료한다.