대학교 다닐때는 놀다가, 지금에서야 여러 블러그 보면서 커널이 궁금해서 이곳까지 왔네요..
다음 스터디모집때는 참가해서 제대로 좀 공부 해봐야 겠다는 각오를 다지고 있구요...
각설하고, 제가 가진 의문은 이렇습니다. 시스템콜이 인터럽터인가????
일반적으로 시스템콜에 대해서 찾아보면 보통은 아래와 같이 설명이 나옵니다..
시스템콜 => S/W 인터럽터루틴내에서 시스템콜 테이블에서 호출됨...
이렇게 보면, 시스템콜은 일종의 인터럽터의 일종으로 봐도 무방할듯 합니다.
근데, 또, 어떤글을보니, 시스템콜은 인터럽터 루틴이 끝난후 호출된다고 합니다..( 출처는 기억이 안남. )
이럴때는 시스템콜은 인터럽터가 아니게 될꺼라고 생각이 들거든요..
시스템콜이 인터럽터가 맞냐? 아니냐? 이 차이가 굉장이 중요할거 같은데요.....
일반적인 쓰레드와 다르게 인터럽터는 자주발생할수 있기 때문에 스케줄러의 Context Switching대상이 아닌거 같고,
( 자주호출되는 말이 좀 이상하긴한데, 어쨌든, 클록 인터럽터라는 놈도 있고 ... )
때문에 인터럽터가 도중에는 스케줄러가 호출이 절대 안되는 거로 알고 있는데요.. ( 이게 비선점Kernel이라고 부르는거 같은데 )
시스템콜함수를 인터럽터로 보면 시스템콜을 심하게 잘못짜서 심하게 코드가 길거나 Block되면
실시간 반응성이 무자게 떨어지는 문제가 생길거 같거든요 ( 이때문에 선점형Kernel이 나오게 된거 같다고 생각이 듭니다. )
곧 인터럽터핸들을 짧고 간결하게 짜듯이 시스템콜 함수는 최대한 심플하게 짜야한다는 결론이....
반면에 시스템콜이 인터럽터가 아니라면, 시스템콜함수를 길게 짜거나 반응성이 느리게 짜도 별 문제가 되지 않을거 같아서,
좀더 복잡한 시스템콜을 만들수 있지 않을까 생각이 듭니다...
마지막으로, 선점형kernel 역시 백프로 개념을 못잡고 있는데요..
선점형커널은 인터럽터 도중에 인터럽터가 올수 있는데, 인터럽터가 몇번 nesting된 상황에서
클럭 인터럽터가 끝난후 스케줄러가 호출되었다고 치면, 인터럽터인 도중 상태에서 스케줄러가 Context Switching,
다시 복귀할때도 스케줄러 Context Switching에 의해서 원래 위치로 돌아온다는 말인데,,
이러면 일반루틴과 인터럽터루틴을 구지 구별해서 코딩할 필요가 없어질거 같거든요..
개념이 잘 안잡혀서 좀 혼란스럽네요.. 블러그 검색으로 알아보는것도 한계가 온거같고,,...
이런기초적인 지식도 없이 리눅스 소스코드 열어서 볼 용기도 나지않고,
주위에 커널 하는 사람이 아무도 없어서 물어볼 사람도 없고 답답한 마음에 글 남겨봅니다.
댓글 6
-
최형호
2014.08.16 21:48
-
장비익덕
2014.08.19 01:35
댓글 정말 감사합니다. 평소에 이것저것 보던 단어들이 이제서야 조립이 되어 머릿속에 들어와서, 의문점이 깔끔하게 해결되었습니다. 이번기회에 인터럽터와 스케줄러의 관계도 공부도 됐고, 비록 시스템 프로그래머는 아니지만 , 평상시 궁금했던거 끙끙거리다가 이제야 풀리니 정말 후련하군요 ※ -
최형호
2014.08.19 00:24
scheduling과 interrupt의 관계는 top & bottom으로 나누어서 설명이 가능합니다.
그런데 system call은 말그대로 user에서 kernel로 privilege권한의 변경만 있습니다.
그러므로 top & bottom으로 설명되지 않습니다.
제가 굳이 인터럽트와 시스템콜을 구별해서 답변을 단 이유가 이런부분에 있습니다.
일반적으로 exception이라는 좀더 상위 개념(x86은 아마 trap이라고도 사용하는것 같던데요)으로 보는게 맞습니다.
물론 system call을 위한 명령어 svc(혹은 swi)가 소프트웨어 인터럽트라는 용어로 사용이 되기 때문에 인터럽트라고 봐도 무방하긴 합니다.
그런데 일반적인 인터럽트는 예측하지 못한 타이밍에 발생을 하고(주기적인 timer interrupt라고 해도 항상 특정위치에 인터럽트가 발생하진 않음) 이를 처리할 때 보통은 current process의 stack을 이용합니다. nesting을 허용한다하더라도 기술적으로 하나의 stack에서 여러 인터럽트 처리하는것은 복잡하고 그에 따라 처리 시간도 복잡해집니다. 그렇기 때문에 일종의 scheduling이 이용가능한 task처럼 사용하기 위해 top & bottom 개념으로 나뉘어지게 됩니다. 즉, top half에서 인터럽트 처리 중 최소한 해야만 하는것을 처리하고 대부분의 처리는 bottom half에서 처리하는 것입니다.(workqueue등..)
단순하게 context 가 변경을 통해 privilege 와 unprivilege 간의 변경을 interrupt라고 한다면 시스템 콜을 인터럽트라고 할수있을 것입니다. 기술적으로 svc 명령어를 호출해 user에서 kernel mode로 변경되고 그리고 나서 system call table에서 해당 함수를 찾아서 바로 실행합니다. kernel mode에서 system call로 호출한 함수 처리 중에 다른 process에서 system call을 호출한다면 둘다 nesting되는 게 아닙니다. 각자의 process의 kernel stack에서 동작합니다. 이는 애초에 top & bottom으로 나누지 않아도 상관없이 scheduling을 사용할 수 있습니다. system call이 호출되었으니 interrupt를 lock을 걸고 그런 행위도 없습니다. 심지어 bottom half로 보내기 위해 workqueue등으로 queueing하는 행위도 아예 없습니다. 애초에 그렇게 구현자체가 된게 아닙니다.
애초에 interrupt와 유사하게 처리하는 녀석이 아닙니다. hw적으로 svc명령어가 interrupt라는 범주에 속할수있지만 sw적으로는 전혀 다르게 처리합니다.
그래서 이런 관점으로 봤을 때 interrupt처리와 전혀 다르므로 interrupt라고 말하긴 애매한 것 같습니다. 물론 hw관점에서 software interrupt라는 개념을 활용하지만 그 명령어만 단순하게 이용할 뿐이라고 생각됩니다.
-
장비익덕
2014.08.18 21:40
시스템콜이 인터럽트 처리 완료 후에 호출이 된다는 소리는 처음 듣습니다.
--> 이부분은 제가 top_half, bottom_half 구간의 차이를 제가 잘못이해한듯 싶습니다
top_half가 인터럽터 핸들부분이고, 인터럽터용어 대신에 인터럽터 루틴으로 바꾸어서 다시 보면...
인터럽트 루틴 처리 완료 후에 시스템콜 호출이 된다는 소리는 맞는소리가 될 수 있지도 않나요 ??
-
hanu
2014.08.18 05:06
리눅스 공부한지는 얼마 되지 않았지만 제 생각에는 시스템콜이 인터럽트에 속하는게 맞는것 같습니다.
인터럽트는 크게 두가지로 나뉘는데요
첫 번째는 외부 인터럽트, Timer나 Keyboard등의 CPU가 아닌 외부의 하드웨어에 의해 발생하는 인터럽트입니다. 따라서 CPU의 클럭과 동기화되지 않으며 보통 예측 불가능한 경우가 많습니다.
두 번째로는 내부 인터럽트, 소프트웨어에 의해 발생하는 인터럽트로 Trap이라고도 합니다. 0으로 나누거나 Page fault등의 예외처리등에서 발생합니다. 프로그램 내부에서 발생하므로 물론 CPU클럭과 동기화되어서 발생하게 됩니다.
시스템콜은 Linux x86같은 경우 eax에 인터럽트의 vector number를 넣고 0x80 인터럽트를 호출함으로서 발생시킵니다. 그럼 시스템은 인터럽트 핸들러로서 시스템 핸들러 함수를 호출하고, 해당 함수에서 eax값을 참조함으로서 원하는 시스템콜 함수를 호출하게 됩니다. 따라서 인터럽트중에서도 내부 인터럽트로 보는게 맞지 않을까 싶습니다.
덧붙여서 시스템콜이 인터럽트라고 하더라도 복잡한 시스템콜을 만들 수 있을것 같습니다. 인터럽트가 발생하면 인터럽트 핸들러가 호출되는데 글에서 적으셨듯이 인터럽트 핸들러가 길어지면 반응성등의 문제가 발생합니다. 따라서 이를 선처리와 후처리로 나누어서 선처리에서 핸들러에서 반드시 해야하는 일을 하고 조금 지체되어도 되는 일은 후처리로 넣어서 인터럽트가 활성화되고 cpu가 여유가 있을 때 수행하는 것으로 알고 있습니다. 이에 관해서는 bottom-half나 태스크릿, soft irq등으로 검색해보시면 됩니다.
예를 들어 네트워크 패킷을 받는 인터럽트 핸들러를 구현한다면 선처리에서는 패킷을 받았다는 신호를 보내고 버퍼를 비웁니다.(버퍼 오버플로우 방지) 그리고 패킷을 처리하는 부분은 시간에 비교적 덜 민감하고 오래 걸리는 작업이기 때문에 후처리로 미루어서 처리를 하게 됩니다.
다만 실제로 시스템콜이 이렇게 선처리 후처리로 나누어서 구성하는지는 부정확하니 한번 찾아보셔야할듯 합니다. -
장비익덕
2014.08.18 21:31
음 말씀하신대로, 찾아보니 top-half , bottom-half로 나눠지는 구간이 있네요.. 답변감사합니다... 정확한 개념은 아직 파악중인데, 개념잡기가 쉽진 않네요...
.
안녕하세요.
실컷 작성중에 다 사라져버렸네요@@
시스템콜은 svc라는 특수한 명령어를 이용해 user 에서 kernel로 진입해서 kernel 에 구현된 함수를 수행하는 것입니다. 그러므로 user mode에서 kernel mode로 변경되는 즉, context가 변경이 되어야 합니다. 이것은 현재 running 중인 process의 context를 저장하고 인터럽트가 수행되는 것과 유사합니다. 즉, 구현 나름이지만 인터럽트로도 구현은 가능할 것입니다. 하지만 일반적인 인터럽트라고 말하진 않습니다. 더구나 인터럽트는 언제 발생할 수 있을지 예측할수 없지만 시스템콜은 직접 이순간에 호출해야지 하고 호출하는 것입니다. 다만 공통점은 현재 context를 저장하고 다른 context를 수행한다는 것 뿐입니다.
일반적으로 software interrupt를 이용하는데 포괄적 개념으로 인터럽트라고 하지 저희가 일반적으로 말하는 인터럽트처럼 스케줄링 안되고 어쩌고..등과는 다릅니다. 인터럽트 보다는 exception이라는 용어가 더 맞을 것 같습니다.
아마 x86도 비슷하겠지만 arm도 software interrupt를 위한 명령어 swi를 사용하는데 이게 호출되는 순간 user mode에서 kernel mode로 hw에 의해 변경이 됩니다. 이렇게 kernel mode로 변경이 되면 시스템콜 테이블에서 해당 함수를 찾아서 호출된 시스템콜에 부합하는 함수가 수행이 됩니다.
시스템콜이 인터럽트 처리 완료 후에 호출이 된다는 소리는 처음 듣습니다. 일반적으로 인터럽트는 kernel mode에서 동작을 합니다. 즉, 이미 user에서 동작 중이던 process는 이미 선점당한것이죠. user에서 시스템콜을 호출하면 바로 kernel mode로 변경이 되고 해당함수가 kernel mode에서 수행됩니다. 이 때 인터럽트가 발생하면 당연히 발생한 인터럽트에 해당되는 인터럽트 서비스 루틴이 수행될 것입니다.
시스템콜을 일반적 관점의 인터럽트(다른 프로세스가 동작하지 않는 상태)의 관점에서 보면 인터럽트가 아닙다. 단순히 exception 즉, 모드 변경의 관점으로 보는게 맞습니다. 그러므로 반응성이 느려지거나 하는것은 별개의 문제입니다. 잠시 삼천포로 빠지자면, 일반적으로 ISR(인터럽트 서비스 루틴)이 길어지면 반응성이 떨어지므로 최소한의 것만 ISR에 구현하고 대부분은 커널 쓰레드 등을 이용해 처리하도록 합니다.
시스템콜은 unprivieged mode에서 privileged mode로 변경해서 kernel mode에서 함수가 수행되도록 하는 행위를 말합니다. 당연히 스케줄될수도있고 일반적인 인터럽트가 치고 들어올 수 있습니다.
프로세스(혹은 쓰레드)가 선점 할수도 선점될수도 있다는 말은 current task가 running중에 다른 task에게 뺏긴다는 것을 의미합니다. 일반적으로 a task가 돌고 있는데 a가 양보하지 않으면 어떻게 b가 돌 수 있을까요? 결국 인터럽트에 의해 b task가 깨어난다는 것을 의미합니다. 이때 a가 할당 받은 시간동안 동작한 후 b가 동작한다면 선점형이 아닙니다. 그런데 할당받은 시간을 다 사용하지도 못했는데 b가 실행이 되면 선점형이 되는 것입나.
리눅스 커널의 경우 a가 동작 중인데 인터럽트에 의해 b를 실행시키려 합니다. 이 때 선점형 리눅스가 아니면 커널은 인터럽트 처리 마지막에 b를 runqueue에 넣고 해당 인터럽트는 종료할 것입니다. 그리고 나서 나중에 a가 할당 받은 시간을 다 소비하면 다른 실행할 task를 선택할 것입니다. 이 때 타이머 인터럽트가 이용이 됩니다. 할당받은 시간이 다 소비될 때 타이머 인터럽트가 발생해서 다른 task를 runqueue에서 꺼내서 실행하는 것입니다.
그런데 선점이 지원이 되고 b가 a보다 우선순위가 높으면 최초에 b를 runqueue에 넣을 인터럽트가 발생하면 runqueue에 b를 넣고 인터럽트 처리 끝부분에 바로 b를 실행시킵니다.
인터럽트루틴에서 코드가 동작하면 반응성이 문제가 되겠죠 당연히 일반루틴과 구별이 되어야 합니다. 네스팅 인터럽트는 일반 스케쥴링과 다르게 분명한 한계가 있습니다.
주저리 주저리 적었는데 이해가 되셨는지 모르겠네요. 나름 최대한 간단하게 많은걸 생략하고 적었습니다. 이해가 안되시거나 제가 잘못 작성한게 있으면 답변 달아주세요