commit-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[hurd] 33/64: Add atomicity support to fshelp_acquire_lock


From: Samuel Thibault
Subject: [hurd] 33/64: Add atomicity support to fshelp_acquire_lock
Date: Wed, 10 Dec 2014 15:17:06 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch upstream
in repository hurd.

commit 7ca4c02513d7c6998d9c92dafb3c0fcbe8d6dd6d
Author: Samuel Thibault <address@hidden>
Date:   Thu Nov 27 19:05:57 2014 +0100

    Add atomicity support to fshelp_acquire_lock
    
    This adds support for the __LOCK_ATOMIC flag which requests atomicity of 
SH->EX
    upgrades and EX->SH downgrades.
    
    * libfshelp/lock-acquire.c (__LOCK_ATOMIC): New macro
    (fshelp_acquire_lock): When __LOCK_ATOMIC is set, do not release the
    lock early, change the lock hold atomically instead. On upgrade to LOCK_EX,
    prevent new shared locks from being acquired to avoid starvation.
---
 libfshelp/lock-acquire.c | 95 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 77 insertions(+), 18 deletions(-)

diff --git a/libfshelp/lock-acquire.c b/libfshelp/lock-acquire.c
index 574bc5c..06c93d8 100644
--- a/libfshelp/lock-acquire.c
+++ b/libfshelp/lock-acquire.c
@@ -23,17 +23,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 
02139, USA.  */
 
 #define EWOULDBLOCK EAGAIN /* XXX */
 
+/* Remove this when glibc has it.  */
+#ifndef __LOCK_ATOMIC
+#define __LOCK_ATOMIC 16
+#endif
+
 error_t
 fshelp_acquire_lock (struct lock_box *box, int *user, pthread_mutex_t *mut,
                     int flags)
 {
+  int atomic = 0;
+
   if (!(flags & (LOCK_UN | LOCK_EX | LOCK_SH)))
     return 0;
   
   if ((flags & LOCK_UN)
       && (flags & (LOCK_SH | LOCK_EX)))
     return EINVAL;
-  
+
+  if (flags & __LOCK_ATOMIC)
+    {
+      atomic = 1;
+      flags &= ~__LOCK_ATOMIC;
+    }
+
   if (flags & LOCK_EX)
     flags &= ~LOCK_SH;
   
@@ -44,8 +57,10 @@ fshelp_acquire_lock (struct lock_box *box, int *user, 
pthread_mutex_t *mut,
       if (*user & LOCK_UN)
        return 0;
 
-      assert (*user == box->type);
-      assert (*user == LOCK_SH || *user == LOCK_EX);
+      assert (*user == box->type ||
+             (*user == LOCK_SH && box->type == (LOCK_SH | LOCK_EX)));
+      assert (*user == LOCK_SH || *user == LOCK_EX ||
+             *user == (LOCK_SH | LOCK_EX));
 
       if (*user == LOCK_SH)
        {
@@ -60,12 +75,39 @@ fshelp_acquire_lock (struct lock_box *box, int *user, 
pthread_mutex_t *mut,
          box->waiting = 0;
          pthread_cond_broadcast (&box->wait);
        }
+      if (box->type == (LOCK_SH | LOCK_EX) && box->shcount == 1 && 
box->waiting)
+       {
+         box->waiting = 0;
+         pthread_cond_broadcast (&box->wait);
+       }
       *user = LOCK_UN;
     }
   else
     {
+      if (atomic && *user == (flags & (LOCK_SH | LOCK_EX)))
+       /* Already have it the right way. */
+       return 0;
+
+      if (atomic && *user == LOCK_EX && flags & LOCK_SH)
+       {
+         /* Easy atomic change. */
+         *user = LOCK_SH;
+         box->type = LOCK_SH;
+         box->shcount = 1;
+         if (box->waiting)
+           {
+             box->waiting = 0;
+             pthread_cond_broadcast (&box->wait);
+           }
+         return 0;
+       }
+
+      /* We can not have two people upgrading their lock, this is a deadlock! 
*/
+      if (*user == LOCK_SH && atomic && box->type == (LOCK_SH | LOCK_EX))
+       return EDEADLK;
+
       /* If we have an exclusive lock, release it. */
-      if (*user == LOCK_EX)
+      if (*user == LOCK_EX && !atomic)
        {
          *user = LOCK_UN;
          box->type = LOCK_UN;
@@ -75,19 +117,9 @@ fshelp_acquire_lock (struct lock_box *box, int *user, 
pthread_mutex_t *mut,
              pthread_cond_broadcast (&box->wait);
            }
        }
-      
-      /* If there is an exclusive lock, wait for it to end. */
-      while (box->type == LOCK_EX)
-       {
-         if (flags & LOCK_NB)
-           return EWOULDBLOCK;
-         box->waiting = 1;
-         if (pthread_hurd_cond_wait_np (&box->wait, mut))
-           return EINTR;
-       }
 
       /* If we have a shared lock, release it. */
-      if (*user == LOCK_SH)
+      if (*user == LOCK_SH && !atomic)
        {
          *user = LOCK_UN;
          if (!--box->shcount)
@@ -99,12 +131,29 @@ fshelp_acquire_lock (struct lock_box *box, int *user, 
pthread_mutex_t *mut,
                  pthread_cond_broadcast (&box->wait);
                }
            }
+         if (box->type == (LOCK_SH | LOCK_EX) && box->shcount == 1 &&
+             box->waiting)
+           {
+             box->waiting = 0;
+             pthread_cond_broadcast (&box->wait);
+           }
        }
-      
+
+      /* If there is another exclusive lock or a pending upgrade, wait for it 
to
+        end. */
+      while (box->type & LOCK_EX)
+       {
+         if (flags & LOCK_NB)
+           return EWOULDBLOCK;
+         box->waiting = 1;
+         if (pthread_hurd_cond_wait_np (&box->wait, mut))
+           return EINTR;
+       }
+
       assert ((flags & LOCK_SH) || (flags & LOCK_EX));
       if (flags & LOCK_SH)
        {
-         assert (box->type != LOCK_EX);
+         assert (!(box->type & LOCK_EX));
          *user = LOCK_SH;
          box->type = LOCK_SH;
          box->shcount++;
@@ -112,17 +161,27 @@ fshelp_acquire_lock (struct lock_box *box, int *user, 
pthread_mutex_t *mut,
       else if (flags & LOCK_EX)
        {
          /* Wait for any shared (and exclusive) locks to finish. */
-         while (box->type != LOCK_UN)
+         while ((*user == LOCK_SH && box->shcount > 1) ||
+                (*user == LOCK_UN && box->type != LOCK_UN))
            {
              if (flags & LOCK_NB)
                return EWOULDBLOCK;
              else
                {
+                 /* Tell others that we are upgrading.  */
+                 if (*user == LOCK_SH && atomic)
+                   box->type = LOCK_SH | LOCK_EX;
+
                  box->waiting = 1;
                  if (pthread_hurd_cond_wait_np (&box->wait, mut))
                    return EINTR;
                }
            }
+         if (*user == LOCK_SH)
+           {
+             assert (box->shcount == 1);
+             box->shcount = 0;
+           }
          box->type = LOCK_EX;
          *user = LOCK_EX;
        }

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

[Prev in Thread] Current Thread [Next in Thread]