Improve comment on sema_down.
[pintos-anon] / src / threads / synch.c
index d7601dacddc89f7c772d3340cf0e856b81c82f09..317c68ad501301538f47a697df7a8eaf02d4e077 100644 (file)
    MODIFICATIONS.
 */
 
-#include "synch.h"
-#include "interrupt.h"
-#include "lib.h"
-#include "thread.h"
+#include "threads/synch.h"
+#include <stdio.h>
+#include <string.h>
+#include "threads/interrupt.h"
+#include "threads/thread.h"
 
-/* Initializes semaphore SEMA to VALUE and names it NAME (for
-   debugging purposes only).  A semaphore is a nonnegative
-   integer along with two atomic operators for manipulating it:
+/* Initializes semaphore SEMA to VALUE.  A semaphore is a
+   nonnegative integer along with two atomic operators for
+   manipulating it:
 
    - down or "P": wait for the value to become positive, then
      decrement it.
    - up or "V": increment the value (and wake up one waiting
      thread, if any). */
 void
-sema_init (struct semaphore *sema, unsigned value, const char *name
+sema_init (struct semaphore *sema, unsigned value) 
 {
   ASSERT (sema != NULL);
-  ASSERT (name != NULL);
 
-  strlcpy (sema->name, name, sizeof sema->name);
   sema->value = value;
   list_init (&sema->waiters);
 }
@@ -56,8 +55,8 @@ sema_init (struct semaphore *sema, unsigned value, const char *name)
 
    This function may sleep, so it must not be called within an
    interrupt handler.  This function may be called with
-   interrupts disabled, but interrupts will be turned back on if
-   we need to sleep. */
+   interrupts disabled, but if it sleeps then the next scheduled
+   thread will probably turn interrupts back on. */
 void
 sema_down (struct semaphore *sema) 
 {
@@ -76,6 +75,32 @@ sema_down (struct semaphore *sema)
   intr_set_level (old_level);
 }
 
+/* Down or "P" operation on a semaphore, but only if the
+   semaphore is not already 0.  Returns true if the semaphore is
+   decremented, false otherwise.
+
+   This function may be called from an interrupt handler. */
+bool
+sema_try_down (struct semaphore *sema) 
+{
+  enum intr_level old_level;
+  bool success;
+
+  ASSERT (sema != NULL);
+
+  old_level = intr_disable ();
+  if (sema->value > 0) 
+    {
+      sema->value--;
+      success = true; 
+    }
+  else
+    success = false;
+  intr_set_level (old_level);
+
+  return success;
+}
+
 /* Up or "V" operation on a semaphore.  Increments SEMA's value
    and wakes up one thread of those waiting for SEMA, if any.
 
@@ -95,35 +120,27 @@ sema_up (struct semaphore *sema)
   intr_set_level (old_level);
 }
 
-/* Return SEMA's name (for debugging purposes). */
-const char *
-sema_name (const struct semaphore *sema) 
-{
-  return sema->name;
-}
-
 static void sema_test_helper (void *sema_);
 
 /* Self-test for semaphores that makes control "ping-pong"
-   between a pair of threads.  Insert calls to printk() to see
+   between a pair of threads.  Insert calls to printf() to see
    what's going on. */
 void
 sema_self_test (void) 
 {
-  struct thread *thread;
   struct semaphore sema[2];
   int i;
 
-  printk ("Testing semaphores...");
-  sema_init (&sema[0], 0, "ping");
-  sema_init (&sema[1], 0, "pong");
-  thread = thread_create ("sema-test", sema_test_helper, &sema);
+  printf ("Testing semaphores...");
+  sema_init (&sema[0], 0);
+  sema_init (&sema[1], 0);
+  thread_create ("sema-test", PRI_DEFAULT, sema_test_helper, &sema);
   for (i = 0; i < 10; i++) 
     {
       sema_up (&sema[0]);
       sema_down (&sema[1]);
     }
-  printk ("done.\n");
+  printf ("done.\n");
 }
 
 /* Thread function used by sema_self_test(). */
@@ -140,11 +157,10 @@ sema_test_helper (void *sema_)
     }
 }
 \f
-/* Initializes LOCK and names it NAME (for debugging purposes).
-   A lock can be held by at most a single thread at any given
-   time.  Our locks are not "recursive", that is, it is an error
-   for the thread currently holding a lock to try to acquire that
-   lock.
+/* Initializes LOCK.  A lock can be held by at most a single
+   thread at any given time.  Our locks are not "recursive", that
+   is, it is an error for the thread currently holding a lock to
+   try to acquire that lock.
 
    A lock is a specialization of a semaphore with an initial
    value of 1.  The difference between a lock and such a
@@ -157,14 +173,12 @@ sema_test_helper (void *sema_)
    onerous, it's a good sign that a semaphore should be used,
    instead of a lock. */
 void
