last commit - Donate tests passed except priority-donate-lower/priority-donate-chain
헤더 파일과 소스파일을 동일한 소스파일에 include해서 빌드 자체가 실패함
(timer.c에서 thread.c와 thread.h를 동시에 include함)
헤더 파일만 정의.
헤더 파일과 소스파일을 같이 넣으면 안되는 이유
The key is to access the threads' priorities from the given semaphore_elems
구조체들을 정확하게 파악하고 있지 않아서
STRUCTURE
list_elem -> sema_elem -> sema -> waiter list -> thread -> priority
struct semaphore_elem *sema_elem_a = list_entry(a, struct semaphore_elem, elem);
struct semaphore_elem *sema_elem_b = list_entry(b, struct semaphore_elem, elem);
struct semaphore sema_a = sema_elem_a->semaphore;
struct semaphore sema_b = sema_elem_b->semaphore;
struct list *waiters_a = &sema_a.waiters;
struct list *waiters_b = &sema_b.waiters;
if(list_empty(waiters_a) == true)
return false;
if(list_empty(waiters_b) == true)
return true;
struct thread* t_a = list_entry(list_begin(waiters_a), struct thread, elem);
struct thread* t_b = list_entry(list_begin(waiters_b), struct thread, elem);
return t_a->priority > t_b->priority;
priority-sema는 pass하는데 priority-condvar는 실패했다.
테스트 결과를 확인해 보니까 정렬이 안되고 있는 점을 발견할 수 있었다.
struct semaphore_elem *semaElem_a = list_entry(a, struct thread, elem);
list_entry함수에서 두번째 매개변수로 구조체를 넣어줘야 하고 여기에 넣은 구조체가 리턴된다. 저장하고자 하는 변수의 구조체와 같게 맞춰줘야 했는데 thread 구조체로 잘못 넣어주고 있었다.
struct semaphore_elem *semaElem_a = list_entry(a, struct semaphore_elem, elem);
함수를 사용할 때 어떤 타입으로 리턴이 되는지 확인하자.
struct thread* t_a = list_begin(waiters_a);
여기서 생기는 문제는 list_begin은 list_elem 타입을 반환하는데 thread 구조체로 받고있다.
struct thread* t_a = list_entry(list_begin(waiters_a), struct thread, elem);
list_entry()함수로 감싸서 thread를 반환하게 하였다.
마찬가지로 함수를 사용할 때 어떤 타입으로 리턴이 되는지 확인하자.
list_begin(&waiters_a)
list_begin()의 정의를 보면 인자로 struct list * 를 받게 되어있고 waiter이라는 리스트도 포인터변수 이기 때문에 &waiters_a로 하게되면 더블포인터가 되버린다.
list_begin(waiters_a)
인자로 어떤 값을 넣어줘야 하는지 함수 정의를 잘 보고, 사용하는 데이터가 포인터 변수인지 일반 변수인지 잘 체크하자.
테스트 코드가 아래와 같았기 때문에 thread_set_priority 가 제대로 동작하지 않는다는 걸 알 수 있었다.
msg ("Creating a high-priority thread 2.");
thread_create ("thread 2", PRI_DEFAULT + 1, changing_thread, NULL);
msg ("Thread 2 should have just lowered its priority.");
thread_set_priority (PRI_DEFAULT - 2);
msg ("Thread 2 should have just exited.");
void
thread_set_priority (int new_priority) {
struct thread *curr = thread_current();
curr->priority = new_priority;
goback_priority();
test_max_priority();
curr->priority = new_priority;
이 코드는 원래 thread_set_priority함수에 있던 코드이다. 그래서 건드리지 않고 밑에다가 필요한 함수들을 적었었는데, 이 코드 때문에 앞에 패스했던 테스트들도 줄줄이 fail 했었다.
이 코드의 문제는 donation을 하고나서 생겼는데, 이유는 인자로 받은 새로운 priority를 donation을 받았을 수도 있는 priority 변수에 덮어 썼기 때문에 문제가 발생했다.
만약 priority가 30인데 set을 40으로 했었고 그 다음에 50을 donate받았다고 가정했을 때, 다시 돌아가야 하는 priority는 40이어야 하는데 이 코드 때문에 40이 아니라 30으로 돌아가게 된다.
간단하게 curr->pri_before_dona = new_priority;
이렇게 priority를 pri_before_dona로 해주면 된다.
당연한 코드는 없다. 기존의 코드라도 내가 바꾼 로직때문에 제대로 동작하지 않을 수 있으니 오류가 난다면 로직을 생각해서 함수의 흐름을 타고 모든 코드를 의심하자.
/ 기부 받기 전 priority /
int pri_before_dona;
/ 해당 스레드가 대기하고 있는 lock 자료구조의 주소를 저장할 필드 /
struct lock *lock_im_waiting;
/ 기부 해주신 스레드의 목록 /
struct list donor_list;
/ donor_list를 관리하기 위한 element 로 thread 구조체의 그냥 elem 과 구분하여 사용하도록 한다. /
struct list_elem donor_list_elem;