Implement a proper block layer with partition support.
[pintos-anon] / src / threads / synch.c
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 \f
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 \f
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 }