X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fthread.c;h=6eda28032b397f109cba706769a12a97788e9302;hb=2cfc156c39840ce7f1cda6b473de1322691a8a0b;hp=e85bc164d172094839124f6e818f23c7946957e9;hpb=8382bdd7884a6d38f7529e0517dd9a7083f4ce73;p=pintos-anon diff --git a/src/threads/thread.c b/src/threads/thread.c index e85bc16..6eda280 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -41,6 +41,11 @@ struct kernel_thread_frame void *aux; /* Auxiliary data for function. */ }; +/* Statistics. */ +static long long idle_ticks; /* # of timer ticks spent idle. */ +static long long kernel_ticks; /* # of timer ticks in kernel threads. */ +static long long user_ticks; /* # of timer ticks in user programs. */ + static void kernel_thread (thread_func *, void *aux); static void idle (void *aux UNUSED); @@ -54,10 +59,11 @@ void schedule_tail (struct thread *prev); static tid_t allocate_tid (void); /* Initializes the threading system by transforming the code - that's currently running into a thread. Note that this is - possible only because the loader was careful to put the bottom - of the stack at a page boundary; it won't work in general. - Also initializes the run queue. + that's currently running into a thread. This can't work in + general and it is possible in this case only because loader.S + was careful to put the bottom of the stack at a page boundary. + + Also initializes the run queue and the tid lock. After calling this function, be sure to initialize the page allocator before trying to create any threads with @@ -86,15 +92,41 @@ thread_start (void) intr_enable (); } +/* Called by the timer interrupt handler at each timer tick to + update statistics. */ +void +thread_tick (void) +{ + struct thread *t = thread_current (); + if (t == idle_thread) + idle_ticks++; +#ifdef USERPROG + else if (t->pagedir != NULL) + user_ticks++; +#endif + else + kernel_ticks++; +} + +/* Prints thread statistics. */ +void +thread_print_stats (void) +{ + printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n", + idle_ticks, kernel_ticks, user_ticks); +} + /* Creates a new kernel thread named NAME with the given initial PRIORITY, which executes FUNCTION passing AUX as the argument, - and adds it to the ready queue. If thread_start() has been - called, then the new thread may be scheduled before - thread_create() returns. It could even exit before - thread_create() returns. Use a semaphore or some other form - of synchronization if you need to ensure ordering. Returns - the thread identifier for the new thread, or TID_ERROR if - creation fails. + and adds it to the ready queue. Returns the thread identifier + for the new thread, or TID_ERROR if creation fails. + + If thread_start() has been called, then the new thread may be + scheduled before thread_create() returns. It could even exit + before thread_create() returns. Contrariwise, the original + thread may run for any amount of time before the new thread is + scheduled. Use a semaphore or some other form of + synchronization if you need to ensure ordering. The code provided sets the new thread's `priority' member to PRIORITY, but no actual priority scheduling is implemented. @@ -140,9 +172,25 @@ thread_create (const char *name, int priority, return tid; } -/* Transitions a blocked thread T from its current state to the - ready-to-run state. This is an error if T is not blocked. - (Use thread_yield() to make the running thread ready.) */ +/* 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. */ +void +thread_block (void) +{ + ASSERT (!intr_context ()); + ASSERT (intr_get_level () == INTR_OFF); + + thread_current ()->status = THREAD_BLOCKED; + schedule (); +} + +/* 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.) */ void thread_unblock (struct thread *t) { @@ -226,20 +274,18 @@ thread_yield (void) intr_set_level (old_level); } -/* 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. */ +/* Sets the current thread's priority to NEW_PRIORITY. */ void -thread_block (void) +thread_set_priority (int new_priority) { - ASSERT (!intr_context ()); - ASSERT (intr_get_level () == INTR_OFF); + thread_current ()->priority = new_priority; +} - thread_current ()->status = THREAD_BLOCKED; - schedule (); +/* Returns the current thread's priority. */ +int +thread_get_priority (void) +{ + return thread_current ()->priority; } /* Idle thread. Executes when no other thread is ready to run. */ @@ -255,7 +301,8 @@ idle (void *aux UNUSED) thread_block (); intr_enable (); - /* Use CPU `hlt' instruction to wait for interrupt. */ + /* Use CPU `hlt' instruction to wait for interrupt. + See [IA32-v2a] "HLT" and [IA32-v3] 7.7. */ asm ("hlt"); } } @@ -281,7 +328,7 @@ running_thread (void) down to the start of a page. Because `struct thread' is always at the beginning of a page and the stack pointer is somewhere in the middle, this locates the curent thread. */ - asm ("movl %%esp, %0\n" : "=g" (esp)); + asm ("mov %0, %%esp" : "=g" (esp)); return pg_round_down (esp); } @@ -346,6 +393,10 @@ next_thread_to_run (void) the first time a thread is scheduled it is called by switch_entry() (see switch.S). + It's not safe to call printf() until the thread switch is + complete. In practice that means that printf()s should be + added at the end of the function. + After this function and its caller returns, the thread switch is complete. */ void @@ -377,7 +428,10 @@ schedule_tail (struct thread *prev) /* Schedules a new process. At entry, interrupts must be off and the running process's state must have been changed from running to some other state. This function finds another - thread to run and switches to it. */ + thread to run and switches to it. + + It's not safe to call printf() until schedule_tail() has + completed. */ static void schedule (void) {