分析了一下Mission 1中的代码,现在我们来开始正式实现。
首先,给线程结构体 struct thread{}加上ticks_blocked成员,在threads/thread.h中
/* Record the time the thread has been blocked. */ int64_t ticks_blocked;
在线程创建的时候,ticks_blocked应该被初始化为0,在threads/thread.c中,找到thread_create()函数,添加如下代码:
/*Set default ticks_blocked = 0*/ t->ticks_blocked = 0;
修改timer_sleep()函数:
/* Sleeps for approximately TICKS timer ticks. Interrupts must be turned on. */voidtimer_sleep (int64_t ticks){ if (ticks <= 0) { return; } ASSERT (intr_get_level () == INTR_ON); enum intr_level old_level = intr_disable (); struct thread *current_thread = thread_current (); current_thread->ticks_blocked = ticks; thread_block (); intr_set_level (old_level);}
在这里我们调用了一个thread_block()函数,在threads/thread.c中修改:
/* Puts the current thread to sleep. It will not be scheduled again until awoken by thread_unblock(). This function must be called with interrupts turned off. It is usually a better idea to use one of the synchronization primitives in synch.h. */voidthread_block (void){ ASSERT (!intr_context ()); ASSERT (intr_get_level () == INTR_OFF); thread_current ()->status = THREAD_BLOCKED; schedule ();}
然后,修改时钟中断处理函数,找到devices/timer.中的timer_interrupt()函数,添加代码
thread_foreach (blocked_thread_check, NULL);
这里的thread_foreach()函数,即对每个函数都执行blocked_thread_check(),在threads/thread.c中修改。
/* Invoke function 'func' on all threads, passing along 'aux'. This function must be called with interrupts off. */voidthread_foreach (thread_action_func *func, void *aux){ struct list_elem *e; ASSERT (intr_get_level () == INTR_OFF); for (e = list_begin (&all_list); e != list_end (&all_list); e = list_next (e)) { struct thread *t = list_entry (e, struct thread, allelem); func (t, aux); }}
最后,给thread添加一个blocked_thread_check()方法:
先声明
void blocked_thread_check (struct thread *, void * UNUSED);
然后在thread.c中添加:
/* Check the blocked thread */voidblocked_thread_check (struct thread *t, void *aux UNUSED){ if (t->status == THREAD_BLOCKED && t->ticks_blocked > 0) { t->ticks_blocked--; if (t->ticks_blocked == 0) { thread_unblock(t); } }}
这里又修改了一个thread_unblock()函数,作用是将线程丢到ready队列中:
/* Transitions a blocked thread T to the ready-to-run state. This is an error if T is not blocked. (Use thread_yield() to make the running thread ready.) This function does not preempt the running thread. This can be important: if the caller had disabled interrupts itself, it may expect that it can atomically unblock a thread and update other data. */voidthread_unblock (struct thread *t){ enum intr_level old_level; ASSERT (is_thread (t)); old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); list_push_back (&ready_list, &t->elem); t->status = THREAD_READY; intr_set_level (old_level);}
这样一来,timer_sleep()的唤醒机制我们就实现了,将更改过的代码push上去。
中间发现自己犯了几个小错误,fix bug之后才跑通。
具体的代码可以在我的Github中找到。