Galvin의 저서 Operating Systems and Concepts에서 다음 내용을 읽었습니다.
"모드 비트라는 비트가 컴퓨터 하드웨어에 추가되어 현재 모드(커널(0) 또는 사용자(1))를 나타냅니다. 모드 비트를 통해 운영 체제를 대신하여 수행되는 작업과 그 모드를 대신하여 수행되는 작업을 구별할 수 있습니다. 하나를 사용하여 수행"
이제 다중 프로세서 시스템이라면 프로세스가 시스템 호출을 수행하고 모드 비트를 1에서 0으로 변경한다고 가정해 보겠습니다.
이제 다중 프로세서 시스템이므로 사용자 모드에서 다른 프로세스가 병렬로 실행될 수 있지만 모드 비트가 0으로 설정된 것은 커널 모드에서 불일치가 발생함을 의미합니다.
그렇다면 레지스터 수(모드 비트를 저장하는 데 필요함)는 프로세서 수에 따라 달라지나요?
답변1
당신의 책은 일을 지나치게 단순화시켰습니다. 실제로는 CPU가 모드를 어떻게 설정하느냐에 따라 달라지며, "비트"일 필요도 없고 단지 두 가지 모드일 필요도 없습니다.
이 질문에서는 Linux, Intel x86 및 멀티 코어를 가정합니다.
멀티태스킹은 Linux에서 소프트웨어 기반인 컨텍스트 전환을 통해 달성됩니다. 컨텍스트 전환은 단순히 프로세서가 수행 중인 작업(코어 또는 CPU)을 중지하고 해당 상태를 RAM에 저장한 후 다른 컨텍스트로 대체합니다.
x86은 프로세스 수준 실행이 발생하기 전에 각 프로세서에 설정할 수 있는 가드 링을 구현합니다. Linux 커널은 메모리 공간에서 실행을 시작하기 전에 프로세스를 링 3(권한 없음)으로 설정하여 이 문제를 처리합니다. 앞서 언급한 컨텍스트 스위치 구현을 통해 커널은 특정 스레드(보통 코어당 2개의 스레드, Intel)에서 실행되는 프로세스의 개념을 유지합니다. 왜냐하면 해당 프로그램 코드가 실행될 때마다 커널은 항상 링을 3으로 설정하기 때문입니다. 프로세서는 초당 여러 번 컨텍스트 전환을 수행하므로 많은 프로세스가 동일한 코어에서 실행됩니다. 하나 이상의 코어를 사용하여 본질적으로 동일한 방식으로 이를 수행할 수 있습니다.
x86 Linux에서 스레드가 링 3에서 링 0(하이퍼바이저)으로 전환하려는 경우 소프트웨어 인터럽트를 통해서만 전환할 수 있습니다. 링 1과 링 2에서는 특별한 지침도 사용할 수 있지만 Linux에서는 이를 구현하지 않습니다. Linux는 소프트웨어 인터럽트 핸들러를 제어하기 때문에 스레드가 이제 링 0에 있더라도 "커널 공간", 즉 동일한 스레드라도 커널의 일부인 코드만 실행하도록 보장할 수 있습니다. 사용자 공간 코드를 실행합니다. 운영 체제에서는 이것이 실제로 수행되는 작업이므로 시스템 호출이라고 합니다. 이것을 "프로세스"가 커널 모드로 전환했다가 다시 돌아가는 것으로 생각할지, 아니면 사용자 공간으로 다시 전환할 때까지 커널 공간 코드만 실행되기 때문에 프로세스가 실제로 일시 중단되는지 여부는 사용자에게 달려 있습니다.
x86에서는 높은 링에 있는 링이 낮은 링으로 전환할 수 있도록 허용하므로 인터럽트 처리기가 완료된 후 다시 3으로 전환할 수 있습니다. 이는 모든 시스템 호출에서 발생하므로 하드웨어 관점에서 볼 때 모든 시스템 호출은 시스템에서 무엇이든 할 수 있습니다. 프로그램의 모든 명령을 역순으로 실행한 다음 필요한 경우 메모리에서 모든 코드를 제거할 수 있습니다. 또는 링 0으로 전환하여 프로그램 시작 부분에서 실행을 시작할 수 있습니다. 보시다시피, 이러한 예제는 하드웨어에 "커널/사용자" 모드 개념이 없기 때문에 "커널/사용자" 모드 개념을 깨뜨립니다. 그러나 Linux에서는 항상 커널 공간에 대한 호출과 사용자 공간으로의 복귀로 구현됩니다(실제로 x86에서는 메모리가 링 0으로 보호되지 않습니다).
따라서 커널/사용자 모드 전환은 스레드 가드 링을 벗어나지만 커널 공간에서만 실행한 다음 사용자 공간으로 돌아가도록 구현되는 소프트웨어 인터럽트 핸들러, 특히 명령 사용자 공간 프로세스를 실행함으로써 달성됩니다. 시스템 호출이지만 링 3으로 돌아온 후에만 가능합니다.