00001 #include "threads/thread.h"
00002
00003 #include <debug.h>
00004 #include <stddef.h>
00005 #include <random.h>
00006 #include <stdio.h>
00007 #include <string.h>
00008 #include "threads/flags.h"
00009 #include "threads/interrupt.h"
00010 #include "threads/intr-stubs.h"
00011 #include "threads/palloc.h"
00012 #include "threads/switch.h"
00013 #include "threads/synch.h"
00014 #include "threads/vaddr.h"
00015 #ifdef USERPROG
00016 #include "userprog/process.h"
00017 #endif
00018
00019
00020
00021
00022 #define THREAD_MAGIC 0xcd6abf4b
00023
00024
00025
00026 static struct list ready_list;
00027
00028
00029
00030 static struct list all_list;
00031
00032
00033 static struct thread *idle_thread;
00034
00035
00036 static struct thread *initial_thread;
00037
00038
00039 static struct lock tid_lock;
00040
00041
00042 struct kernel_thread_frame
00043 {
00044 void *eip;
00045 thread_func *function;
00046 void *aux;
00047 };
00048
00049
00050 static long long idle_ticks;
00051 static long long kernel_ticks;
00052 static long long user_ticks;
00053
00054
00055 #define TIME_SLICE 4
00056 static unsigned thread_ticks;
00057
00058
00059
00060
00061 bool thread_mlfqs;
00062
00063 static void kernel_thread (thread_func *, void *aux);
00064
00065 static void idle (void *aux UNUSED);
00066 static struct thread *running_thread (void);
00067 static struct thread *next_thread_to_run (void);
00068 static void init_thread (struct thread *, const char *name, int priority);
00069 static bool is_thread (struct thread *) UNUSED;
00070 static void *alloc_frame (struct thread *, size_t size);
00071 static void schedule (void);
00072 void schedule_tail (struct thread *prev);
00073 static tid_t allocate_tid (void);
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 void
00089 thread_init (void)
00090 {
00091 ASSERT (intr_get_level () == INTR_OFF);
00092
00093 lock_init (&tid_lock);
00094 list_init (&ready_list);
00095 list_init (&all_list);
00096
00097
00098 initial_thread = running_thread ();
00099 init_thread (initial_thread, "main", PRI_DEFAULT);
00100 initial_thread->status = THREAD_RUNNING;
00101 initial_thread->tid = allocate_tid ();
00102 }
00103
00104
00105
00106 void
00107 thread_start (void)
00108 {
00109
00110 struct semaphore idle_started;
00111 sema_init (&idle_started, 0);
00112 thread_create ("idle", PRI_MIN, idle, &idle_started);
00113
00114
00115 intr_enable ();
00116
00117
00118 sema_down (&idle_started);
00119 }
00120
00121
00122
00123 void
00124 thread_tick (void)
00125 {
00126 struct thread *t = thread_current ();
00127
00128
00129 if (t == idle_thread)
00130 idle_ticks++;
00131 #ifdef USERPROG
00132 else if (t->pagedir != NULL)
00133 user_ticks++;
00134 #endif
00135 else
00136 kernel_ticks++;
00137
00138
00139 if (++thread_ticks >= TIME_SLICE)
00140 intr_yield_on_return ();
00141 }
00142
00143
00144 void
00145 thread_print_stats (void)
00146 {
00147 printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n",
00148 idle_ticks, kernel_ticks, user_ticks);
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 tid_t
00167 thread_create (const char *name, int priority,
00168 thread_func *function, void *aux)
00169 {
00170 struct thread *t;
00171 struct kernel_thread_frame *kf;
00172 struct switch_entry_frame *ef;
00173 struct switch_threads_frame *sf;
00174 tid_t tid;
00175 enum intr_level old_level;
00176
00177 ASSERT (function != NULL);
00178
00179
00180 t = palloc_get_page (PAL_ZERO);
00181 if (t == NULL)
00182 return TID_ERROR;
00183
00184
00185 init_thread (t, name, priority);
00186 tid = t->tid = allocate_tid ();
00187
00188
00189
00190
00191 old_level = intr_disable ();
00192
00193
00194 kf = alloc_frame (t, sizeof *kf);
00195 kf->eip = NULL;
00196 kf->function = function;
00197 kf->aux = aux;
00198
00199
00200 ef = alloc_frame (t, sizeof *ef);
00201 ef->eip = (void (*) (void)) kernel_thread;
00202
00203
00204 sf = alloc_frame (t, sizeof *sf);
00205 sf->eip = switch_entry;
00206 sf->ebp = 0;
00207
00208 intr_set_level (old_level);
00209
00210
00211 thread_unblock (t);
00212
00213 return tid;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 void
00223 thread_block (void)
00224 {
00225 ASSERT (!intr_context ());
00226 ASSERT (intr_get_level () == INTR_OFF);
00227
00228 thread_current ()->status = THREAD_BLOCKED;
00229 schedule ();
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 void
00241 thread_unblock (struct thread *t)
00242 {
00243 enum intr_level old_level;
00244
00245 ASSERT (is_thread (t));
00246
00247 old_level = intr_disable ();
00248 ASSERT (t->status == THREAD_BLOCKED);
00249 list_push_back (&ready_list, &t->elem);
00250 t->status = THREAD_READY;
00251 intr_set_level (old_level);
00252 }
00253
00254
00255 const char *
00256 thread_name (void)
00257 {
00258 return thread_current ()->name;
00259 }
00260
00261
00262
00263
00264 struct thread *
00265 thread_current (void)
00266 {
00267 struct thread *t = running_thread ();
00268
00269
00270
00271
00272
00273
00274 ASSERT (is_thread (t));
00275 ASSERT (t->status == THREAD_RUNNING);
00276
00277 return t;
00278 }
00279
00280
00281 tid_t
00282 thread_tid (void)
00283 {
00284 return thread_current ()->tid;
00285 }
00286
00287
00288
00289 void
00290 thread_exit (void)
00291 {
00292 ASSERT (!intr_context ());
00293
00294 #ifdef USERPROG
00295 process_exit ();
00296 #endif
00297
00298
00299
00300
00301 intr_disable ();
00302 list_remove (&thread_current()->allelem);
00303 thread_current ()->status = THREAD_DYING;
00304 schedule ();
00305 NOT_REACHED ();
00306 }
00307
00308
00309
00310 void
00311 thread_yield (void)
00312 {
00313 struct thread *cur = thread_current ();
00314 enum intr_level old_level;
00315
00316 ASSERT (!intr_context ());
00317
00318 old_level = intr_disable ();
00319 if (cur != idle_thread)
00320 list_push_back (&ready_list, &cur->elem);
00321 cur->status = THREAD_READY;
00322 schedule ();
00323 intr_set_level (old_level);
00324 }
00325
00326
00327
00328 void
00329 thread_foreach (thread_action_func *func, void *aux)
00330 {
00331 struct list_elem *e;
00332
00333 ASSERT (intr_get_level () == INTR_OFF);
00334
00335 for (e = list_begin (&all_list); e != list_end (&all_list);
00336 e = list_next (e))
00337 {
00338 struct thread *t = list_entry (e, struct thread, allelem);
00339 func (t, aux);
00340 }
00341 }
00342
00343
00344 void
00345 thread_set_priority (int new_priority)
00346 {
00347 thread_current ()->priority = new_priority;
00348 }
00349
00350
00351 int
00352 thread_get_priority (void)
00353 {
00354 return thread_current ()->priority;
00355 }
00356
00357
00358 void
00359 thread_set_nice (int nice UNUSED)
00360 {
00361
00362 }
00363
00364
00365 int
00366 thread_get_nice (void)
00367 {
00368
00369 return 0;
00370 }
00371
00372
00373 int
00374 thread_get_load_avg (void)
00375 {
00376
00377 return 0;
00378 }
00379
00380
00381 int
00382 thread_get_recent_cpu (void)
00383 {
00384
00385 return 0;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 static void
00398 idle (void *idle_started_ UNUSED)
00399 {
00400 struct semaphore *idle_started = idle_started_;
00401 idle_thread = thread_current ();
00402 sema_up (idle_started);
00403
00404 for (;;)
00405 {
00406
00407 intr_disable ();
00408 thread_block ();
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 asm volatile ("sti; hlt" : : : "memory");
00423 }
00424 }
00425
00426
00427 static void
00428 kernel_thread (thread_func *function, void *aux)
00429 {
00430 ASSERT (function != NULL);
00431
00432 intr_enable ();
00433 function (aux);
00434 thread_exit ();
00435 }
00436
00437
00438 struct thread *
00439 running_thread (void)
00440 {
00441 uint32_t *esp;
00442
00443
00444
00445
00446
00447 asm ("mov %%esp, %0" : "=g" (esp));
00448 return pg_round_down (esp);
00449 }
00450
00451
00452 static bool
00453 is_thread (struct thread *t)
00454 {
00455 return t != NULL && t->magic == THREAD_MAGIC;
00456 }
00457
00458
00459
00460 static void
00461 init_thread (struct thread *t, const char *name, int priority)
00462 {
00463 ASSERT (t != NULL);
00464 ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
00465 ASSERT (name != NULL);
00466
00467 memset (t, 0, sizeof *t);
00468 t->status = THREAD_BLOCKED;
00469 strlcpy (t->name, name, sizeof t->name);
00470 t->stack = (uint8_t *) t + PGSIZE;
00471 t->priority = priority;
00472 t->magic = THREAD_MAGIC;
00473 list_push_back (&all_list, &t->allelem);
00474 }
00475
00476
00477
00478 static void *
00479 alloc_frame (struct thread *t, size_t size)
00480 {
00481
00482 ASSERT (is_thread (t));
00483 ASSERT (size % sizeof (uint32_t) == 0);
00484
00485 t->stack -= size;
00486 return t->stack;
00487 }
00488
00489
00490
00491
00492
00493
00494 static struct thread *
00495 next_thread_to_run (void)
00496 {
00497 if (list_empty (&ready_list))
00498 return idle_thread;
00499 else
00500 return list_entry (list_pop_front (&ready_list), struct thread, elem);
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 void
00520 schedule_tail (struct thread *prev)
00521 {
00522 struct thread *cur = running_thread ();
00523
00524 ASSERT (intr_get_level () == INTR_OFF);
00525
00526
00527 cur->status = THREAD_RUNNING;
00528
00529
00530 thread_ticks = 0;
00531
00532 #ifdef USERPROG
00533
00534 process_activate ();
00535 #endif
00536
00537
00538
00539
00540
00541
00542 if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread)
00543 {
00544 ASSERT (prev != cur);
00545 palloc_free_page (prev);
00546 }
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556 static void
00557 schedule (void)
00558 {
00559 struct thread *cur = running_thread ();
00560 struct thread *next = next_thread_to_run ();
00561 struct thread *prev = NULL;
00562
00563 ASSERT (intr_get_level () == INTR_OFF);
00564 ASSERT (cur->status != THREAD_RUNNING);
00565 ASSERT (is_thread (next));
00566
00567 if (cur != next)
00568 prev = switch_threads (cur, next);
00569 schedule_tail (prev);
00570 }
00571
00572
00573 static tid_t
00574 allocate_tid (void)
00575 {
00576 static tid_t next_tid = 1;
00577 tid_t tid;
00578
00579 lock_acquire (&tid_lock);
00580 tid = next_tid++;
00581 lock_release (&tid_lock);
00582
00583 return tid;
00584 }
00585
00586
00587
00588 uint32_t thread_stack_ofs = offsetof (struct thread, stack);