유저 모드 스레드 질문

gpminsuk의 이미지

유저 모드 스레드가 이해가 안되서 질문드립니다.

일단 제가 이해하는 데까지만 설명드리면

커널 모드 스레드는 Ring0 Privilege에서 구현되는 스레드고

일정한 Time Slice마다 일어나는 interrupt에 의해 컨텍스트 스위칭 되는 것으로 이해하고 있습니다.

유저 모드 스레드는 Ring3 Privilege에서 구현되고 Ring0에서는 알지 못하는 스레드이라는 것까지는 알겠습니다만,

유저 모드에서 어떻게 컨텍스트 스위치를 하는건지 모르겠네요..어떻게 유저 모드에서 Execution Context를 다른 스레드로 넘길 수 있는건지요?

유저 모드 스레드의 장점은 커널 모드로의 스위칭이 일어나지 않기 때문에 속도 향상이 있다고 알고 있는데요,

커널 모드로 들어가지 않고 컨텍스트 스위치가 가능한건가요?

goforit의 이미지


>유저 모드 스레드는 Ring3 Privilege에서 구현되고 Ring0에서는 알지 못하는 스레드이라는 것까지는 알겠습니다만,

Privilege 구조는 CPU 마다 다릅니다. Ring을 얘기하니 x86 계열의 CPU것이라 생각됩니다.

>유저 모드에서 어떻게 컨텍스트 스위치를 하는건지 모르겠네요..어떻게 유저 모드에서 Execution Context를 다른 스레드로 넘길 수 있는건지요?

System call을 부르면 결국은 Software IRQ를 발생 시켜 모드가 스위칭됩니다.
즉 유저 모드 스레드가 System Calld을 부르면 주동적으로 모드 스위치 (가령 Ring 3 -> Ring 0 ) 시킬 수 있습니다.

>유저 모드 스레드의 장점은 커널 모드로의 스위칭이 일어나지 않기 때문에 속도 향상이 있다고 알고 있는데요,

기본적으로 모드 변경은 process/cache 의 flush 을 수반합니다. 이 것은 시스템 성능에 영향을 줍니다.
따라서 되도록이면 "자주" 변경하지 않는 것이 중요합니다.

>커널 모드로 들어가지 않고 컨텍스트 스위치가 가능한건가요?

아뇨, 이 부분을 바꾸어서 얘기하면 system call 사용하지 않고 컨텍스트 스위치가 가능한가 물어 보는 것입니다.

gpminsuk의 이미지

네, x86 계열의 CPU를 얘기한 것입니다.

말씀하신게 이해가 잘 안되네요..

정리하자면..

1. 유저 모드 라이브러리의 장점이 커널 모드로의 스위칭이 일어나지 않는다
2. 커널 모드로의 스위칭이 없이는 컨텍스트 스위치가 불가능하다.

그러므로 유저 모드 스레드 라이브러리는 컨텍스트 스위치가 불가능하다

컨텍스트 스위치가 불가능한데 어떻게 스레드가 있을 수 있는가?

pynoos의 이미지

컨텍스트는 말 그대로 실행문맥입니다. 실행의 관점을 커널에서만 보면 프로세스의 현재 상태인 범용레지스터, 스택, 힙, 각종 시그널 핸들러, 메모리 맵, 오픈 파일디스크립터 등등이겠죠... 하지만 일부를 공유하면 실행이라는 관점을 축소할 수 있고 이를 쓰레드라할 수 있습니다. 일부를 공유하는 스케쥴은 비교적 구현이 쉽(?)기 때문에 운영체제가 지원하기 이전부터 쓰레드의 개념이 존재해 왔습니다. 그러다가 운영체제가 지원하면서부터 조금 복잡해지기 시작합니다.

구현에 따라 늘 다르지만, 실행하는 중에 강제로 다른 문맥으로 바꾸는 방법의 스케쥴이 있을 수 있고, 상호 협조적으로 문맥을 바꿀 수도 있습니다. 이른바 유저레벨에서의 쓰레드 구현은 대개 상호 협조적인 방식으로 전환됩니다.

예를 들자면, 유저레벨에서 파일 입출력이나 소켓 조작등의 시스템콜을 이용할 때, 운영체제가 제공하는 것에 앞서서 자체 제작된 스케쥴러가 먼저 현재 문맥을 평가하고 변경여부를 판단하는 방법으로 구현할 수 있습니다.

평가하고 변경하는 것은 대개 같은 프로세스내에서 setjmp, longjmp 조합을 사용하여 구현합니다.

익명 사용자의 이미지

이 분이 궁금해하는 건, 유저모드에서 커널 모드 시스템콜 호출 없이 스위칭을 어떻게 구현하냐는 얘기 같습니다.

가령 A 쓰레드에 아래와 같은 코드가 있을 때

mov eax, dword ptr [ebp+8]
add eax, 0x8

여기서 만약 위의 mov 를 실행한 후에 스위칭이 일어나려면 저 명령 실행 후에 다른 스위칭 관련 명령들이
실행이 되어야 하는데 유저 모드 쓰레드는 커널 상에선 쓰레드가 하나인데 쓰레드를 멈추는 시스템 콜도
사용할 수 없는데 어떻게 중간에 스위칭 명령이 끼어들어서 실행되는 걸 구현할 수 있냐는 얘기 같습니다.

