From 5fa7a9e2a12522684b0fbaa7d06555544563f124 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 16 Sep 2004 21:07:03 +0000 Subject: [PATCH] Invent tid_t data type and use it in many places where we current use struct thread *. Remove thread_name() argument. --- src/threads/synch.c | 3 +- src/threads/test.c | 12 +++--- src/threads/thread.c | 88 +++++++++++++++++++++++++++------------- src/threads/thread.h | 26 ++++++++---- src/userprog/exception.c | 3 +- 5 files changed, 85 insertions(+), 47 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 169128d..be8f0a5 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -111,14 +111,13 @@ static void sema_test_helper (void *sema_); void sema_self_test (void) { - struct thread *thread; struct semaphore sema[2]; int i; printf ("Testing semaphores..."); sema_init (&sema[0], 0, "ping"); sema_init (&sema[1], 0, "pong"); - thread = thread_create ("sema-test", sema_test_helper, &sema); + thread_create ("sema-test", sema_test_helper, &sema); for (i = 0; i < 10; i++) { sema_up (&sema[0]); diff --git a/src/threads/test.c b/src/threads/test.c index ccb2427..4c7bfed 100644 --- a/src/threads/test.c +++ b/src/threads/test.c @@ -25,7 +25,7 @@ struct sleep_thread_data int *product; /* Largest product so far. */ struct lock *lock; /* Lock on access to `product'. */ struct semaphore done; /* Completion semaphore. */ - struct thread *thread; /* Thread. */ + tid_t tid; /* Thread ID. */ }; static void sleeper (void *); @@ -63,14 +63,14 @@ test_sleep (int iterations) t->product = &product; t->lock = &lock; sema_init (&t->done, 0, name); - t->thread = thread_create (name, sleeper, t); + t->tid = thread_create (name, sleeper, t); } /* Wait for all the threads to finish. */ for (i = 0; i < thread_cnt; i++) { #ifdef THREAD_JOIN_IMPLEMENTED - thread_join (threads[i].thread); + thread_join (threads[i].tid); #else sema_down (&threads[i].done); #endif @@ -98,13 +98,11 @@ sleeper (void *t_) lock_release (t->lock); printf ("%s: duration=%d, iteration=%d, product=%d\n", - thread_name (thread_current ()), - t->duration, i, new_product); + thread_name (), t->duration, i, new_product); if (old_product > new_product) printf ("%s: Out of order sleep completion (%d > %d)!\n", - thread_name (thread_current ()), - old_product, new_product); + thread_name (), old_product, new_product); } /* Signal completion. */ diff --git a/src/threads/thread.c b/src/threads/thread.c index 1b56f98..5400f78 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -8,27 +8,29 @@ #include "threads/mmu.h" #include "threads/palloc.h" #include "threads/switch.h" +#include "threads/synch.h" #ifdef USERPROG #include "userprog/gdt.h" #endif -/* Value for struct thread's `magic' member. +/* Random value for struct thread's `magic' member. Used to detect stack overflow. See the big comment at the top of thread.h for details. */ -#define THREAD_MAGIC 0x1234abcdu +#define THREAD_MAGIC 0xcd6abf4b /* List of processes in THREAD_READY state, that is, processes that are ready to run but not actually running. */ static struct list ready_list; /* Idle thread. */ -static struct thread *idle_thread; /* Thread. */ -static void idle (void *aux UNUSED); /* Thread function. */ +static struct thread *idle_thread; -/* Initial thread. - This is the thread running main(). */ +/* Initial thread, the thread running init.c:main(). */ static struct thread *initial_thread; +/* Lock used by allocate_tid(). */ +static struct lock tid_lock; + /* Stack frame for kernel_thread(). */ struct kernel_thread_frame { @@ -39,6 +41,7 @@ struct kernel_thread_frame static void kernel_thread (thread_func *, void *aux); +static void idle (void *aux UNUSED); static struct thread *running_thread (void); static struct thread *next_thread_to_run (void); static struct thread *new_thread (const char *name); @@ -48,6 +51,7 @@ static void *alloc_frame (struct thread *, size_t size); static void destroy_thread (struct thread *); static void schedule (void); 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 @@ -63,10 +67,13 @@ thread_init (void) { ASSERT (intr_get_level () == INTR_OFF); + lock_init (&tid_lock, "tid"); + /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); init_thread (initial_thread, "main"); initial_thread->status = THREAD_RUNNING; + initial_thread->tid = allocate_tid (); /* Initialize run queue. */ list_init (&ready_list); @@ -77,31 +84,33 @@ thread_init (void) void thread_start (void) { - /* Create idle thread. */ - idle_thread = thread_create ("idle", idle, NULL); - idle_thread->status = THREAD_BLOCKED; - - /* Enable interrupts. */ + thread_create ("idle", idle, NULL); intr_enable (); } /* Creates a new kernel thread named NAME, 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. Use a - semaphore or some other form of synchronization if you need to - ensure ordering. */ -struct 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. */ +tid_t thread_create (const char *name, thread_func *function, void *aux) { struct thread *t; struct kernel_thread_frame *kf; struct switch_entry_frame *ef; struct switch_threads_frame *sf; + tid_t tid; ASSERT (function != NULL); t = new_thread (name); + if (t == NULL) + return TID_ERROR; + tid = t->tid = allocate_tid (); /* Stack frame for kernel_thread(). */ kf = alloc_frame (t, sizeof *kf); @@ -120,7 +129,7 @@ thread_create (const char *name, thread_func *function, void *aux) /* Add to run queue. */ thread_unblock (t); - return t; + return tid; } #ifdef USERPROG @@ -128,7 +137,7 @@ thread_create (const char *name, thread_func *function, void *aux) FILENAME, and adds it to the ready queue. If thread_start() has been called, then new thread may be scheduled before thread_execute() returns.*/ -bool +tid_t thread_execute (const char *filename) { struct thread *t; @@ -136,12 +145,14 @@ thread_execute (const char *filename) struct switch_entry_frame *ef; struct switch_threads_frame *sf; void (*start) (void); + tid_t tid; ASSERT (filename != NULL); t = new_thread (filename); if (t == NULL) - return false; + return TID_ERROR; + tid = t->tid = allocate_tid (); if (!addrspace_load (t, filename, &start)) PANIC ("%s: program load failed", filename); @@ -167,7 +178,7 @@ thread_execute (const char *filename) /* Add to run queue. */ thread_unblock (t); - return true; + return tid; } #endif @@ -190,12 +201,11 @@ thread_unblock (struct thread *t) intr_set_level (old_level); } -/* Returns the name of thread T. */ +/* Returns the name of the running thread. */ const char * -thread_name (struct thread *t) +thread_name (void) { - ASSERT (is_thread (t)); - return t->name; + return thread_current ()->name; } /* Returns the running thread. @@ -217,6 +227,13 @@ thread_current (void) return t; } +/* Returns the running thread's tid. */ +tid_t +thread_tid (void) +{ + return thread_current ()->tid; +} + /* Deschedules the current thread and destroys it. Never returns to the caller. */ void @@ -269,16 +286,17 @@ thread_block (void) static void idle (void *aux UNUSED) { + idle_thread = thread_current (); + for (;;) { - /* Wait for an interrupt. */ - DEBUG (idle, "idle"); - asm ("hlt"); - /* Let someone else run. */ intr_disable (); thread_block (); intr_enable (); + + /* Use CPU `hlt' instruction to wait for interrupt. */ + asm ("hlt"); } } @@ -336,9 +354,9 @@ static void init_thread (struct thread *t, const char *name) { memset (t, 0, sizeof *t); + t->status = THREAD_BLOCKED; strlcpy (t->name, name, sizeof t->name); t->stack = (uint8_t *) t + PGSIZE; - t->status = THREAD_BLOCKED; t->magic = THREAD_MAGIC; } @@ -438,6 +456,20 @@ schedule (void) prev = switch_threads (cur, next); schedule_tail (prev); } + +/* Returns a tid to use for a new thread. */ +static tid_t +allocate_tid (void) +{ + static tid_t next_tid = 1; + tid_t tid; + + lock_acquire (&tid_lock); + tid = next_tid++; + lock_release (&tid_lock); + + return tid; +} /* Offset of `stack' member within `struct thread'. Used by switch.S, which can't figure it out on its own. */ diff --git a/src/threads/thread.h b/src/threads/thread.h index 248f1d4..e844b5c 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -18,6 +18,11 @@ enum thread_status THREAD_DYING /* About to be destroyed. */ }; +/* Thread identifier type. + You can redefine this to whatever type you like. */ +typedef int tid_t; +#define TID_ERROR ((tid_t) -1) /* Error value for tid_t. */ + /* A kernel thread or user process. Each thread structure is stored in its own 4 kB page. The @@ -76,14 +81,17 @@ enum thread_status blocked state is on a semaphore wait list. */ struct thread { - /* These members are owned by the thread_*() functions. */ + /* These members are owned by thread.c. */ + tid_t tid; /* Thread identifier. */ enum thread_status status; /* Thread state. */ char name[16]; /* Name (for debugging purposes). */ uint8_t *stack; /* Saved stack pointer. */ + + /* Shared between thread.c and synch.c. */ list_elem elem; /* List element. */ #ifdef USERPROG - /* These members are owned by the addrspace_*() functions. */ + /* These members are owned by userprog/addrspace.c. */ uint32_t *pagedir; /* Page directory. */ #endif @@ -95,21 +103,23 @@ void thread_init (void); void thread_start (void); typedef void thread_func (void *aux); -struct thread *thread_create (const char *name, thread_func *, void *); +tid_t thread_create (const char *name, thread_func *, void *); #ifdef USERPROG -bool thread_execute (const char *filename); +tid_t thread_execute (const char *filename); #endif void thread_unblock (struct thread *); -const char *thread_name (struct thread *); struct thread *thread_current (void); +tid_t thread_tid (void); +const char *thread_name (void); void thread_exit (void) NO_RETURN; void thread_yield (void); void thread_block (void); -void thread_join (struct thread *); -void thread_set_priority (struct thread *, int); -int thread_get_priority (const struct thread *); +/* These functions will be implemented in project 1. */ +void thread_join (tid_t); +void thread_set_priority (tid_t, int); +int thread_get_priority (tid_t); #endif /* threads/thread.h */ diff --git a/src/userprog/exception.c b/src/userprog/exception.c index 4e9d28f..dead766 100644 --- a/src/userprog/exception.c +++ b/src/userprog/exception.c @@ -74,8 +74,7 @@ kill (struct intr_frame *f) /* User's code segment, so it's a user exception, as we expected. Kill the user process. */ printf ("%s: dying due to interrupt %#04x (%s).\n", - thread_name (thread_current ()), - f->vec_no, intr_name (f->vec_no)); + thread_name (), f->vec_no, intr_name (f->vec_no)); intr_dump_frame (f); thread_exit (); -- 2.30.2