diff options
Diffstat (limited to 'threads/synch.c')
| -rw-r--r-- | threads/synch.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/threads/synch.c b/threads/synch.c new file mode 100644 index 0000000..317c68a --- /dev/null +++ b/threads/synch.c | |||
| @@ -0,0 +1,338 @@ | |||
| 1 | /* This file is derived from source code for the Nachos | ||
| 2 | instructional operating system. The Nachos copyright notice | ||
| 3 | is reproduced in full below. */ | ||
| 4 | |||
| 5 | /* Copyright (c) 1992-1996 The Regents of the University of California. | ||
| 6 | All rights reserved. | ||
| 7 | |||
| 8 | Permission to use, copy, modify, and distribute this software | ||
| 9 | and its documentation for any purpose, without fee, and | ||
| 10 | without written agreement is hereby granted, provided that the | ||
| 11 | above copyright notice and the following two paragraphs appear | ||
| 12 | in all copies of this software. | ||
| 13 | |||
| 14 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO | ||
| 15 | ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR | ||
| 16 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE | ||
| 17 | AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA | ||
| 18 | HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 19 | |||
| 20 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY | ||
| 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| 23 | PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" | ||
| 24 | BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO | ||
| 25 | PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR | ||
| 26 | MODIFICATIONS. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "threads/synch.h" | ||
| 30 | #include <stdio.h> | ||
| 31 | #include <string.h> | ||
| 32 | #include "threads/interrupt.h" | ||
| 33 | #include "threads/thread.h" | ||
| 34 | |||
| 35 | /* Initializes semaphore SEMA to VALUE. A semaphore is a | ||
| 36 | nonnegative integer along with two atomic operators for | ||
| 37 | manipulating it: | ||
| 38 | |||
| 39 | - down or "P": wait for the value to become positive, then | ||
| 40 | decrement it. | ||
| 41 | |||
| 42 | - up or "V": increment the value (and wake up one waiting | ||
| 43 | thread, if any). */ | ||
| 44 | void | ||
| 45 | sema_init (struct semaphore *sema, unsigned value) | ||
| 46 | { | ||
| 47 | ASSERT (sema != NULL); | ||
| 48 | |||
| 49 | sema->value = value; | ||
| 50 | list_init (&sema->waiters); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Down or "P" operation on a semaphore. Waits for SEMA's value | ||
| 54 | to become positive and then atomically decrements it. | ||
| 55 | |||
| 56 | This function may sleep, so it must not be called within an | ||
| 57 | interrupt handler. This function may be called with | ||
| 58 | interrupts disabled, but if it sleeps then the next scheduled | ||
| 59 | thread will probably turn interrupts back on. */ | ||
| 60 | void | ||
| 61 | sema_down (struct semaphore *sema) | ||
| 62 | { | ||
| 63 | enum intr_level old_level; | ||
| 64 | |||
| 65 | ASSERT (sema != NULL); | ||
| 66 | ASSERT (!intr_context ()); | ||
| 67 | |||
| 68 | old_level = intr_disable (); | ||
| 69 | while (sema->value == 0) | ||
| 70 | { | ||
| 71 | list_push_back (&sema->waiters, &thread_current ()->elem); | ||
| 72 | thread_block (); | ||
| 73 | } | ||
| 74 | sema->value--; | ||
| 75 | intr_set_level (old_level); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* Down or "P" operation on a semaphore, but only if the | ||
| 79 | semaphore is not already 0. Returns true if the semaphore is | ||
| 80 | decremented, false otherwise. | ||
| 81 | |||
| 82 | This function may be called from an interrupt handler. */ | ||
| 83 | bool | ||
| 84 | sema_try_down (struct semaphore *sema) | ||
| 85 | { | ||
| 86 | enum intr_level old_level; | ||
| 87 | bool success; | ||
| 88 | |||
| 89 | ASSERT (sema != NULL); | ||
| 90 | |||
| 91 | old_level = intr_disable (); | ||
| 92 | if (sema->value > 0) | ||
| 93 | { | ||
| 94 | sema->value--; | ||
| 95 | success = true; | ||
| 96 | } | ||
| 97 | else | ||
| 98 | success = false; | ||
| 99 | intr_set_level (old_level); | ||
| 100 | |||
| 101 | return success; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* Up or "V" operation on a semaphore. Increments SEMA's value | ||
| 105 | and wakes up one thread of those waiting for SEMA, if any. | ||
| 106 | |||
| 107 | This function may be called from an interrupt handler. */ | ||
| 108 | void | ||
| 109 | sema_up (struct semaphore *sema) | ||
| 110 | { | ||
| 111 | enum intr_level old_level; | ||
| 112 | |||
| 113 | ASSERT (sema != NULL); | ||
| 114 | |||
| 115 | old_level = intr_disable (); | ||
| 116 | if (!list_empty (&sema->waiters)) | ||
| 117 | thread_unblock (list_entry (list_pop_front (&sema->waiters), | ||
| 118 | struct thread, elem)); | ||
| 119 | sema->value++; | ||
| 120 | intr_set_level (old_level); | ||
| 121 | } | ||
| 122 | |||
| 123 | static void sema_test_helper (void *sema_); | ||
| 124 | |||
| 125 | /* Self-test for semaphores that makes control "ping-pong" | ||
| 126 | between a pair of threads. Insert calls to printf() to see | ||
| 127 | what's going on. */ | ||
| 128 | void | ||
| 129 | sema_self_test (void) | ||
| 130 | { | ||
| 131 | struct semaphore sema[2]; | ||
| 132 | int i; | ||
| 133 | |||
| 134 | printf ("Testing semaphores..."); | ||
| 135 | sema_init (&sema[0], 0); | ||
| 136 | sema_init (&sema[1], 0); | ||
| 137 | thread_create ("sema-test", PRI_DEFAULT, sema_test_helper, &sema); | ||
| 138 | for (i = 0; i < 10; i++) | ||
| 139 | { | ||
| 140 | sema_up (&sema[0]); | ||
| 141 | sema_down (&sema[1]); | ||
| 142 | } | ||
| 143 | printf ("done.\n"); | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Thread function used by sema_self_test(). */ | ||
| 147 | static void | ||
| 148 | sema_test_helper (void *sema_) | ||
| 149 | { | ||
| 150 | struct semaphore *sema = sema_; | ||
| 151 | int i; | ||
| 152 | |||
| 153 | for (i = 0; i < 10; i++) | ||
| 154 | { | ||
| 155 | sema_down (&sema[0]); | ||
| 156 | sema_up (&sema[1]); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /* Initializes LOCK. A lock can be held by at most a single | ||
| 161 | thread at any given time. Our locks are not "recursive", that | ||
| 162 | is, it is an error for the thread currently holding a lock to | ||
| 163 | try to acquire that lock. | ||
| 164 | |||
| 165 | A lock is a specialization of a semaphore with an initial | ||
| 166 | value of 1. The difference between a lock and such a | ||
| 167 | semaphore is twofold. First, a semaphore can have a value | ||
| 168 | greater than 1, but a lock can only be owned by a single | ||
| 169 | thread at a time. Second, a semaphore does not have an owner, | ||
| 170 | meaning that one thread can "down" the semaphore and then | ||
| 171 | another one "up" it, but with a lock the same thread must both | ||
| 172 | acquire and release it. When these restrictions prove | ||
| 173 | onerous, it's a good sign that a semaphore should be used, | ||
| 174 | instead of a lock. */ | ||
| 175 | void | ||
| 176 | lock_init (struct lock *lock) | ||
| 177 | { | ||
| 178 | ASSERT (lock != NULL); | ||
| 179 | |||
| 180 | lock->holder = NULL; | ||
| 181 | sema_init (&lock->semaphore, 1); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Acquires LOCK, sleeping until it becomes available if | ||
| 185 | necessary. The lock must not already be held by the current | ||
| 186 | thread. | ||
| 187 | |||
| 188 | This function may sleep, so it must not be called within an | ||
| 189 | interrupt handler. This function may be called with | ||
| 190 | interrupts disabled, but interrupts will be turned back on if | ||
| 191 | we need to sleep. */ | ||
| 192 | void | ||
| 193 | lock_acquire (struct lock *lock) | ||
| 194 | { | ||
| 195 | ASSERT (lock != NULL); | ||
| 196 | ASSERT (!intr_context ()); | ||
| 197 | ASSERT (!lock_held_by_current_thread (lock)); | ||
| 198 | |||
| 199 | sema_down (&lock->semaphore); | ||
| 200 | lock->holder = thread_current (); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* Tries to acquires LOCK and returns true if successful or false | ||
| 204 | on failure. The lock must not already be held by the current | ||
| 205 | thread. | ||
| 206 | |||
| 207 | This function will not sleep, so it may be called within an | ||
| 208 | interrupt handler. */ | ||
| 209 | bool | ||
| 210 | lock_try_acquire (struct lock *lock) | ||
| 211 | { | ||
| 212 | bool success; | ||
| 213 | |||
| 214 | ASSERT (lock != NULL); | ||
| 215 | ASSERT (!lock_held_by_current_thread (lock)); | ||
| 216 | |||
| 217 | success = sema_try_down (&lock->semaphore); | ||
| 218 | if (success) | ||
| 219 | lock->holder = thread_current (); | ||
| 220 | return success; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Releases LOCK, which must be owned by the current thread. | ||
| 224 | |||
| 225 | An interrupt handler cannot acquire a lock, so it does not | ||
| 226 | make sense to try to release a lock within an interrupt | ||
| 227 | handler. */ | ||
| 228 | void | ||
| 229 | lock_release (struct lock *lock) | ||
| 230 | { | ||
| 231 | ASSERT (lock != NULL); | ||
| 232 | ASSERT (lock_held_by_current_thread (lock)); | ||
| 233 | |||
| 234 | lock->holder = NULL; | ||
| 235 | sema_up (&lock->semaphore); | ||
| 236 | } | ||
| 237 | |||
| 238 | /* Returns true if the current thread holds LOCK, false | ||
| 239 | otherwise. (Note that testing whether some other thread holds | ||
| 240 | a lock would be racy.) */ | ||
| 241 | bool | ||
| 242 | lock_held_by_current_thread (const struct lock *lock) | ||
| 243 | { | ||
| 244 | ASSERT (lock != NULL); | ||
| 245 | |||
| 246 | return lock->holder == thread_current (); | ||
| 247 | } | ||
| 248 | |||
| 249 | /* One semaphore in a list. */ | ||
| 250 | struct semaphore_elem | ||
| 251 | { | ||
| 252 | struct list_elem elem; /* List element. */ | ||
| 253 | struct semaphore semaphore; /* This semaphore. */ | ||
| 254 | }; | ||
| 255 | |||
| 256 | /* Initializes condition variable COND. A condition variable | ||
| 257 | allows one piece of code to signal a condition and cooperating | ||
| 258 | code to receive the signal and act upon it. */ | ||
| 259 | void | ||
| 260 | cond_init (struct condition *cond) | ||
| 261 | { | ||
| 262 | ASSERT (cond != NULL); | ||
| 263 | |||
| 264 | list_init (&cond->waiters); | ||
| 265 | } | ||
| 266 | |||
| 267 | /* Atomically releases LOCK and waits for COND to be signaled by | ||
| 268 | some other piece of code. After COND is signaled, LOCK is | ||
| 269 | reacquired before returning. LOCK must be held before calling | ||
| 270 | this function. | ||
| 271 | |||
| 272 | The monitor implemented by this function is "Mesa" style, not | ||
| 273 | "Hoare" style, that is, sending and receiving a signal are not | ||
| 274 | an atomic operation. Thus, typically the caller must recheck | ||
| 275 | the condition after the wait completes and, if necessary, wait | ||
| 276 | again. | ||
| 277 | |||
| 278 | A given condition variable is associated with only a single | ||
| 279 | lock, but one lock may be associated with any number of | ||
| 280 | condition variables. That is, there is a one-to-many mapping | ||
| 281 | from locks to condition variables. | ||
| 282 | |||
| 283 | This function may sleep, so it must not be called within an | ||
| 284 | interrupt handler. This function may be called with | ||
| 285 | interrupts disabled, but interrupts will be turned back on if | ||
| 286 | we need to sleep. */ | ||
| 287 | void | ||
| 288 | cond_wait (struct condition *cond, struct lock *lock) | ||
| 289 | { | ||
| 290 | struct semaphore_elem waiter; | ||
| 291 | |||
| 292 | ASSERT (cond != NULL); | ||
| 293 | ASSERT (lock != NULL); | ||
| 294 | ASSERT (!intr_context ()); | ||
| 295 | ASSERT (lock_held_by_current_thread (lock)); | ||
| 296 | |||
| 297 | sema_init (&waiter.semaphore, 0); | ||
| 298 | list_push_back (&cond->waiters, &waiter.elem); | ||
| 299 | lock_release (lock); | ||
| 300 | sema_down (&waiter.semaphore); | ||
| 301 | lock_acquire (lock); | ||
| 302 | } | ||
| 303 | |||
| 304 | /* If any threads are waiting on COND (protected by LOCK), then | ||
| 305 | this function signals one of them to wake up from its wait. | ||
| 306 | LOCK must be held before calling this function. | ||
| 307 | |||
| 308 | An interrupt handler cannot acquire a lock, so it does not | ||
| 309 | make sense to try to signal a condition variable within an | ||
| 310 | interrupt handler. */ | ||
| 311 | void | ||
| 312 | cond_signal (struct condition *cond, struct lock *lock UNUSED) | ||
| 313 | { | ||
| 314 | ASSERT (cond != NULL); | ||
| 315 | ASSERT (lock != NULL); | ||
| 316 | ASSERT (!intr_context ()); | ||
| 317 | ASSERT (lock_held_by_current_thread (lock)); | ||
| 318 | |||
| 319 | if (!list_empty (&cond->waiters)) | ||
| 320 | sema_up (&list_entry (list_pop_front (&cond->waiters), | ||
| 321 | struct semaphore_elem, elem)->semaphore); | ||
| 322 | } | ||
| 323 | |||
| 324 | /* Wakes up all threads, if any, waiting on COND (protected by | ||
| 325 | LOCK). LOCK must be held before calling this function. | ||
| 326 | |||
| 327 | An interrupt handler cannot acquire a lock, so it does not | ||
| 328 | make sense to try to signal a condition variable within an | ||
| 329 | interrupt handler. */ | ||
| 330 | void | ||
| 331 | cond_broadcast (struct condition *cond, struct lock *lock) | ||
| 332 | { | ||
| 333 | ASSERT (cond != NULL); | ||
| 334 | ASSERT (lock != NULL); | ||
| 335 | |||
| 336 | while (!list_empty (&cond->waiters)) | ||
| 337 | cond_signal (cond, lock); | ||
| 338 | } | ||
