CS318 - Pintos
Pintos source browser for JHU CS318 course
synch.c
Go to the documentation of this file.
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;
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
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  {
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
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
110 {
111  enum intr_level old_level;
112 
113  ASSERT (sema != NULL);
114 
115  old_level = intr_disable ();
116  if (!list_empty (&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
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);
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
194 {
195  ASSERT (lock != NULL);
196  ASSERT (!intr_context ());
198 
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
211 {
212  bool success;
213 
214  ASSERT (lock != NULL);
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
230 {
231  ASSERT (lock != NULL);
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
243 {
244  ASSERT (lock != NULL);
245 
246  return lock->holder == thread_current ();
247 }
248 
249 /** One semaphore in a list. */
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 ());
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 ());
318 
319  if (!list_empty (&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 }
list_elem
Doubly linked list.
Definition: list.h:90
list_entry
#define list_entry(LIST_ELEM, STRUCT, MEMBER)
Converts pointer to list element LIST_ELEM into a pointer to the structure that LIST_ELEM is embedded...
Definition: list.h:108
lock_release
void lock_release(struct lock *lock)
Releases LOCK, which must be owned by the current thread.
Definition: synch.c:229
intr_context
bool intr_context(void)
Returns true during processing of an external interrupt and false at all other times.
Definition: interrupt.c:212
sema_self_test
void sema_self_test(void)
Self-test for semaphores that makes control "ping-pong" between a pair of threads.
Definition: synch.c:129
intr_level
intr_level
Interrupts on or off?
Definition: interrupt.h:8
NULL
#define NULL
Definition: stddef.h:4
string.h
list_init
void list_init(struct list *list)
Initializes LIST as an empty list.
Definition: list.c:61
lock::holder
struct thread * holder
Thread holding lock (for debugging).
Definition: synch.h:23
lock_init
void lock_init(struct lock *lock)
Initializes LOCK.
Definition: synch.c:176
intr_set_level
enum intr_level intr_set_level(enum intr_level level)
Enables or disables interrupts as specified by LEVEL and returns the previous interrupt status.
Definition: interrupt.c:81
semaphore
A counting semaphore.
Definition: synch.h:8
semaphore_elem::semaphore
struct semaphore semaphore
This semaphore.
Definition: synch.c:253
UNUSED
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
thread
A kernel thread or user process.
Definition: thread.h:83
semaphore_elem
One semaphore in a list.
Definition: synch.c:250
sema_up
void sema_up(struct semaphore *sema)
Up or "V" operation on a semaphore.
Definition: synch.c:109
thread_current
struct thread * thread_current(void)
Returns the running thread.
Definition: thread.c:256
thread_block
void thread_block(void)
Puts the current thread to sleep.
Definition: thread.c:214
cond_broadcast
void cond_broadcast(struct condition *cond, struct lock *lock)
Wakes up all threads, if any, waiting on COND (protected by LOCK).
Definition: synch.c:331
semaphore::waiters
struct list waiters
List of waiting threads.
Definition: synch.h:11
cond_init
void cond_init(struct condition *cond)
Initializes condition variable COND.
Definition: synch.c:260
sema_try_down
bool sema_try_down(struct semaphore *sema)
Down or "P" operation on a semaphore, but only if the semaphore is not already 0.
Definition: synch.c:84
lock_held_by_current_thread
bool lock_held_by_current_thread(const struct lock *lock)
Returns true if the current thread holds LOCK, false otherwise.
Definition: synch.c:242
interrupt.h
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
sema_down
void sema_down(struct semaphore *sema)
Down or "P" operation on a semaphore.
Definition: synch.c:61
cond_wait
void cond_wait(struct condition *cond, struct lock *lock)
Atomically releases LOCK and waits for COND to be signaled by some other piece of code.
Definition: synch.c:288
cond_signal
void cond_signal(struct condition *cond, struct lock *lock UNUSED)
If any threads are waiting on COND (protected by LOCK), then this function signals one of them to wak...
Definition: synch.c:312
intr_disable
enum intr_level intr_disable(void)
Disables interrupts and returns the previous interrupt status.
Definition: interrupt.c:104
list_empty
bool list_empty(struct list *list)
Returns true if LIST is empty, false otherwise.
Definition: list.c:310
ASSERT
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
list_pop_front
struct list_elem * list_pop_front(struct list *list)
Removes the front element from LIST and returns it.
Definition: list.c:260
sema_init
void sema_init(struct semaphore *sema, unsigned value)
This file is derived from source code for the Nachos instructional operating system.
Definition: synch.c:45
semaphore_elem::elem
struct list_elem elem
List element.
Definition: synch.c:252
value
A linked list element.
Definition: list.c:22
condition::waiters
struct list waiters
List of waiting threads.
Definition: synch.h:36
lock_try_acquire
bool lock_try_acquire(struct lock *lock)
Tries to acquires LOCK and returns true if successful or false on failure.
Definition: synch.c:210
thread_create
tid_t thread_create(const char *name, int priority, thread_func *function, void *aux)
Creates a new kernel thread named NAME with the given initial PRIORITY, which executes FUNCTION passi...
Definition: thread.c:166
sema_test_helper
static void sema_test_helper(void *sema_)
Thread function used by sema_self_test().
Definition: synch.c:148
semaphore::value
unsigned value
Current value.
Definition: synch.h:10
lock::semaphore
struct semaphore semaphore
Binary semaphore controlling access.
Definition: synch.h:24
list_push_back
void list_push_back(struct list *list, struct list_elem *elem)
Inserts ELEM at the end of LIST, so that it becomes the back in LIST.
Definition: list.c:217
thread_unblock
void thread_unblock(struct thread *t)
Transitions a blocked thread T to the ready-to-run state.
Definition: thread.c:232
lock_acquire
void lock_acquire(struct lock *lock)
Acquires LOCK, sleeping until it becomes available if necessary.
Definition: synch.c:193
thread.h
synch.h
lock
Lock.
Definition: synch.h:21
condition
Condition variable.
Definition: synch.h:34
PRI_DEFAULT
#define PRI_DEFAULT
Default priority.
Definition: thread.h:24
sema
static struct semaphore sema
Definition: priority-sema.c:13