(6/2)
새벽 2시쯤 들어갔지만, 아침 챙겨먹고 9시에 다시 나왔다.
전날 팀원들과 같이 셋이서 열심히 디버깅을 했음에도 불구하고, 계속 무한에러가 반복됨에 따라 분한 마음으로 잠들었기 때문이다. 다소 피곤했지만, 꼭 버그를 잡고 말겠다는 다짐과 함께 강의실에서 도착하고 바로 노트북을 열었다.
그리고, 뭔가 찝찝했던 child_list 관련 코드들을 ctrl+F로 찾아가며 다시 살펴보기 시작했다. 에러 코드를 봤을 때, 분명 문제는 이 child_list 처리에서 발생하는 것 같았기 때문이다. 놀랍게도 어제는 발견하지 못했던 것이 바로 보였다. (이래서 잠을 충분히 자야하나보다,,,)
오류의 주인공은 위와 같다.
Project 1 때, list_begin 과 list_end 에 ready_list, sleep_list 등 다양한 리스트를 넘겨주기 위해서 & 를 앞에 붙여줬었다. 이번에도 습관처럼 & 를 붙여놨었는데, 그것이 문제였다. 이미 위에서 curr_child_list라는 포인터 변수에, &curr->child_list 로 올바르게 값을 넣어줬는데, 거기에 또 & 를 붙여줬으니... 자연스레 list_begin 을 통해 뽑아온 list_elem에는 이상한 값이 들어갔을 것이고, list_end 와의 비교도 정상적으로 수행되지 않았을 것이며, list_next도 제대로 처리를 못해줬을 것이다. 그러니 에러가 날 수밖에....!
list_begin과 list_end에 넘겨준 인자의 &을 각각 제거해 수정해주고 다시 테스트를 돌려본 결과, 프로젝트 1에 해당하는 18개의 테스트를 제외한 77개는 모두 FAIL이었는데, 결과가 그래도 26 FAIL 로 개선되었다. 전날 진짜 눈이 빠져라 들여다봐도 못 찾았었는데, 이렇게 아침에 나오자마자 찾게 되니까 조금은 허무했다. 그래도 찾아서 너무 다행이다.
이후엔, 어떤 부분에서 에러가 났는지 살펴보았다. 주로 read, write, close 가 개입하는 테스트가 FAIL로 나타난 것을 확인하고, 다른 팀의 코드와 비교해 순서가 잘못되었거나 누락한 부분을 찾아 2~3개 정도 수정 및 추가해준 결과, 또 다시 1시간 만에 다음과 같이 1 FAIL 까지 갈 수 있었다.
하지만 1 FAIL 이란 결과를 받고나니 오히려 심란해졌다. 도대체 이 하나를 어디서 잡지.......?
아까의 흥분은 사라지고, 다시 답답한 기분이 들었다.
아직 팀원들이 다 오지 않은 김에, 지난 금요일에 서울 올라가며 들었던 네이버 채용설명회에서 한 현직자 분이 추천해주신 글을 읽었다. (지난 목요일에 오셨던 협력사 CTO 분이 추천해주셨던 것 같기도 하고..... 🙇🏻♂️)
10배 이상 뛰어난 개발자가 되는 법 - Michael Lin
읽다보니, 초보 개발자가 저지르는 실수 2번째에 이런 내용이 나온다. '도움을 요청하지 않음'
동료에게 질문하면 5분 만에 해결될 간단한 문제임에도, 혼자 끙끙 앓으며 고민하는 것이 결코 정도가 아니라는 것이었다.
평소 알고리즘 문제를 풀거나 프로젝트를 진행할 때 가급적이면 스스로의 힘으로 해결하며 그 쾌감을 즐겨왔던지라, 이번에도 스스로 해결해보고 싶은 마음도 있긴 했다. 하지만, 이 글을 읽고 나서 과감히 도움을 요청해보기로 했다. 전날 이미 같은 문제를 겪었던 것으로 추정되는 동료가 뒷 조에 있었기에, 조언을 구해보는 것도 괜찮지 않을까란 생각이 들었기 때문이다. 그래서 그 친구가 강의실에 나오자마자 곧장 다가가서, 혹시 어제 1 FAIL이 떳던 것이 나와 같은 TEST 항목 (multi-oom) 이었는지 물었다. 아니나 다를까, 역시나 같은 경우였다.
혹시 어떤 부분에서 버그를 잡았는지 알려줄 수 있느냐고 했더니, 흔쾌히 우리 조의 코드를 함께 살펴봐주었다.
이 글을 통해 다시 한 번 감사의 인사를 드립니다....
문제가 된 부분은, 아래의 process_add_file이란 함수였다. 이 함수는, 파일 디스크립터 관련한 시스템 콜을 구현할 때 선언한 것이었다. (다음 글에서 나머지 시스템 콜을 정리하며 함께 언급할 것이다)
이 함수는 간략한 가이드(한양대 자료)만 보고, 다른 팀원들과 함께 직접 구현한 함수였다. 구현한 후에 다른 팀의 코드와 비교했을 때, 다들 while문으로 구현하긴 했으나 동작 로직은 완전히 같아보였다.
다만, 우리의 코드에서는 for 문 안의 if문에서 return을 하지 못하는 경우, curr->fd_idx를 갱신하지 않는다는 치명적인 오류가 있었다. 만약 한 차례 스캔을 했는데 빈 공간이 없었으면, curr->fd_idx를 FDCOUNT_LIMIT으로 갱신해놔주어야 한다. 그래야 위의 __do_fork 와 같이 fd_table이 가득 찬 경우에 에러 처리를 하는 함수들이 정상적으로 작동할 수 있기 때문이다.
따라서, for문에서 return이 이루어지지 않은 경우에 curr->fd_idx를 FDCOUNT_LIMIT(최댓값)으로 갱신하도록 수정해주었다. 수정해 준 결과, 이렇게 multi-oom.output에 찍히는 결과가 확연히 달라졌다. 아까는 무한루프에 걸렸나 싶을 정도로 너무 오랜 시간이 걸리더니, 이번엔 슉슉 지나가는 것이 왠지 통과할 것 같았다. 그 결과는 아래의 캡쳐본 하나로 설명을 대체한다. 이 맛에 코딩한다 😋
다행히도 구현을 일단은 잘 마쳤기에, 오늘은 저녁에 협력사 설명회가 끝난 후에 팀원들과 all pass 기념으로 가볍게 맥주 한 잔 하며 담소를 나눴다. 2주 전에 처음으로 팀이 됐을 때부터 꼭 마시자고 했는데, 오늘에야 마셨다:)
남은 extra 과제, 그리고 Project 3과 4도 다들 무탈히 이겨낼 수 있기를....🙏 그리고 파일 디스크립터 관련 시스템 콜도 얼른 정리해야지 !