PintOS: Operating System as OrcheStra
PintOS 첫 주, thread 코드를 읽었다. 함수 하나하나는 어렵지 않았다. 어려운 건 함수 사이였다. 이 함수는 왜 여기서 멈추는가. 멈춘 스레드는 어디로 가고, 누가 다시 깨우는가. 흩어진 답을 모으려고 흐름을 지도로 그렸고, 다 그린 지도를 들여다보다 눈을 감았다.
연주가 들렸다. 스레드는 각자의 선율을 가진 연주자, timer interrupt는 박자를 새기는 메트로놈, scheduler는 다음 소리를 고르는 지휘자.

지도가 답한 첫 질문은 "스레드는 지금 어디에 있는가"였다. 실행 중이면 RUNNING, CPU 위의 단 하나다. 실행할 수는 있지만 차례가 아니면 READY로 ready_list에 선다. 실행할 수 없으면 BLOCKED가 되어 필요한 곳에 머문다. 깨어날 시각을 기다리면 sleep_list, lock을 기다리면 sema의 waiters. 상태는 속성이 아니라 위치였다.
두 번째 답은 잠드는 규칙이었다. thread_block()은 스레드를 그냥 멈추는 게 아니라 실행의 흐름에서 빼내는 함수다. 그래서 잠들기 전에 반드시 어딘가에 등록되어 있어야 한다. 아무 데도 적히지 않고 잠든 스레드는 누구도 깨울 수 없다. sema_down()이 현재 스레드를 waiters에 적은 뒤에야 thread_block()을 부르는 이유다. thread_block() 자신은 왜 잠드는지 모른다. 자신을 잠재운 쪽이 깨울 자리를 마련해 뒀으리라 믿을 뿐이다.
깨어날 때도 같다. thread_unblock()은 스레드를 READY로 만들 뿐, 실행은 scheduler가 정한다. 퇴장은 서로를 믿고, 입장은 지휘자가 정한다.
박자는 timer interrupt가 새긴다. 매 tick, 실행이 아주 잠깐 멈춘다. 시간을 세고, 깨어날 시각이 된 스레드를 sleep_list에서 깨우고, 너무 오래 실행된 스레드에게는 양보를 예고한다. 어떤 스레드도 이 박자 바깥에서 무한히 실행될 수 없다. 그 믿음들 위에서 schedule()이 다음 스레드를 고르고, do_iret()으로 CPU를 넘긴다. 이전 실행이 끝나는 정확히 그 지점에서, 다음 실행이 시작된다.

코드가 흐름이 되고, 흐름이 질서가 되는 순간이 있다. 그 질서에 이름을 붙이려다, 답이 처음부터 철자 안에 있었다는 걸 알았다.
OrcheStra. 대문자만 남기면, OS다.