Pintos Project 1: Alarm Clock에서 만난 문제들

이형준·2023년 5월 27일
0

TIL

목록 보기
30/37

처음 만난 PintOS 🖐️

대망의 PintOS 대장정의 막이 올랐다. 처음 만난 PintOS는 그야말로 높디높은 벽 그 자체. 지금껏 정글에서 만난 적 없는 거대한 분량의 코드의 양에 압도되었다. 코드들이 어떤 식으로 구성되어 있나 알아볼 틈도 없이, PintOS의 첫 과제, Alarm Clock을 시작하게 되었다.

Alarm Clock ⏱️

첫 과제 Alarm Clock은 timer_sleep() 을 개선하는 것이다. 기존의 timer_sleep()Busy Wait 방식으로, 이는 주어진 조건을 만족할 때 까지 다른 작업을 수행하지 않고 기다리는 것을 의미한다. 듣기만 해도 비효율적인 녀석인데, 이 녀석을 Sleep 방식으로 개선해 주어야 한다.

그렇다면 Sleep방식은 무엇일까? 조건을 만족할 때 까지 가만히 앉아 기다리는 Busy Wait 방식과는 다르게 Sleep 방식은 조건을 만족할 때 까지 해당 스레드를 재워놓고 다른 작업을 처리하다, 조건을 만족하면 스레드를 깨워주는 방식이다.

맞닥뜨린 문제 ⚠️

thread_unblock()t->status == THREAD_BLOCKED ASSERT를 통과하지 못했다. 간단히 설명하자면 재워놓은 스레드를 깨우려고 확인했는데, 해당 스레드가 자고 있는 상태가 아니라는 것. 우리 팀은 이 문제를 해결하기 위해 고군분투했는데, 아무리 찾아봐도 어디서 문제가 발생하는지 찾을 수 없었다. 내가 생각하는 코드의 흐름이 맞다면, sleep_list 에는 분명 잠들어 있는 스레드들만 들어가 있어야 했다.

결과적으로, 붙어 있는 코드 두 줄의 순서를 살짝 바꿔준 것으로 이 문제를 해결할 수 있었다. 대체 어떤 문제가 있었던 것일까?

답은 인터럽트 핸들링에서 오는 문제였다. 바꿔준 두 줄의 코드는 함수를 실행하는 함수였는데, 기존의 코드에서 먼저 실행되던 함수는 타임 인터럽트를 중지시켰다가, 다시 활성화시켜주는 부분을 포함하고 있었다. 이 녀석이 먼저 실행되면, 다음 함수를 실행하기 전에 타임 인터럽트가 활성화되어버렸다. 그 결과로 Global tick을 기준으로 척척 돌아가던 흐름이, tick 사이에 처리하지 못한 함수가 껴버리면서 원활하게 동작하지 못하게 된 것.

이러한 문제를 어떻게 찾았는가? 바로 가장 간단하고 강력한 디버그 도구, print 를 통해 찾아냈다. 함수의 흐름 사이사이마다 어떤 함수에 접근했고, 나갔는지 tick과 함께 출력해보았다. 그 결과 원하는 대로 흘러가지 않는 부분을 확인할 수 있었던 것! 역시 가장 원초적이고 강력한 디버깅 도구인 듯 하다. 특히나 이런 로우레벨에서는 더더욱. 앞으로 PintOS 프로젝트를 진행하면서 애용하게 되지 않을까? 😎

profile
저의 미약한 재능이 세상을 바꿀 수 있을 거라 믿습니다.

0개의 댓글