날씨가 정말 더워요 ㅠ
게시판이 너무 썰렁하기도 해서 질문 올립니다. ㅋ
kernel stack은 각 프로세스마다 가지고 있는 것으로 알고 있습니다.
그리고 kernel이 가지고 있는 함수를 사용하면 항상 이 kernel stack을 사용하는 것으로 알고 있습니다. (인터럽트도 마찬가지구요)
그렇다는 것은 context_switch()함수도 kernel stack에 쌓인 다는 것이겠지요.
context_switch()함수는 매번 커널 모드에서 유저모드로 돌아갈 때 마다 need_sched 변수가 1로 세팅 되어있을 때,
또는 disk I/O같은 요청을 했을 때, wait(), read(), write() 같은 함수를 수행 할 때 내부적으로 호출 하는 것으로 알고 있습니다.
문제는 context_switch()함수에서 하는 다음의 일련의 과정들입니다.
1. save current PCB(process control block)
2. select next process
3. load next PCB
4. return(context_switch()함수 호출 한 곳으로 리턴, 커널의 어느 함수 일듯)
여기서 1. save current PCB 과정에서 현재 수행중인 프로세스의 rgisters 는 아마도 현재 프로세스의 kernel stack에 저장될 것 같은데요
(생각입니다. kernel stack도 PCB의 일부라서 저장되니깐요)
그것을 제외 하더라도 가장 궁금한점은 PC의 값의 save와 load 과정입니다.
현재 수행중인 프로세스의 레지스터들을 선택적으로 save하고 load하는 과정이 아키텍처마다 다르다면 이해하기가 어려울 것 같지만,
질문의 요지는 PC(program counter)값이 context_switch()함수 내에서 save가 된다면, 나중에 실행될 때 context_switch()함수내에서 시작하게 될 것 같습니다. 제 생각이 맞는 건가요?
그럴 것 도 같은 이유는 kernel stack의 내용 또한 save 되고 load 됩니다.
커널모드에서 sys_read()함수에서 I/O 요청 후 context_switch()함수를 호출 한다면, 현재 프로세스는 preempt당하고
(여기서 kernel stack에는 sys_read()함수와 context_switch()함수에 대한 local 변수, 리턴 주소와 같은 정보가 들어 있을 것이고, register와 마찬가지로 save와 load될 것 입니다..)
나중에 다시 수행시 context_switch()함수에서 깨어나서 sys_read()함수로 리턴되어(kernel stack에서 pop해서) 나머지 작업 수행 후(?), 유저모드로 복귀 할 것입니다. 복귀장소는 read()함수 다음 instruction이겠지요.
너무 깊게 생각한건가요?;;
아키텍처마다 다를 수 있기 때문에 더 정확히는 커널 소스를 분석하면 알 수 있을 듯 합니다.
그래도 한번 같이 토론했으면 해서 올려봅니다:D
그럼 내일 봐요 :D
* 인텔기반으로 설명한 context_switch() 함수 : http://galaxyra.linuxstudy.pe.kr/galaxyra/tag/switch_to
댓글 11
-
홍문화
2011.05.27 19:23
-
홍문화
2011.05.27 23:45
다시 생각 해보니 이거 좀 어려운데요. ㅋㅋㅋ
좋은 주제인거 같습니다. 다른 멤버님께서 해결좀 해주세요. ㅋ
-
유경환
2011.05.29 13:51
이종인님 덕분에 공부했네요 ^^ 검색해보니 이종인님 생각이 거의 완벽하게 맞아들어가네요. 좋은 질문 감사합니다.
-
이종인
2011.05.29 19:44
인텔 아키텍처 간단하게 설명한 자료나 책 없을까요? ;; 어렵네요 ㅠ..
-
홍문화
2011.06.01 22:35
이종인님과 유경환님 덕분에 컨텍스트 스위칭의 짜릿한? 맛을 보고 있습니다. ㅋㅋㅋ
유경환님께서 올려주신 자료를 시작으로 슬슬 몸을 풀어볼까 합니다. ㅋ
인터넷을 뒤적인 결과 TSS(task state segment)가 범용 레지스터, 세그먼트 셀렉터 등
태스크의 컨텍스트 정보를 저장하는 104 바이트의 자료구조라는 것을 알게 되었습니다.
태스크마다 하나씩 존재하구요. 파워포인트 자료 3페이지를 보면 TSS 내의 tss->esp0가
커널 스택의 시작 주소를 포인트 하는 것처럼 보입니다. 또한 오른쪽의 레지스터들이
tss->esp0을 시작으로 하는 커널 스택에 저장 되는 것처럼 보입니다.
그림을 놓고 볼 때 시스템 콜로 커널 모드로 진입 할 때 유저모드에서 사용하던 컨텍스트
정보 들이 커널 스택의 베이스에 저장되는 것으로 보입니다. 만일 그렇다면 시스템 콜에 의해
커널 모드로 진입 한 순간 tss->esp0을 시작으로 하는 커널 스택에 저장 되는 유저모드 컨텍스트
정보와 TSS에 저장되어 있는 컨텍스트 정보가 어떤 차이가 있는지 궁금합니다. 커널 스택에
유저모드 컨텍스트 정보를 저장하는데 TSS도 구지 같은 정보를 저장 할 필요가 없을것 같거든요.
그리고 TSS는 태스크마다 유일하므로 tss->esp0를 통해 각각의 태스크별로 존재하는 커널스택의
베이스 주소에 접근하는것으로 보이는데 맞는것인가요?
완벽한 답변을 바라는 것은 아니구요. 같이 고민해서 조금이나마 정답에 접근하고자 하는 바람에
질문 드립니다. ^^;
-
유경환
2011.06.02 10:35
1. 태스크의 컨텍스트 정보를 저장하는 104 바이트의 자료구조라는 것을 알게 되었습니다.
>> OK
2. 태스크마다 하나씩 존재하구요.
>> 아닌것으로 보입니다. 문서 보시면 "CPU i's TSS" 라고 첫 페이지에 나와 있습니다.
http://en.wikipedia.org/wiki/Task_State_Segment, http://onestep.tistory.com/31 를 보시면
오직 커널만 접근할수 있는 메모리 특정영역 이라고 나와있고요 종합해보면 TSS는 인텔 아키텍처에
의존적인 CPU 별로 current task 정보를 저장해 놓는 메모리 특정영역으로 보입니다.
3. TSS 내의 tss->esp0가 커널 스택의 시작 주소를 포인트 하는 것처럼 보입니다.
>> OK
4. 오른쪽의 레지스터들이 tss->esp0을 시작으로 하는 커널 스택에 저장 되는 것처럼 보입니다.
>> OK
5. 그림을 놓고 볼 때 시스템 콜로 커널 모드로 진입 할 때 유저모드에서 사용하던 컨텍스트
정보 들이 커널 스택의 베이스에 저장되는 것으로 보입니다.
>> OK
6. 만일 그렇다면 시스템 콜에 의해 커널 모드로 진입 한 순간 tss->esp0을 시작으로 하는 커널 스택에 저장 되는
유저모드 컨텍스트 정보와 TSS에 저장되어 있는 컨텍스트 정보가 어떤 차이가 있는지 궁금합니다.
>>
TSS 는 current task의 오직 유저스택에서 커널 스택으로 점프 하기위한 정보(register)를 저장해
놓는 공간으로 보입니다. 커널스택에는 커널스택에서 유저 스택으로 점프 하기위한 정보를 저장하구요.
즉 TSS정보는 (user to kernel stack), kernel stack은 (kernel stack to user stack) 인것이죠.
물론 커널 스택에도 context switching 시의 커널스택 상태를 가리키는 레지스터 값을 저장합니다.
그래서,대충 종합해보면 TSS는 user stack에서 커널 스택으로 점프할때의 오버헤드를 줄이기 위한
기법으로 생각됩니다.
-
홍문화
2011.06.03 21:26
먼저 답글에 감사드립니다. 일에 치여서 답글이 늦어졌습니다.ㅋ이번에 ARM 책 주문하면서 "만들면서 배우는 OS 커널의 구조와 원리"도
같이 주문 했는데 컨텍스트 스위칭에서 TSS가 어떤 역할을 하는지 잘 나와 있네요.
대강 읽어본 바로 TSS는 CPU별로 존재 하는것이 아니라 태스크 별로 존재 하는것으로 보입니다.
태스크마다 자신의 컨텍스트(레지스터) 정보를 자신만의 TSS에 저장 합니다. 이를 통해
컨텍스트 스위칭은 CPU의 레지스터 값과 TSS에 저장된 레지스터 값의 교환으로 달성 됩니다.
예를 들어 Task1 -> Task2로 전환이 되는 경우 CPU 레지스터 -> TSS1, TSS2 -> CPU 레지스터
과정을 거칩니다.
유저모드에서 커널모드로 넘어가는 경우는 컨텍스트 스위칭이 아니므로 커널 스택의 베이스 주소를
가져오는 용도등 여러 용도가 있을 수 있겠지만 커널 스택으로 점프할때의 오버헤드를 줄이기 위한
기법은 아닌것으로 판단 됩니다. 시스템 콜의 동작을 생각 해볼때 시스템 콜 번호를 레지스터에 저장
하고 소프트웨어 인터럽트를 발생 시킴으로 커널 모드로 넘어갑니다. 이후 시스템콜 테이블에서
시스템 콜 번호에 해당하는 엔트리의 함수를 호출하게 됩니다. 즉, PC(프로그램 카운터)는 TSS를
참고하는 것이 아니라 시스템콜의 흐름을 따라가게 될것입니다. 하지만 커널모드에서 시스템 콜 호출이
완료된 후에는 다시 유저모드의 이전 실행 흐름으로 넘어가야 하므로 커널 스택에 유저모드로 돌아갈
컨텍스트 정보가 반드시 있어야 할것입니다. 유저모드로 돌아갈때 컨텍스트 정보가 어떻게 복원
되는지 아직 파악을 못했습니다. 들어올때는 인터럽트로 들어왔는데 나갈때는 어떻게 나갈까요?
간단히 정리하자면 TSS는 커널모드 -> 유저모드와는 긴밀한 관계가 없으며 커널모드 -> 유저모드 시에는
커널 스택을 사용한다고 보는게 맞지 않을까 생각합니다.
TSS는 태스크간의 컨택스트 스위칭 시에 사용하는 자료구조라고 보면 될거 같습니다.
그리고 이종인님 말씀대로 컨텍스트 스위칭 시 수행되는 첫번째 코드는 이전에 컨텍스트 스위칭이 완료된
다음 코드가 맞는것으로 보입니다. "만들면서 배우는 OS 커널의 구조와 원리" 책은 다른 커널 책과는
상당히 다른맛이 있는것 같습니다. ㅋ
-
홍문화
2011.06.04 08:03
와우~ 감사합니다.
뒤에 그런 내용이 나오는군요.
방철호님 아니었으면 선무당이 사람 잡을 뻔했네요. ㅋㅋㅋ
김태훈님 블로그 읽었었는데 깜빡했네요.
일단 책을 자세히 읽어봐야겠네요. ^^;
-
방철호
2011.06.04 00:19
X86 팀인데 마침 만들면서 배우는 os 구조와 원리를 끝내고 나서 학습한 내용을 바탕으로 말씀 드리면
물론 테스크 스위칭을 TSS 를 두개를 태스크당 만들어서 태스크 스위칭을 진행하는 예제가 있었으나 이것은 커널 모드 상의두개의 태스크 스위칭에 대해서 하나의 예시로써 보여줬던 것이었고(이렇게 하면 CPU가 지원하는 하드웨어적 태스크 스위칭이 가능하나 사용하지 않는다고 나옵니다) 실제 뒷부분을 읽어 보시면 하나의 TSS만을 만들어서 유저모드와 커널모드의 전환이 일어났었습니다.
http://onestep.tistory.com/31 요기 내용을 읽어 보시면 리눅스에서는 TSS가 CPU 하나를 기준은 하나씩만 있다고 나오네요.
-
홍문화
2011.06.03 23:17
집에 오는길에 생각해보니 커널스택에 유저영역의 복귀 주소와 유저스택 주소를 제외하고는
딱히 저장할게 없지 않나 하는 생각이 들었습니다. 유저모드의 특정 스택에서 시스템콜을
통해 커널모드로 들어올때 시스템콜 매개변수들은 CPU 레지스터를 통해 전달이 될테고
크기가 큰 데이터는 copy_from_user() 함수로 복사가 되어 전달이 될테니 딱히 저장할게
없어보입니다. 그런데 ppt에는 왜 모든 레지스터들이 저장 되는것처럼 나와 있을까요?
제가 잘못 생각하고 있는건가요? 경환님 한수 부탁드립니다. ㅋ ^^;
-
홍문화
2011.06.05 01:01
오늘 유경환님과 저녁을 같이 하며 주고 받은 내용은 다음과 같습니다.
시스템콜이 시작 되기 바로 직전에 유저모드의 컨텍스트 정보를 TSS에 저장 합니다.
시스템콜이 수행되는 도중에 레지스터의 정보가 바뀌기 때문입니다.
커널모드에 진입한 후 TSS의 유저모드 컨텍스트 정보를 커널 스택에 저장합니다.
그리고 태스크 전환을 위한 컨텍스트 스위칭 동작을 수행합니다.
이때 struct mm_struct의 교환이 일어납니다.
마지막으로 커널모드의 컨텍스트 정보를 커널 스택에 저장하고
다음에 수행할 태스크의 컨텍스트 정보가 복원되면서 마무리가 됩니다.
복귀는 이과정을 거꾸로 수행한다고 보시면 됩니다.
이는 어디까지나 x86의 내용이었고 ARM은 또 어떻게 되는지 살펴봐야 되겠죠? ^^;
(잘못된 내용이 있다면 언제든 어느분이든 지적에 대환영입니다.ㅋ)
.
상당히 재미있네요. ㅋ
컨텍스트 스위칭을 하는 순간 PC는 컨텍스트 스위칭 코드의 주소를 가지고 있을테니
커널스텍에 저장되는 PC 값은 컨텍스트 스위칭 코드의 주소가 될거라는 말씀이시죠?
만일 이렇게 된다면 context_switch()함수가 마무리 되지 않은 상태에서 다른 태스크로
CPU의 제어가 넘어가는 이상한 상황이 될거 같네요.
context_switch()함수 내에서 저장하는 PC의 주소는 컨텍스트 스위칭 함수의 복귀 주소가
되어야 이치에 맞을거 같습니다. 이후 컨텍스트 스위칭 관련 함수가 모두 마무리 되고 나서야
선점을 하는 태스크로 CPU의 제어가 넘어가야 할거라고 봅니다.