Commit a97d8d46 authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] Futex hash improv and minor cleanups

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