우리가 개발하는 프로그램은 일반적으로 User mode이다. 보통 User mode에서 Kernel model로 가는 경우는 프로그램 실행 중에 인터럽트(interrupt)가 발생하거나 시스템 콜(system call)을 호출하게 되면 커널모드로 전환된다. 여기서 시스템 콜이라는 단어가 나온다.
System Call은 커널이 자신을 보호하기 위해 만든 인터페이스이다. 커널은 사용자나 응용 프로그램으로부터 컴퓨터 자원을 보호하기 위해 자원에 직접 접근하는 것을 차단한다. 따라서 자원 이용시 System Call 인터페이스를 이용해야 접근이 가능하다.
자원 : 사용자가 컴퓨터자원에 직접 접근하는 방식으로, 사용자가 모든 것을 처리해야 한다. 이럴경우 자원을 자유 자재로 조작하는 것이 가능하지만, 잘못 건드리면 망가질 우려가 크다. 예를들면 커피머신을 직접 사서 조작하고 원하는데로 커스터마이즈 해서 추출한다. 하지만 커피머신을 망가뜨리거나 이상하게 쓸 수도 있다.
응용 프로그램 : 응용프로그램이 자기 마음대로 데이터를 아무 공간에나 저장할 수 있다. 이 경우 다른 사용자가 지울수 있고 나도 지울 수 있다.
자원 : 누군가에게 요청하여 작업의 결과만을 받는 방식이다. 예를들어 커피를 키오스크에서 시키고 그냥 커피를 받는 형식과 동일하다. 이 경우 머신이 망가지는 것을 예방할 수 있다.이처럼 운영체제는 사용자나 응용 프로그램이 하드웨어에 직접 접근하지 못하도록 막음으로써 컴퓨터 자원을 보호한다. 대신 하드웨어와 같은 시스템 자원을 사용할 수 있도록 인터페이스를 제공하는데 이것이 시스템 호출이다.
응용 프로그램 : 응용 프로그램이 직접 HDD에 저장하지 않고 커널이 제공하는 write() 함수를 사용하여 데이터를 저장요청을 통해 저장한다. 응용 프로그램은 데이터가 어느 위치에 어떤 방식으로 저장되는지 알 수 없다. 그리고 데이터를 읽을 때 read() 함수로 호출하여 데이터를 읽는다. System Call을 이용하면 커널이 데이터를 가져오거나 저장하는 것을 전적으로 책임져 컴퓨터 자원 관리가 좋다.
시스템 호출은 커널이 제공하는 시스템 관련 서비스를 모아놓은 것이며 함수 형태로 제공된다. 대표적인 예시로 C언어의 printf() 함수도 시스템 호출이다. 만약 저 함수없이 read를 하면 문자가 출력되는 위치가 겹치고,남의 문자를 지우고 하는 현상이 있을 수 있다.하지만 printf는 겹치는 일 없이 문자를 화면에 출력해준다.
그리고 원래 System Call이 없다면 절대 시스템 동작에 접근할 수 없지만 이를 Wrapping해서 사용하고 있는 것이다.
자바를 예로 들면 JNI(Java Native Interface)를 통해 OS에 접근할 수 있는 것이고 대표적인 예로 thread.start0이 있다. 이친구는 clone이라는 system call을 호출하게 된다.
System Call과 유사한 용어로 API, SDK(System Developer's Kit)가 있다. 쉽게 설명하면 운영체제의 API가 System Call이라고 한다.
프로세스와 스레드 게시물에 잘 설명되어있다.
대표적인 예시로 인터넷에 Cmd + N이 있다.
위와 같지만 요약하자면
동작 과정 자체는 간단하다. exec()을 호출하면 코드 영역에 있는 기존의 내용을 지우고 새로운 코드로 바꿔버린다. 또한 데이터 영역이 새로운 변수로 채워지고 스택 영역이 리셋된다. PCB에 내용 중 Process Identifier, 부모 구분자, 자식 구분자, 메모리 관련 사항은 변하지 않지만, 프로그램 카운터 테리저스터 값부터 각종 레지스터와 사용한 파일 정보가 모두 리셋된다. 이러면 프로세스를 마치 처음 시작하는것처럼 내용이 정리된다.
fork를 통해 생성된 자식 프로세스는 종료되면 부모 프로세스가 자원을 정리한다. 그런데 exit() system call로 부모 프로세를 자식 프로세스가 살아있을때 종료를 하면 자식 프로세스는 종료를 해도 돌아갈 곳이 없는데 이는 고아프로세스라고 부르낟. 이 프로세스는 운영체제가 자원회수로 정리를 해주겠지만 많이 발생하면 낭비가 됨은 틀림없다.
이를 위해 wait() System call이 있다. 이는 자식 프로세스가 종료되길 기다렸다가 끝나면 부모 프로세스가 계속 함수를 진행하는 것을 말한다. 이 때문에 wait() 함수는 부모 프로세스와 자식 프로세스의 동기화에도 사용된다.
예를들어 인터넷의 여러 창을 띄웠을때, 맨 앞창은 키보드와 마우스가 적용되지만, 뒤에 창은 적용되지 않는다. 이때 맨앞을 전면 프로세스(foreground process), 뒤를 후면 프로세스(background process)라고 부르는데 gui 뿐만 아니라 유닉스의 Shell에도 적용된다. 유닉스 셸에서
sleep 100 // 전면 -> 자식 프로세스에서 sleep100 수행
sleep 100& // 후면 -> 자식 프로세스에서 sleep100 수행하는데 다음 명령어 실행시 그냥 돌아옴
이라고 할 때 전면 프로세스는 100초동안 아무 작업도 수행할 수 없지만 후면 프로세스의 셸은 바로 다음 작업을 실행할 수 있다. 그리고 100초 뒤에 sleep 100이 끝난것을 알려준다.
전면 프로세스는 셸이 wait()함수를 사용한 반면 후면 프로세스는 wait()함수를 사용하지 않는다.