d7601dacddc89f7c772d3340cf0e856b81c82f09
[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 "synch.h"
30 #include "interrupt.h"
31 #include "lib.h"
32 #include "thread.h"
33
34 /* Initializes semaphore SEMA to VALUE and names it NAME (for
35    debugging purposes only).  A semaphore is a nonnegative
36    integer along with two atomic operators for manipulating it:
37
38    - down or "P": wait for the value to become positive, then
39      decrement it.
40
41    - up or "V": increment the value (and wake up one waiting
42      thread, if any). */
43 void
44 sema_init (struct semaphore *sema, unsigned value, const char *name) 
45 {
46   ASSERT (sema != NULL);
47   ASSERT (name != NULL);
48
49   strlcpy (sema->name, name, sizeof sema->name);
50   sema->value = value;
51   list_init (&sema->waiters);
52 }
53
54 /* Down or "P" operation on a semaphore.  Waits for SEMA's value
55    to become positive and then atomically decrements it.
56
57    This function may sleep, so it must not be called within an
58    interrupt handler.  This function may be called with
59    interrupts disabled, but interrupts will be turned back on if
60    we need to sleep. */
61 void
62 sema_down (struct semaphore *sema) 
63 {
64   enum intr_level old_level;
65
66   ASSERT (sema != NULL);
67   ASSERT (!intr_context ());
68
69   old_level = intr_disable ();
70   while (sema->value == 0) 
71     {
72       list_push_back (&sema->waiters, &thread_current ()->elem);
73       thread_block ();
74     }
75   sema->value--;
76   intr_set_level (old_level);
77 }
78
79 /* Up or "V" operation on a semaphore.  Increments SEMA's value
80    and wakes up one thread of those waiting for SEMA, if any.
81
82    This function may be called from an interrupt handler. */
83 void
84 sema_up (struct semaphore *sema) 
85 {
86   enum intr_level old_level;
87
88   ASSERT (sema != NULL);
89
90   old_level = intr_disable ();
91   if (!list_empty (&sema->waiters)) 
92     thread_unblock (list_entry (list_pop_front (&sema->waiters),
93                                 struct thread, elem));
94   sema->value++;
95   intr_set_level (old_level);
96 }
97
98 /* Return SEMA's name (for debugging purposes). */
99 const char *
100 sema_name (const struct semaphore *sema) 
101 {
102   return sema->name;
103 }
104
105 static void sema_test_helper (void *sema_);
106
107 /* Self-test for semaphores that makes control "ping-pong"
108    between a pair of threads.  Insert calls to printk() to see
109    what's going on. */
110 void
111 sema_self_test (void) 
112 {
113   struct thread *thread;
114   struct semaphore sema[2];
115   int i;
116
117   printk ("Testing semaphores...");
118   sema_init (&sema[0], 0, "ping");
119   sema_init (&sema[1], 0, "pong");
120   thread = thread_create ("sema-test", sema_test_helper, &sema);
121   for (i = 0; i < 10; i++) 
122     {
123       sema_up (&sema[0]);
124       sema_down (&sema[1]);
125     }
126   printk ("done.\n");
127 }
128
129 /* Thread function used by sema_self_test(). */
130 static void
131 sema_test_helper (void *sema_) 
132 {
133   struct semaphore *sema = sema_;
134   int i;
135
136   for (i = 0; i < 10; i++) 
137     {
138       sema_down (&sema[0]);
139       sema_up (&sema[1]);
140     }
141 }
142 \f
143 /* Initializes LOCK and names it NAME (for debugging purposes).
144    A lock can be held by at most a single thread at any given
145    time.  Our locks are not "recursive", that is, it is an error
146    for the thread currently holding a lock to try to acquire that
147    lock.
148
149    A lock is a specialization of a semaphore with an initial
150    value of 1.  The difference between a lock and such a
151    semaphore is twofold.  First, a semaphore can have a value
152    greater than 1, but a lock can only be owned by a single
153    thread at a time.  Second, a semaphore does not have an owner,
154    meaning that one thread can "down" the semaphore and then
155    another one "up" it, but with a lock the same thread must both
156    acquire and release it.  When these restrictions prove
157    onerous, it's a good sign that a semaphore should be used,
158    instead of a lock. */
159 void
160 lock_init (struct lock *lock, const char *name)
161 {
162   ASSERT (lock != NULL);
163   ASSERT (name != NULL);
164
165   strlcpy (lock->name, name, sizeof lock->name);
166   lock->holder = NULL;
167   sema_init (&lock->semaphore, 1, name);
168 }
169
170 /* Acquires LOCK, sleeping until it becomes available if
171    necessary.  The lock must not already be held by the current
172    thread.
173
174    This function may sleep, so it must not be called within an
175    interrupt handler.  This function may be called with
176    interrupts disabled, but interrupts will be turned back on if
177    we need to sleep. */
178 void
179 lock_acquire (struct lock *lock)
180 {
181   enum intr_level old_level;
182
183   ASSERT (lock != NULL);
184   ASSERT (!intr_context ());
185   ASSERT (!lock_held_by_current_thread (lock));
186
187   old_level = intr_disable ();
188   sema_down (&lock->semaphore);
189   lock->holder = thread_current ();
190   intr_set_level (old_level);
191 }
192
193 /* Releases LOCK, which must be owned by the current thread.
194
195    An interrupt handler cannot acquire a lock, so it does not
196    make sense to try to signal a condition variable within an
197    interrupt handler. */
198 void
199 lock_release (struct lock *lock) 
200 {
201   enum intr_level old_level;
202
203   ASSERT (lock != NULL);
204   ASSERT (lock_held_by_current_thread (lock));
205
206   old_level = intr_disable ();
207   lock->holder = NULL;
208   sema_up (&lock->semaphore);
209   intr_set_level (old_level);
210 }
211
212 /* Returns true if the current thread holds LOCK, false
213    otherwise.  (Note that testing whether some other thread holds
214    a lock would be racy.) */
215 bool
216 lock_held_by_current_thread (const struct lock *lock) 
217 {
218   ASSERT (lock != NULL);
219
220   return lock->holder == thread_current ();
221 }
222
223 /* Returns the name of LOCK (for debugging purposes). */
224 const char *
225 lock_name (const struct lock *lock) 
226 {
227   ASSERT (lock != NULL);
228
229   return lock->name;
230 }
231 \f
232 /* One semaphore in a list. */
233 struct semaphore_elem 
234   {
235     list_elem elem;                     /* List element. */
236     struct semaphore semaphore;         /* This semaphore. */
237   };
238
239 /* Initializes condition variable COND and names it NAME.  A
240    condition variable allows one piece of code to signal a
241    condition and cooperating code to receive the signal and act
242    upon it. */
243 void
244 cond_init (struct condition *cond, const char *name) 
245 {
246   ASSERT (cond != NULL);
247   ASSERT (name != NULL);
248
249   strlcpy (cond->name, name, sizeof cond->name);
250   list_init (&cond->waiters);
251 }
252
253 /* Atomically releases LOCK and waits for COND to be signaled by
254    some other piece of code.  After COND is signalled, LOCK is
255    reacquired before returning.  LOCK must be held before calling
256    this function.
257
258    The monitor implemented by this function is "Mesa" style, not
259    "Hoare" style, that is, sending and receiving a signal are not
260    an atomic operation.  Thus, typically the caller must recheck
261    the condition after the wait completes and, if necessary, wait
262    again.
263
264    A given condition variable is associated with only a single
265    lock, but one lock may be be associated with any number of
266    condition variables.  That is, there is a one-to-many mapping
267    from locks to condition variables.
268
269    This function may sleep, so it must not be called within an
270    interrupt handler.  This function may be called with
271    interrupts disabled, but interrupts will be turned back on if
272    we need to sleep. */
273 void
274 cond_wait (struct condition *cond, struct lock *lock) 
275 {
276   struct semaphore_elem waiter;
277
278   ASSERT (cond != NULL);
279   ASSERT (lock != NULL);
280   ASSERT (!intr_context ());
281   ASSERT (lock_held_by_current_thread (lock));
282   
283   sema_init (&waiter.semaphore, 0, "condition");
284   list_push_back (&cond->waiters, &waiter.elem);
285   lock_release (lock);
286   sema_down (&waiter.semaphore);
287   lock_acquire (lock);
288 }
289
290 /* If any threads are waiting on COND (protected by LOCK), then
291    this function signals one of them to wake up from its wait.
292    LOCK must be held before calling this function.
293
294    An interrupt handler cannot acquire a lock, so it does not
295    make sense to try to signal a condition variable within an
296    interrupt handler. */
297 void
298 cond_signal (struct condition *cond, struct lock *lock) 
299 {
300   ASSERT (cond != NULL);
301   ASSERT (lock != NULL);
302   ASSERT (!intr_context ());
303   ASSERT (lock_held_by_current_thread (lock));
304
305   if (!list_empty (&cond->waiters)) 
306     sema_up (&list_entry (list_pop_front (&cond->waiters),
307                           struct semaphore_elem, elem)->semaphore);
308 }
309
310 /* Wakes up all threads, if any, waiting on COND (protected by
311    LOCK).  LOCK must be held before calling this function.
312
313    An interrupt handler cannot acquire a lock, so it does not
314    make sense to try to signal a condition variable within an
315    interrupt handler. */
316 void
317 cond_broadcast (struct condition *cond, struct lock *lock) 
318 {
319   ASSERT (cond != NULL);
320   ASSERT (lock != NULL);
321
322   while (!list_empty (&cond->waiters))
323     cond_signal (cond, lock);
324 }
325
326 /* Returns COND's name (for debugging purposes). */
327 const char *
328 cond_name (const struct condition *cond)
329 {
330   ASSERT (cond != NULL);
331
332   return cond->name;
333 }