Process

Update:     Updated:

Category:

Tags:


UNIX Architecture

UNIX 시스템들의 전체적인 구조

image

  • UNIX는 multiple program, process 기반이지만 프로세스들이 모두 동시에 동작하지는 않음
  • 그렇다면 How to manage process using system call functions? -> Process control subsystem

  • 하드웨어 접근하기 위한 방법
    1. System call Interface(function) : c-library function로 구성된 OS 서비스
    2. Standard(user) library : 사용자가 사용하는 standard I/O library


File Subsystem

파일을 쉽게 찾고 접근할 수 있도록 보관 및 관리하는 체계. user 영역이 아닌 kernel 영역에서 동작한다.

image

  • Managing files and structures of file
  • Administering file/free space
  • Controlling access to files
  • Retriving data for users 등
  • Interact with set of system call functions

    -> open, close, read, write, stat, chown, chmod 를 통해 접근 가능


Buffer Cache

버퍼 캐시는 하드 디스크 <-> 메인 메모리 간의 속도 차이를 줄이기 위해 만들어졌다.

  • Interact with block I/O device drivers (데이터를 kernel로 보내거나 받기 위해)

    -> Block I/O devices : hard disk. tape unit, USB camera 등


Buffer Cache 사용하는 이유

파일을 하드 디스크에 출력한다고 하자. 그러나 디스크 드라이버에 엑세스하는데는 시간이 굉장히 오래 걸린다. 여기서 버퍼 캐시는 파일을 임시로 저장해두어서 하드 디스크 디바이스에 엑세스를 최소화하기 위해 사용된다. (Standard I/O 버퍼: 파일의 임시 저장소 역할, 시간을 단축시킨다는 점에서 유사)


Virtual Memory vs. Buffer Cache 차이점

가상 메모리는 사용자를 위해 메인 메모리의 용량을 가상으로 확장하는 “기술”이고,

캐시 메모리는 최근에 엑세스 한 데이터를 임시로 저장해두는 “저장 장치”로, CPU가 데이터에 빠르게 엑세스 하도록 한다.


Process Control Subsystem

  • responsible for process synchronization
  • Interprocess communication (Synchronous/Asynchronous)
  • Memory Management 프로세스 간 메모리 공유
  • Interact with File subsystem
  • System call functions for process control : fork, exec, exit, wait, brk, signal


Lifetime of a Unix Process

하나의 프로세스가 시작하고 종료하는 전체적인 과정

image


Process Start

프로세스 시작 과정 : exec(2) 시스템 함수 호출 -> C startup routine 실행 -> main function 호출

image

  • C Start-up Routine : kernel로부터 argument랑 environmental variable를 받아서 메인 함수 호출
  • Main() 함수 : entry point of program

      int main(void);
        
      // argc : number of arguments,  *argv[]* : array pointer to argument
      int main(int argc, char *argv[]);   
        
      // envp[] : environment variable pointer 
      int main(int argc, char *argv[], char *envp[]);
        
    


Process Termination

프로세스 종료는 사용자의 의도에 따라 정상 종료와 비정상 종료로 나뉜다.

프로세스 종료 과정 : atexit(3)로 함수 호출 -> 열려있는 스트림 버퍼 모두 출력(flush) -> 열려있는 스트림 버퍼 모두 닫기(close) -> tmpfile(3)로 생성한 임시 파일 삭제(unlink) -> _exit(2) 호출 후 완전히 종료

Normal Termination 정상적인 종료

  • return from main() : 메인 함수에서 리턴 값을 받는 경우
  • exit(3) : standard library function, 프로세스 종료 with cleanup process

      #include <stdlib.h>
      void exit(int status);  // returns no value 
    
  • _exit(2) : system call function, 프로세스 종료 without cleanup process

      #include <unistd.h>
      void _exit(int status);   // returns no value
    

    -> 프로세스를 즉시 종료시키기 때문에 return 값이 존재하지 않음

    -> 프로세스가 정상적으로 종료되었는지 확인하는 방법 : status 인자를 이용

  • atexit(3) : standard library function, 직접 함수의 포인터를 exit handler로 등록 가능

      #include <stdlib.h>
      int atexit(void (*function)(void));   // return 0, error -1
        
      // 등록하는 함수의 입력과 출력 parameter 모두 void여야 함 
    

    -> 프로세스 종료 이전에 등록한 함수를 호출한 후, _exit(2)로 종료

    -> 직접 함수를 등록해서 나만의 exit handler 구현, 같은 함수를 여러 번 등록 가능

    -> 함수를 stack(FILO)에 저장하기 때문에 reverse order로 실행


    ex. doatexit.c : 등록한 역순으로 함수를 출력하는 예시 image