gpminsuk의 이미지

제 질문을 정확하게 캐치하셨는것 같습니다.

감사합니다.ㅠㅠ

윗분이 말씀하셨듯이, preemtion이 아니더라도 상호 협조적 스케쥴링이라도 구현하려면 어떻게든 execution context를 스위치 해야되는데

시스템콜 없이 어떻게 하는지..

혹시 커널 단에서 알지 못한다는 말이 아니라, 스케쥴링만 유저 모드에서 이루어진다는건지. (커널에선 알고 있는 셈이죠)

아니면 컨텍스트 스위치 하는 시스템콜을 커널에서 제공해 주면 그것을 이용해서 구현하게 되는건지,

익명 사용자의 이미지

실제로 구현해 본것은 아니고 이론적으로 가능성있다고 생각만 하고 있는 거란걸 미리 밝혀둡니다.
실행 컨텍스트의 전환은 setcontext()/getcontext()/swapcontext()류의 함수들을 이용하면 유저레벨 내에서도 가능합니다. 또한 이것들을 이용할 스케쥴러는 SIGALRM 시그널 핸들러에서 구현해 두면 될 것으로 생각합니다.

goforit의 이미지

함수가 생소해서 소스 코드를 찾아 보았습니다.

리눅스 커널을 예를 들어 보면,

$ cd linux-kernel
$ git grep swapcontext

powerpc 말고는 setcontext()/getcontext()/swapcontext() 지원하지 않습니다.
즉 대부분 CPU는 지금 지원하지 않습니다.
그리고 powerpc는 system call로 등록되어있습니다.

arch/powerpc/include/asm/systbl.h:SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
arch/powerpc/include/uapi/asm/unistd.h:#define __NR_swapcontext 249
arch/powerpc/kernel/entry_32.S: .globl  ppc_swapcontext
arch/powerpc/kernel/entry_32.S:ppc_swapcontext:
arch/powerpc/kernel/entry_32.S: b       sys_swapcontext
arch/powerpc/kernel/entry_64.S:_GLOBAL(ppc32_swapcontext)
arch/powerpc/kernel/entry_64.S: bl      .compat_sys_swapcontext
arch/powerpc/kernel/entry_64.S:_GLOBAL(ppc64_swapcontext)
arch/powerpc/kernel/entry_64.S: bl      .sys_swapcontext
arch/powerpc/kernel/signal_32.c:#define sys_swapcontext compat_sys_swapcontext
arch/powerpc/kernel/signal_32.c:long sys_swapcontext(struct ucontext __user *old_ctx,
arch/powerpc/kernel/signal_64.c:int sys_swapcontext(struct ucontext __user *old_ctx,

매뉴얼을 보니,

man swapcontext

       SUSv2, POSIX.1-2001.  POSIX.1-2008 removes the specifications of makecontext() and swapcontext(), citing  portabil‐
       ity issues, and recommending that applications be rewritten to use POSIX threads instead.

이제 더 이상 사용되지 않는 것 같네요.

참조로 OS X에서는 사용되는 것 같습니다.

jick의 이미지

그냥 간단하게 현재 CPU에 있는 레지스터의 내용을 모두 메모리에 저장한 다음, 아까 저장해 뒀던 다른 쓰레드의 레지스터 내용으로 바꿔치기하면 되지요.

쉬운 건 아니고 어셈블리로 짜야 하지만 불가능할 이유는 없습니다.

(물론 커널에서 전혀 이런 일이 일어났다는 사실을 인식 못하기 때문에 아마도 pthread 관련 API와 섞어쓰면 각종 오묘한 사태가 일어날 것 같습니다만...)

gpminsuk의 이미지

그렇게 간단하게 되는건가요?

컨텍스트 스위치를 위한 cpu의 레지스터 접근이 유저모드에서 모두 허용이 되는가요?

jick의 이미지

Context = 유저 프로세스가 알고 있는 현재의 상태
= 유저 프로세스가 접근할 수 있는 레지스터의 값

유저 프로세스가 읽을 수는 있는데 쓸 수는 없는 변태적인 레지스터가 없는 한, 컨텍스트를 바꾸는 건 레지스터 값을 모두 바꿈으로써 가능합니다.

* 생각해 보니 thread-local variable 같은 경우 커널에서 fs(?) 레지스터를 바꿔줘야 하는 걸로 알고 있는데 이건 제대로 될지 잘 모르겠네요. 뭐 쓰레드 로컬 변수 안 쓰면 되겠죠. (이런 무성의한 답변이... -_-)

pynoos의 이미지

http://ftp.gnu.org/gnu/pth/

재밌는 인사이트가 많습니다.
전 본지가 족흠 오래돼서...

raymundo의 이미지

예전에 스레드 관련한 글에 아주 유익했던 링크가 있던 기억이 나서 뒤져봤습니다.
https://kldp.org/node/132332#comment-583687
이 답변글에 있는 링크 보시면 괜찮을 것 같습니다.

좋은 하루 되세요!

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.