System Call
정의
- 응용 프로그램의 요청에 따라 커널에 접근하기 위한 call이다. 일반 응용 프로그램은 직접적으로 커널에 접근할 수 없다.
필요한 이유
- 특정한 작업은 해커가 시스템에 피해를 입힐 수도 있고 초보 프로그래머가 실수로 잘못 사용해서 시스템을 망가뜨릴 수 있다. 이를 예방하기 위해서 커널에서만 실행할 수 있는 작업을 따로 두고 있다.
- System Call을 통해서 응용 프로그램은 하드웨어 장치를 사용할 수 있고 각종 자원을 할당 받을 수 있고 각종 작업을 할 수 있다.
- 해당 system call이 적절한 system call인지 판단하고 적절한 system call이라고 판단되면 커널 모드로 진입한 후 필요한 작업을 한다.
사용되는 곳
- 프로세스 제어
- 프로세스 생성(create process)
- 메모리 할당 및 해제 : malloc, free
- 파일 조작
- 파일 생성, 파일 삭제
- 열기, 닫기
- 읽기 쓰기
- 장치 관리
- 장치를 요구, 장치 방출
- 읽기, 쓰기, 위치 변경
- 정보 유지
- 시간과 날짜의 설정과 획득
- 시스템 데이터의 설정과 획득
- 응용 프로그램이 사용자 모드(user mode)에서 실행중이다.
- 응용 프로그램이 하드디스크, 입출력 장치 등 자원이 필요해지면 system call을 호출한다.
- 커널 모드로 전환되고 필요 자원이 반환 된다.
- 다시 사용자 모드로 전환되고 응용 프로그램이 계속 실행된다.
여러 system call
fork
- 프로세스를 생성하고자 할 때 fork 함수를 사용하면 된다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t pid;
int x = 1;
pid = fork();
if(pid == 0){ /*Child*/
printf("child: x=%d\\n", ++x);
exit(0);
}
/*Parent*/
printf("parent: x=%d\\n", --x);
exit(0)
- 자식 프로세스는 fork값을 0으로 받는다. 반면 부모 프로세스는 fork값으로 자식 프로세스의 pid를 받는다.
- os는 똑같은 2개의 프로그램이 동작한다고 생각하고 fork()가 return될 차례라고 생각한다. 그래서 자식 프로세스도 if문으로 바로 들어간다.
- print되는 순서는 cpu 스케줄링 순서에 따라서 다르다. 즉 실행마다 print순서가 다르다.
wait
- child 프로세스가 종료될 때까지 기다리는 작업
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
printf("pid : %d", (int) getpid()); // pid : 29146
int rc = fork(); // 주목
if (rc < 0) {
exit(1);
} // (1) fork 실패
else if (rc == 0) { // (2) child 인 경우 (fork 값이 0)
printf("child (pid : %d)", (int) getpid());
}
else { // (3) parent case
int wc = wait(NULL) // 추가된 부분
printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
}
}
- wait를 통해서 child 프로세스의 실행이 끝날 때까지 기다린다. 즉 출력 순서가 항상 동일하다.
exec
- 단순 fork는 동일한 프로세스의 내용을 여러 번 동작할 때 사용한다.
- child에서는 parent와 다른 동작을 하고 싶을 때 exec를 사용한다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
printf("pid : %d", (int) getpid()); // pid : 29146
int rc = fork(); // 주목
if (rc < 0) {
exit(1);
} // (1) fork 실패
else if (rc == 0) { // (2) child 인 경우 (fork 값이 0)
printf("child (pid : %d)", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); // 내가 실행할 파일 이름
myargs[1] = strdup("p3.c"); // 실행할 파일에 넘겨줄 argument
myargs[2] = NULL; // end of array
execvp(myarges[0], myargs); // wc 파일 실행.
printf("this shouldn't print out") // 실행되지 않음.
}
else { // (3) parent case
int wc = wait(NULL) // 추가된 부분
printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
}
}
- execvp 이후 코드가 실행되지 않는다. 즉 print되지 않는다.
- exec함수를 호출한 프로세스의 메모리 영역에 실행파일의 바이너리 이미지가 그대로 쓰여진다. 즉 기존 부모 프로세스는 소멸된 것으로 이해할 수 있다.
커널(kernel)
정의
- 운영체제에서 프로세스에 자원 할당, 프로세스 제어, 메모리 제어, 시스템 콜 등을 다루는 부분
- 커널은 운영체제에서 중요한 부분이므로 메모리에 올라가서 상주하게 된다.
- 보안, 자원관리, 추상화
cpu 모드
- 커널모드, 사용자모드 구분은 cpu 내부의 mode bit를 사용한다.
사용자 모드
- 애플리케이션 코드가 실행되는데 이때 하드웨어에 접근할 수 없다. system call을 통해서 커널 모드로 전환돼야 하드웨어 자원을 사용할 수 있다.
커널 모드
- 하드웨어 등 각종 자원을 접근할 수 있게 된다.
참고 - https://hongong.hanbit.co.kr/운영체제란-커널의-개념-응용-프로그램-실행을-위한/
'cs > Operating System' 카테고리의 다른 글
| 프로세스와 스레드(process and thread) (0) | 2023.04.18 |
|---|