Abnormal Termination 비정상적인 종료

  • abort(3): 프로세스가 비정상적인 상태에 도달했을 때, 프로세스 강제 종료

      void abort(void);
    


Process Environment


프로그램 내에서 변수는 크게 environment, global, local variable로 구분된다.

환경 변수는 프로그램이 실행되는 환경을 저장하는 변수로, 프로세스를 실행할 때 참조된다. shell은 내부 명령어의 경우, 스스로 실행하여 출력하지만, 내부 명령어가 아닐 때는 PATH 환경변수에 지정된 경로에서 같은 파일을 찾아 실행한다.


Environmental Variable in Shell

  • env : 현재 프로세스에서 사용되는 모든 environment variable를 확인하는 명령어

    -> env 명령어를 통해 확인한 현재 내 터미널에서 사용되는 환경 변수들

    image

  • 부모 프로세스의 환경 변수는 새로운 자식 프로세스에 상속
  • bash 설정 파일 (환경변수를 저장하는 파일)

    .bashrc: non-login shell에서 사용할 환경 변수 저장 -> 로그인한 상태에서 새로운 터미널

    .bash_profile : login shell에서 사용할 환경변수 저장 -> ssh 접속, GUI를 통한 shell 실행


Environmental Variable in C

  • How is environmental variable designed (C code 안에서)

    image

  • C code에서 환경 변수를 사용하기 위한 기본 Setting

    환경 변수를 저장할 array pointer메인 함수 argument가 필요

      int main(int argc, char **argv, char **envp); 
      // need third argument! : environmental variable에 접근할 수 있다는 의미 
        
      extern char **environ; 
      // need to store environmental variable in array of pointer
      // last element of array: null character
    
  • getenv(3), putenv(3), setenv(3), unsetenv(3) :

      #include <stdlib.h>
        
      char *getenv(const char *string);  // return value if found, NULL otherwise
        
      int putenv(char *string); // "name=value"
      int setenv(const char *name, const char *value, int overwrite);
      int unsetenv(const char *name);  
      																	// return 0, -1 on error
    


    -> putenv vs. setenv 차이점

    putenv는 환경변수의 name이 이미 존재할 때, 이전의 정의는 자동적으로 삭제

    setenv는 환경변수의 name이 이미 존재할 때

    • overwrite이 != 0인 경우, 기존의 정의를 지우고 항상 새로운 값으로 overwrite

    • overwrite이 = 0인 경우, 기존의 정의를 지우지 않고 값이 그대로 유지 (에러 없이 반환)

    ex. env_man.c : 라이브러리 함수로 환경변수를 설정하고 출력하는 코드

    image

    출력된 결과 : 프로그램 안에서 값을 변경했지만, 터미널에서는 TERM 값이 바뀌지 않고 출력

    image

    -> 값이 바뀌지 않은 이유 : 프로그램을 실행하면 현재 쉘에서 새로운 child 프로세스를 생성해서 실행하게 된다. child 프로세스는 항상 기존 parent 프로세스의 모든 환경변수를 상속 받기 때문에 이 안에서는 변수들에 대한 접근과 변경이 가능하지만, 변경한 사항들이 parent 프로세스까지 적용되지는 않기 때문이다.


Control Flow

Process and Control Flow

프로그램은 명령어(instruction)들의 집합이고, 프로세스실행 중인 프로그램

Control Flow : 프로그램 시작부터 종료까지, 코드에 대한 instruction들을 하나씩 읽어가면서 각각에 해당하는 address를 가르키고 그 주소들을 하나씩 옮겨가면서 실행하는 일련의 명령어 실행 흐름

ex. CPU control flow

image

-> 명령어를 sequential하게 실행하는 CPU (if-else, 함수 호출로 인한 jump 제외)


Altering the Control Flow

Control Flow를 따르지 않고, CPU가 임의로 순서를 바꾸어 명령어를 실행해야 하는 경우도 있다.

Control Flow를 변형하는 사례

Program State Change System State Change
코드 안에서 특정 statement를 통해 상태가 바뀐 경우 외부의 장치에 의해 프로세스 상태가 바뀐 경우
변화에 대한 react 가능 변화에 대한 react 어려움
ex. Jumps and Branches (if-else, select), Call and Return ex. Instruction divides by zero, Ctrl+C 키, System timer expiration
  -> exceptional control flow를 위한 별도의 매커니즘 필요


Exceptional Control Flow

(= System State Change)

