]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Futex hash improv and minor cleanups
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 24 Sep 2003 13:41:32 +0000 (06:41 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 24 Sep 2003 13:41:32 +0000 (06:41 -0700)
Minor changes to Jamie & Hugh's excellent futex patch.
 1) Remove obsolete comment above hash array decl.
 2) Clarify comment about TASK_INTERRUPTIBLE.
 3) Andrew Morton says spurious wakeup is a bug.  Catch it.
 4) Use Jenkins hash.
 5) Make hash function non-inline.

kernel/futex.c

index 1a354ba725225838740742ed71f92b623771c166..db0a81a810dd0502f1ca9716a5ad6b7a890992cc 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/hash.h>
+#include <linux/jhash.h>
 #include <linux/init.h>
 #include <linux/futex.h>
 #include <linux/mount.h>
@@ -44,6 +44,7 @@
 /*
  * Futexes are matched on equal values of this key.
  * The key type depends on whether it's a shared or private mapping.
+ * Don't rearrange members without looking at hash_futex().
  */
 union futex_key {
        struct {
@@ -87,7 +88,6 @@ struct futex_hash_bucket {
        struct list_head       chain;
 };
 
-/* The key for the hash is the address + index + offset within page */
 static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
 
 /* Futex-fs vfsmount entry: */
@@ -96,11 +96,12 @@ static struct vfsmount *futex_mnt;
 /*
  * We hash on the keys returned from get_futex_key (see below).
  */
-static inline struct futex_hash_bucket *hash_futex(union futex_key *key)
+static struct futex_hash_bucket *hash_futex(union futex_key *key)
 {
-       return &futex_queues[hash_long(key->both.word
-                                      + (unsigned long) key->both.ptr
-                                      + key->both.offset, FUTEX_HASHBITS)];
+       u32 hash = jhash2((u32*)&key->both.word,
+                         (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+                         key->both.offset);
+       return &futex_queues[hash & ((1 << FUTEX_HASHBITS)-1)];
 }
 
 /*
@@ -361,7 +362,6 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
        struct futex_q q;
        struct futex_hash_bucket *bh = NULL;
 
- try_again:
        init_waitqueue_head(&q.waiters);
 
        down_read(&current->mm->mmap_sem);
@@ -395,10 +395,10 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
        /*
         * There might have been scheduling since the queue_me(), as we
         * cannot hold a spinlock across the get_user() in case it
-        * faults.  So we cannot just set TASK_INTERRUPTIBLE state when
+        * faults, and we cannot just set TASK_INTERRUPTIBLE state when
         * queueing ourselves into the futex hash.  This code thus has to
-        * rely on the futex_wake() code doing a wakeup after removing
-        * the waiter from the list.
+        * rely on the futex_wake() code removing us from hash when it
+        * wakes us up.
         */
        add_wait_queue(&q.waiters, &wait);
        bh = hash_futex(&key);
@@ -423,26 +423,17 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
         * we are the only user of it.
         */
 
-       /*
-        * Were we woken or interrupted for a valid reason?
-        */
-       ret = unqueue_me(&q);
-       if (ret == 0)
+       /* If we were woken (and unqueued), we succeeded, whatever. */
+       if (!unqueue_me(&q))
                return 0;
        if (time == 0)
                return -ETIMEDOUT;
-       if (signal_pending(current))
-               return -EINTR;
-
-       /*
-        * No, it was a spurious wakeup.  Try again.  Should never happen. :)
-        */
-       goto try_again;
+       /* A spurious wakeup should never happen. */
+       WARN_ON(!signal_pending(current));
+       return -EINTR;
 
  out_unqueue:
-       /*
-        * Were we unqueued anyway?
-        */
+       /* If we were woken (and unqueued), we succeeded, whatever. */
        if (!unqueue_me(&q))
                ret = 0;
  out_release_sem: