Improve comment on sema_down.
[pintos-anon] / src / threads / synch.c
index d7601dacddc89f7c772d3340cf0e856b81c82f09..317c68ad501301538f47a697df7a8eaf02d4e077 100644 (file)
    MODIFICATIONS.
 */
 
    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.
 
    - 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
    - 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 (sema != NULL);
-  ASSERT (name != NULL);
 
 
-  strlcpy (sema->name, name, sizeof sema->name);
   sema->value = value;
   list_init (&sema->waiters);
 }
   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
 
    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) 
 {
 void
 sema_down (struct semaphore *sema) 
 {
@@ -76,6 +75,32 @@ sema_down (struct semaphore *sema)
   intr_set_level (old_level);
 }
 
   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.
 
 /* 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);
 }
 
   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"
 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) 
 {
    what's going on. */
 void
 sema_self_test (void) 
 {
-  struct thread *thread;
   struct semaphore sema[2];
   int i;
 
   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]);
     }
   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(). */
 }
 
 /* Thread function used by sema_self_test(). */
@@ -140,11 +157,10 @@ sema_test_helper (void *sema_)
     }
 }
 \f
     }
 }
 \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
 
    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
    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 (lock != NULL);
-  ASSERT (name != NULL);
 
 
-  strlcpy (lock->name, name, sizeof lock->name);
   lock->holder = NULL;
   lock->holder = NULL;
-  sema_init (&lock->semaphore, 1, name);
+  sema_init (&lock->semaphore, 1);
 }
 
 /* Acquires LOCK, sleeping until it becomes available if
 }
 
 /* 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)
 {
 void
 lock_acquire (struct lock *lock)
 {
-  enum intr_level old_level;
-
   ASSERT (lock != NULL);
   ASSERT (!intr_context ());
   ASSERT (!lock_held_by_current_thread (lock));
 
   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 ();
   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
 }
 
 /* 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) 
 {
 void
 lock_release (struct lock *lock) 
 {
-  enum intr_level old_level;
-
   ASSERT (lock != NULL);
   ASSERT (lock_held_by_current_thread (lock));
 
   ASSERT (lock != NULL);
   ASSERT (lock_held_by_current_thread (lock));
 
-  old_level = intr_disable ();
   lock->holder = NULL;
   sema_up (&lock->semaphore);
   lock->holder = NULL;
   sema_up (&lock->semaphore);
-  intr_set_level (old_level);
 }
 
 /* Returns true if the current thread holds LOCK, false
 }
 
 /* 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 ();
 }
 
   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 
   {
 \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. */
   };
 
     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
 void
-cond_init (struct condition *cond, const char *name) 
+cond_init (struct condition *cond)
 {
   ASSERT (cond != NULL);
 {
   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
   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.
 
    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
    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.
 
    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));
   
   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);
   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
    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);
 {
   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);
 }
   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;
-}