이러한 프로세스 변경 문제를 handle하기 위해, Control Flow에는 예외적인 몇 가지 상황이 정의되어 있다.

  1. Low-level mechanisms
    • Exceptions : 특정 system event가 발생했을 때, control을 OS kernel로 전송
  2. High-level mechanisms
    • Process Context Switch : OS가 timer를 통해 프로세스를 스위칭하는 경우
    • Signals : OS에 의해 특정한 시그널을 받고 프로세스를 종료하는 경우
    • Nonlocal jumps : C 라이브러리로 구현된 기능으로, 프로세스 바깥으로 이동하는 경우


Exceptions

Exception은 특정 이벤트가 발생할 경우, control을 프로그램에서 OS kernel로 전송하는 역할

(ex. divide by zero, arithmetic overflow, page fault, Ctrl+C 누르기, I/O 요청 완료)


Exception Handling

Exception이 발생하면 프로세스를 잠시 멈추고 kernel로 이동해서 예외를 처리한다.

image

  • 예외 처리 과정 : I_current의 명령어 실행 중 event 발생하면, I_current 프로세스를 잠시 멈추고 control flow를 커널로 이동시킨다. 그리고 exceptional handler 실행해서 exception 처리

  • Exception 종류에 따라 어떻게 프로세스로 돌아갈지 결정

    • Return to I_current : 이벤트로 I_current 명령이 올바르게 수행되지 않은 경우
    • Return to l_next : I_current의 명령을 올바르게 수행한 경우, 다음 명령어 실행
    • Abort : 이벤트가 치명적인 경우 프로세스 중단


Asynchronous Exceptions (Interrupts)

프로세서 밖에서의 이벤트로 인해 발생하는 exception으로, interrupt pin으로 수행된다.

CPU는 프로세스의 명령어를 순차적으로 수행하면서, 각각의 명령어를 수행한 직후 인터럽트 핀의 상태를 확인한다. 이때 인터럽트 핀의 값이 high인 경우, 프로세스를 중단하고 control flow를 kernel로 보낸다. 그리고 exception에 대한 처리를 해준 뒤 I_next로 이동해서 수행하던 프로세스를 진행한다.

  • Interruption Handling 과정

    image

  • Interrupt의 대표적인 예시
    • Timer Interrupt : 프로세서는 하나의 프로세스만 실행할 수 있어서, time sharing을 통해 정해진 시간동안 프로세스를 실행시킨다. timer가 다 되면 context switching을 통해 다른 프로세스로 교체한다. 이때 timer는 프로세스 바깥에 위치하기 때문에 인터럽트 핀을 통해 알림을 전달한다.
    • I/O interrupt from external device : 네트워크를 통해 값이 전달된 경우, 디스크 파일 입출력 연산을 요청했는데 완료되었다는 알림이 오는 경우, 프로세스 실행 중 Ctrl+C를 누르는 경우

  • Level of Interrupts

    다양한 하드웨어 디바이스가 인터럽트를 발생시키고, 각 디바이스 간의 속도 차이 발생

    image


Synchronous Exceptions

프로세스에서 명령을 실행하는 과정에서 생기는 이벤트로 인한 exception

  1. Traps (intentional)

    프로세스가 직접 system call을 호출하거나 이외의 방법으로 OS에 특정 명령어를 요청할 때 발생

    스스로 event를 만들어서 kernel로 control flow를 옮겨서 해당 system call에 맞는 명령어를 찾은 후, 필요한 값을 exceptional handler에 반환하면서 next instruction 수행

    ex. system calls, breakpoint traps, special instructions in OS

    trap.png

  2. Faults (unintentional but recoverable)

    의도적이지는 않지만 복구 가능한 이벤트로 발생하는 exception이다. 문제를 해결한 경우 current instruction를 실행하지만, 해결하지 못한 경우 프로세스를 중단시킨다.

    ex. page faults, protection faults, floating point exceptions

    fault.png

    Page Fault : user memory(DRAM)에 없는 일부 데이터(page)를 프로세스가 요청한 경우 발생

    -> kernel이 디스크나 SSD에 있는 데이터를 DRAM으로 옮겨준 후 다시 실행하면 정상적으로 작동

     int a[1000];
        
     main (void){       // recoverable page fault
         a[500] = 13;  
     }
            
     main(void){        // unrecoverable page fault 
         a[5000] = 13;  // invalid memory reference !
     }
    

    -> invalid address 요청 : segmentation fault로 종료, SIGSEGV signal 프로세스에 전송

  3. Aborts (unintentional and unrecoverable)

    의도하지 않았지만 복구하기 어려운 치명적인 이벤트에 대한 exception로, 프로세스를 바로 중단시킨다

    ex. 유효하지 않은 명령어 입력, parity 비트 오류 등

    abort.png



@Advanced Programming in the UNIX environment, Third edition 내용을 참고함

맨 위로 이동하기