diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2003-09-24 06:41:32 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-09-24 06:41:32 -0700 |
| commit | a97d8d460e17d2c003e3e79112be0b328dc854bb (patch) | |
| tree | ec41eff4813d8ebd299385bb3b5cf8b6c6a4b2a8 /kernel | |
| parent | b58da0d02df9eee7a000162ccad1f64f7651b0c5 (diff) | |
[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.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/futex.c | 41 |
1 files changed, 16 insertions, 25 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 1a354ba72522..db0a81a810dd 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -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(¤t->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: |
