aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-01 11:45:14 -0500
committerIngo Molnar <mingo@elte.hu>2008-02-01 11:45:14 -0500
commitcd689985cf49f6ff5c8eddc48d98b9d581d9475d (patch)
treea1a119402f5208c45c21b855e8d2fbbaf18cfd72 /kernel/futex.c
parent83e96c604e781098a2f61b8a294919bcf3abfab4 (diff)
futex: Add bitset conditional wait/wakeup functionality
To allow the implementation of optimized rw-locks in user space, glibc needs a possibility to select waiters for wakeup depending on a bitset mask. This requires two new futex OPs: FUTEX_WAIT_BITS and FUTEX_WAKE_BITS These OPs are basically the same as FUTEX_WAIT and FUTEX_WAKE plus an additional argument - a bitset. Further the FUTEX_WAIT_BITS OP is expecting an absolute timeout value instead of the relative one, which is used for the FUTEX_WAIT OP. FUTEX_WAIT_BITS calls into the kernel with a bitset. The bitset is stored in the futex_q structure, which is used to enqueue the waiter into the hashed futex waitqueue. FUTEX_WAKE_BITS also calls into the kernel with a bitset. The wakeup function logically ANDs the bitset with the bitset stored in each waiters futex_q structure. If the result is zero (i.e. none of the set bits in the bitsets is matching), then the waiter is not woken up. If the result is not zero (i.e. one of the set bits in the bitsets is matching), then the waiter is woken. The bitset provided by the caller must be non zero. In case the provided bitset is zero the kernel returns EINVAL. Internaly the new OPs are only extensions to the existing FUTEX_WAIT and FUTEX_WAKE functions. The existing OPs hand a bitset with all bits set into the futex_wait() and futex_wake() functions. Signed-off-by: Thomas Gleixner <tgxl@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 0006d64c448e..a6baaec44b8f 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -109,6 +109,9 @@ struct futex_q {
109 /* Optional priority inheritance state: */ 109 /* Optional priority inheritance state: */
110 struct futex_pi_state *pi_state; 110 struct futex_pi_state *pi_state;
111 struct task_struct *task; 111 struct task_struct *task;
112
113 /* Bitset for the optional bitmasked wakeup */
114 u32 bitset;
112}; 115};
113 116
114/* 117/*
@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
722 * to this virtual address: 725 * to this virtual address:
723 */ 726 */
724static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, 727static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
725 int nr_wake) 728 int nr_wake, u32 bitset)
726{ 729{
727 struct futex_hash_bucket *hb; 730 struct futex_hash_bucket *hb;
728 struct futex_q *this, *next; 731 struct futex_q *this, *next;
@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
730 union futex_key key; 733 union futex_key key;
731 int ret; 734 int ret;
732 735
736 if (!bitset)
737 return -EINVAL;
738
733 futex_lock_mm(fshared); 739 futex_lock_mm(fshared);
734 740
735 ret = get_futex_key(uaddr, fshared, &key); 741 ret = get_futex_key(uaddr, fshared, &key);
@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
746 ret = -EINVAL; 752 ret = -EINVAL;
747 break; 753 break;
748 } 754 }
755
756 /* Check if one of the bits is set in both bitsets */
757 if (!(this->bitset & bitset))
758 continue;
759
749 wake_futex(this); 760 wake_futex(this);
750 if (++ret >= nr_wake) 761 if (++ret >= nr_wake)
751 break; 762 break;
@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
1156static long futex_wait_restart(struct restart_block *restart); 1167static long futex_wait_restart(struct restart_block *restart);
1157 1168
1158static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, 1169static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1159 u32 val, ktime_t *abs_time) 1170 u32 val, ktime_t *abs_time, u32 bitset)
1160{ 1171{
1161 struct task_struct *curr = current; 1172 struct task_struct *curr = current;
1162 DECLARE_WAITQUEUE(wait, curr); 1173 DECLARE_WAITQUEUE(wait, curr);
@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1167 struct hrtimer_sleeper t; 1178 struct hrtimer_sleeper t;
1168 int rem = 0; 1179 int rem = 0;
1169 1180
1181 if (!bitset)
1182 return -EINVAL;
1183
1170 q.pi_state = NULL; 1184 q.pi_state = NULL;
1185 q.bitset = bitset;
1171 retry: 1186 retry:
1172 futex_lock_mm(fshared); 1187 futex_lock_mm(fshared);
1173 1188
@@ -1295,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1295 restart->futex.uaddr = (u32 *)uaddr; 1310 restart->futex.uaddr = (u32 *)uaddr;
1296 restart->futex.val = val; 1311 restart->futex.val = val;
1297 restart->futex.time = abs_time->tv64; 1312 restart->futex.time = abs_time->tv64;
1313 restart->futex.bitset = bitset;
1298 restart->futex.flags = 0; 1314 restart->futex.flags = 0;
1299 1315
1300 if (fshared) 1316 if (fshared)
@@ -1321,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
1321 restart->fn = do_no_restart_syscall; 1337 restart->fn = do_no_restart_syscall;
1322 if (restart->futex.flags & FLAGS_SHARED) 1338 if (restart->futex.flags & FLAGS_SHARED)
1323 fshared = &current->mm->mmap_sem; 1339 fshared = &current->mm->mmap_sem;
1324 return (long)futex_wait(uaddr, fshared, restart->futex.val, &t); 1340 return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
1341 restart->futex.bitset);
1325} 1342}
1326 1343
1327 1344
@@ -1942,7 +1959,8 @@ retry:
1942 * PI futexes happens in exit_pi_state(): 1959 * PI futexes happens in exit_pi_state():
1943 */ 1960 */
1944 if (!pi && (uval & FUTEX_WAITERS)) 1961 if (!pi && (uval & FUTEX_WAITERS))
1945 futex_wake(uaddr, &curr->mm->mmap_sem, 1); 1962 futex_wake(uaddr, &curr->mm->mmap_sem, 1,
1963 FUTEX_BITSET_MATCH_ANY);
1946 } 1964 }
1947 return 0; 1965 return 0;
1948} 1966}
@@ -2042,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
2042 2060
2043 switch (cmd) { 2061 switch (cmd) {
2044 case FUTEX_WAIT: 2062 case FUTEX_WAIT:
2045 ret = futex_wait(uaddr, fshared, val, timeout); 2063 val3 = FUTEX_BITSET_MATCH_ANY;
2064 case FUTEX_WAIT_BITSET:
2065 ret = futex_wait(uaddr, fshared, val, timeout, val3);
2046 break; 2066 break;
2047 case FUTEX_WAKE: 2067 case FUTEX_WAKE:
2048 ret = futex_wake(uaddr, fshared, val); 2068 val3 = FUTEX_BITSET_MATCH_ANY;
2069 case FUTEX_WAKE_BITSET:
2070 ret = futex_wake(uaddr, fshared, val, val3);
2049 break; 2071 break;
2050 case FUTEX_FD: 2072 case FUTEX_FD:
2051 /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */ 2073 /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -2085,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
2085 u32 val2 = 0; 2107 u32 val2 = 0;
2086 int cmd = op & FUTEX_CMD_MASK; 2108 int cmd = op & FUTEX_CMD_MASK;
2087 2109
2088 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { 2110 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
2111 cmd == FUTEX_WAIT_BITSET)) {
2089 if (copy_from_user(&ts, utime, sizeof(ts)) != 0) 2112 if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
2090 return -EFAULT; 2113 return -EFAULT;
2091 if (!timespec_valid(&ts)) 2114 if (!timespec_valid(&ts))