summaryrefslogtreecommitdiffstats
path: root/threads/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'threads/thread.c')
-rw-r--r--threads/thread.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/threads/thread.c b/threads/thread.c
index 61ab5d9..cf404b6 100644
--- a/threads/thread.c
+++ b/threads/thread.c
@@ -379,12 +379,26 @@ thread_set_priority (int new_priority)
379void 379void
380thread_other_set_priority (struct thread *t, int new_priority) 380thread_other_set_priority (struct thread *t, int new_priority)
381{ 381{
382 enum intr_level old_level;
383 bool yield = false;
384
382 ASSERT (is_thread (t)); 385 ASSERT (is_thread (t));
383 ASSERT (new_priority >= PRI_MIN && new_priority <= PRI_MAX); 386 ASSERT (new_priority >= PRI_MIN && new_priority <= PRI_MAX);
384 387
385 if (t->priority == new_priority) 388 if (t->priority == new_priority)
386 return; 389 return;
387 390
391 /* we need to disable interrupts here because after changing the thread's
392 priority and a possible timer interrupt which triggers thread_yield() we
393 could run into a couple of races. e.g. no proper sorted ready list,
394 corrupt ready list (wrong internal pointers) or the timer interrupt fires
395 after calling list_empty() but before list_front() while having only two
396 threads (one active, the other one ready). the scheduler then schedules the
397 other thread which runs and terminates, thus removing itself from all lists.
398 after that our thread gets scheduled again and reads from an empty list,
399 although it wasn't empty before. */
400 old_level = intr_disable ();
401
388 t->priority = new_priority; 402 t->priority = new_priority;
389 403
390 if (t->status == THREAD_READY) 404 if (t->status == THREAD_READY)
@@ -398,8 +412,13 @@ thread_other_set_priority (struct thread *t, int new_priority)
398 /* compare priority with the highest priority in the list */ 412 /* compare priority with the highest priority in the list */
399 struct thread *t2 = list_entry (list_front (&ready_list), struct thread, elem); 413 struct thread *t2 = list_entry (list_front (&ready_list), struct thread, elem);
400 if (t2->priority > t->priority) 414 if (t2->priority > t->priority)
401 thread_yield (); 415 yield = true;
402 } 416 }
417
418 intr_set_level (old_level);
419
420 if (yield)
421 thread_yield ();
403} 422}
404 423
405void 424void