-lock_init (struct lock *lock, const char *name)
+lock_init (struct lock *lock)
 {
   ASSERT (lock != NULL);
-  ASSERT (name != NULL);
 
-  strlcpy (lock->name, name, sizeof lock->name);
   lock->holder = NULL;
-  sema_init (&lock->semaphore, 1, name);
+  sema_init (&lock->semaphore, 1);
 }
 
 /* Acquires LOCK, sleeping until it becomes available if
@@ -178,35 +192,47 @@ lock_init (struct lock *lock, const char *name)
 void
 lock_acquire (struct lock *lock)
 {
-  enum intr_level old_level;
-
   ASSERT (lock != NULL);
   ASSERT (!intr_context ());
   ASSERT (!lock_held_by_current_thread (lock));
 
-  old_level = intr_disable ();
   sema_down (&lock->semaphore);
   lock->holder = thread_current ();
-  intr_set_level (old_level);
+}
+
+/* Tries to acquires LOCK and returns true if successful or false
+   on failure.  The lock must not already be held by the current
+   thread.
+
+   This function will not sleep, so it may be called within an
+   interrupt handler. */
+bool
+lock_try_acquire (struct lock *lock)
+{
+  bool success;
+
+  ASSERT (lock != NULL);
+  ASSERT (!lock_held_by_current_thread (lock));
+
+  success = sema_try_down (&lock->semaphore);
+  if (success)
+    lock->holder = thread_current ();
+  return success;
 }
 
 /* Releases LOCK, which must be owned by the current thread.
 
    An interrupt handler cannot acquire a lock, so it does not
-   make sense to try to signal a condition variable within an
-   interrupt handler. */
+   make sense to try to release a lock within an interrupt
+   handler. */
 void
 lock_release (struct lock *lock) 
 {
-  enum intr_level old_level;
-
   ASSERT (lock != NULL);
   ASSERT (lock_held_by_current_thread (lock));
 
-  old_level = intr_disable ();
   lock->holder = NULL;
   sema_up (&lock->semaphore);
-  intr_set_level (old_level);
 }
 
 /* Returns true if the current thread holds LOCK, false
@@ -219,39 +245,27 @@ lock_held_by_current_thread (const struct lock *lock)
 
   return lock->holder == thread_current ();
 }
-
-/* Returns the name of LOCK (for debugging purposes). */
-const char *
-lock_name (const struct lock *lock) 
-{
-  ASSERT (lock != NULL);
-
-  return lock->name;
-}
 \f
 /* One semaphore in a list. */
 struct semaphore_elem 
   {
-    list_elem elem;                     /* List element. */
+    struct list_elem elem;              /* List element. */
     struct semaphore semaphore;         /* This semaphore. */
   };
 
-/* Initializes condition variable COND and names it NAME.  A
-   condition variable allows one piece of code to signal a
-   condition and cooperating code to receive the signal and act
-   upon it. */
+/* Initializes condition variable COND.  A condition variable
+   allows one piece of code to signal a condition and cooperating
+   code to receive the signal and act upon it. */
 void
-cond_init (struct condition *cond, const char *name) 
+cond_init (struct condition *cond)
 {
   ASSERT (cond != NULL);
-  ASSERT (name != NULL);
 
-  strlcpy (cond->name, name, sizeof cond->name);
   list_init (&cond->waiters);
 }
 
 /* Atomically releases LOCK and waits for COND to be signaled by
-   some other piece of code.  After COND is signalled, LOCK is
+   some other piece of code.  After COND is signaled, LOCK is
    reacquired before returning.  LOCK must be held before calling
    this function.
 
@@ -262,7 +276,7 @@ cond_init (struct condition *cond, const char *name)
    again.
 
    A given condition variable is associated with only a single
-   lock, but one lock may be be associated with any number of
+   lock, but one lock may be associated with any number of
    condition variables.  That is, there is a one-to-many mapping
    from locks to condition variables.
 
@@ -280,7 +294,7 @@ cond_wait (struct condition *cond, struct lock *lock)
   ASSERT (!intr_context ());
   ASSERT (lock_held_by_current_thread (lock));
   
-  sema_init (&waiter.semaphore, 0, "condition");
+  sema_init (&waiter.semaphore, 0);
   list_push_back (&cond->waiters, &waiter.elem);
   lock_release (lock);
   sema_down (&waiter.semaphore);
@@ -295,7 +309,7 @@ cond_wait (struct condition *cond, struct lock *lock)
    make sense to try to signal a condition variable within an
    interrupt handler. */
 void
-cond_signal (struct condition *cond, struct lock *lock) 
+cond_signal (struct condition *cond, struct lock *lock UNUSED
 {
   ASSERT (cond != NULL);
   ASSERT (lock != NULL);
@@ -322,12 +336,3 @@ cond_broadcast (struct condition *cond, struct lock *lock)
   while (!list_empty (&cond->waiters))
     cond_signal (cond, lock);
 }
-
-/* Returns COND's name (for debugging purposes). */
-const char *
-cond_name (const struct condition *cond)
-{
-  ASSERT (cond != NULL);
-
-  return cond->name;
-}