switch_to()에서 세번째 파라미터 "last" 는 필요한건가요?

hyungpower의 이미지

kernel 2.6.16.20를 가지고 공부하고있는데요, switch_to()에서 막혀서 질문합니다.

 15 #define switch_to(prev,next,last) do {                                  \
 16         unsigned long esi,edi;                                          \
 17         asm volatile("pushl %%ebp\n\t"                                  \
 18                      "movl %%esp,%0\n\t"        /* save ESP */          \
 19                      "movl %5,%%esp\n\t"        /* restore ESP */       \
 20                      "movl $1f,%1\n\t"          /* save EIP */          \
 21                      "pushl %6\n\t"             /* restore EIP */       \
 22                      "jmp __switch_to\n"                                \
 23                      "1:\t"                                             \
 24                      "popl %%ebp\n\t"                                   \
 25                      :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
 26                       "=a" (last),"=S" (esi),"=D" (edi)                 \
 27                      :"m" (next->thread.esp),"m" (next->thread.eip),    \
 28                       "2" (prev), "d" (next));                          \
 29 } while (0)

위에 보이는것처럼 "last"는 eax 레지스터를 사용하면서 output으로써 쓰이는거 같은데.. eax register는 또한 "2" (prev) 를 통해서 input으로도 쓰이구요(__switch_to에 eax 레지스터를 통해서 넘겨주는거 같습니다)
어쨌든 그렇다면 저 "last"변수는 쓰이는것이 아무것도 없는게 아닌거 같은데요? 무언가 이해를 잘 못했다거나 먼가를 빠트린거 같은데 아직 확실치가 안네요.. 굳이 last 인수를 받아서 쓰여져야 할필요가 있는건지, 필요가 없는거 아닐까요?
더군다나 switch_to()를 부르는 context_switch()도 prev와 next만 넘겨주던데요..

1580 static inline
1581 task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)
1582 {
...
1599         /* Here we just switch the register state and the stack. */
1600         switch_to(prev, next, prev);
1601 
1602         return prev;
1603 }

다른데 암만 찾아보아도 이 last에 대해서 자세히 설명된게 없어서요.. 있더라도 옜날 코드로 설명된거만 있어서요..
혹시 아시는 분은 답글좀 자세하게 달아주시면.. 사례는 업지만.. :(
제발요.. 꼭 좀...

thyoo의 이미지

히라씨의 해석 페이지

http://www.excite.co.jp/world/korean/web/?wb_url=http://hira.main.jp/wiki/pukiwiki.php?switch_to%28%29%2Flinux2.6

http://kldp.org/node/71854
___________________________________
Less is More (Robert Browning)

___________________________________
Less is More (Robert Browning)

bird0303의 이미지

switch_to 매크로에서

prev, last는 같은 프로세서 디스크립터 입니다.

그래서 같은 변수이지요.

그런데 굳이 prev, last를 써서 구분한 이유는

의미상 prev는 switch 되기전의 상태를

last 는 switch 된 후의 상태를 나타내려는 것입니다.

"=a" (last) 대신에 "=a" (prev)를 넣어도

의미가 같은 매크로 입니다.

LiNUX 정복하는 그날까지...

LiNUX 정복하는 그날까지...

headbang의 이미지

설명의 편의를 위해 프로세스 A에서 B로 태스크 스위칭되는 상황이라고 가정합니다.

결론부터 말하자면 switch_to()에서 (Kernel mode) 스택이 바뀌는데 이로인해서 switch_to() 이후에 "교체되는 프로세스는 A이다"라는 정보를 잃지 않기위한 꼼수입니다. schedule() 함수를 뒤져보면 context_switch()의 반환값인 교체되는 프로세스 A의 process descriptor (struct task_t)를 prev 변수에 저장한 뒤

finish_task_switch(this_rq(), prev)

reacquire_kernel_lock(prev)

이런식으로 쓰는 것을 알 수가 있습니다.


자세히 설명하자면, switch_to() 에서

movl %5,%%esp\n\t" /* restore ESP */;

위 라인에 의해서 ESP에는 next->thread.esp 값이 들어갑니다. 즉, ESP는 더이상 A의 stack을 가르키지 않고 B의 stack을 가르키게 됩니다.

context_switch() 인라인 함수에서 변수 prev와 next는 스택에 저장되는 automatic variable 입니다. 따라서 switch_to() 진입하기 전의 상황을 정리하자면 다음과 같습니다.
가. ESP, EBP는 A의 커널 모드 스택을 가르킨다. (EBP, ESP의 역할과 차이는 programming language 수업때 모두 배우셨다고 가정하겠습니다.)
나. A의 커널 모드 스택에 저장되어 있는 prev와 next는 각각 A와 B의 process descriptor를 가르킵니다.

switch_to() 에서 스택이 바뀐 직후의 상황을 정리하자면 다음과 같습니다.
가. ESP는 B의 커널 모드 스택을 가르킨다.
("popl %%ebp\n\t"; 이 명령을 통해 EBP도 B의 커널 모드 스택을 가르킨다.)
나. B의 커널 모드 스택에 저장되어 있는 prev와 next는 각각 B와 C의 process descriptor를 가르킨다.
프로세스 C는 프로세스 B가 가장 최근에 태스크 스위치 당했을때의 다음 프로세스를 나타냅니다. 따라서 이 시점부터는 prev에 교체된 프로세스인 A의 descriptor 정보가 올바르게 저장되어 있지 않습니다.

여기서 input operands와 output operands를 설명하자면,
가. "2" (prev) --- input operands; switch_to()에 진입할 때 prev를 EAX에 로딩, 즉 프로세스 A의 descriptor를 EAX에 로딩
나. "=a" (last) --- output operands; switch_to()를 빠져나갈때 EAX값을 last 변수에 저장, 즉 프로세스 A의 descriptor를 프로세스 B의 스택의 last 변수에 저장
또한 context_switch()에서 switch_to(prev, next, prev); 이런 식으로 호출했으므로 prev가 last가 됩니다.

따라서 swithc_to()를 빠져나간 직후의 상황을 정리하자면 다음과 같습니다.
가. ESP, EBP는 프로세스 B의 커널 모드 스택을 가르킨다.
나. prev와 next는 각각 A와 C의 process descriptor를 가르킵니다.
- next에는 C라는 쓰레기 값이 저장되지만 이 값은 쓰이지 않으므로 무시해도 됩니다.
- prev에는 프로세스 A의 descriptor값이 올바르게 남아있게 됩니다.

결국 switch_to()에서 쓰는 꼼수를 정리하자면
- input operators를 지정하여 이전 프로세스인 A의 descriptor를 EAX 레지스터에 로딩한뒤
- output operators를 지정하여 EAX 값을 다시 다음 프로세스인 B의 커널 모드 스택에 위치한 prev 변수에 저장하게됩니다.

headbang의 이미지

질문에 직접적인 답을 하지 않고 돌려서 이야기했군요.

last는 굳이 쓰여져야 할 필요가 없을 것 같군요.
switch_to(prev,next) 만으로도 동작은 제대로 할 것 같습니다.
하지만 스택이 바뀐 후 prev의 가상 주소가 달라지는걸 환기시키기 위해 따로 둔게 아닐까 추측됩니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.