diff options
author | dchagin <dchagin@FreeBSD.org> | 2011-01-31 05:59:05 +0000 |
---|---|---|
committer | dchagin <dchagin@FreeBSD.org> | 2011-01-31 05:59:05 +0000 |
commit | 6570332d31939a8f1b325739d41b69e95d140823 (patch) | |
tree | da8320a9f3e2d8e307c6165b98d22538dce54223 | |
parent | 126cbabd2e530d55dd2c3a7871426f0fe8ada608 (diff) | |
download | FreeBSD-src-6570332d31939a8f1b325739d41b69e95d140823.zip FreeBSD-src-6570332d31939a8f1b325739d41b69e95d140823.tar.gz |
Implement a futex BITSET op.
Submitted by: arundel
MFC after: 1 month.
-rw-r--r-- | sys/compat/linux/linux_futex.c | 69 | ||||
-rw-r--r-- | sys/compat/linux/linux_futex.h | 2 |
2 files changed, 46 insertions, 25 deletions
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 219b601..6ee293f 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -79,6 +79,7 @@ struct futex { struct sx f_lck; uint32_t *f_uaddr; uint32_t f_refcount; + uint32_t f_bitset; LIST_ENTRY(futex) f_list; TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc; }; @@ -264,15 +265,25 @@ futex_sleep(struct futex *f, struct waiting_proc *wp, int timeout) } static int -futex_wake(struct futex *f, int n) +futex_wake(struct futex *f, int n, uint32_t bitset) { struct waiting_proc *wp, *wpt; int count = 0; + if (bitset == 0) + return (EINVAL); + FUTEX_ASSERT_LOCKED(f); TAILQ_FOREACH_SAFE(wp, &f->f_waiting_proc, wp_list, wpt) { LINUX_CTR3(sys_futex, "futex_wake uaddr %p wp %p ref %d", f->f_uaddr, wp, f->f_refcount); + /* + * Unless we find a matching bit in + * the bitset, continue searching. + */ + if (!(wp->wp_futex->f_bitset & bitset)) + continue; + wp->wp_flags |= FUTEX_WP_REMOVED; TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); wakeup_one(wp); @@ -325,13 +336,18 @@ futex_requeue(struct futex *f, int n, struct futex *f2, int n2) } static int -futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts) +futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts, + uint32_t bitset) { struct l_timespec timeout; struct timeval tv; int timeout_hz; int error; + if (bitset == 0) + return (EINVAL); + f->f_bitset = bitset; + if (ts != NULL) { error = copyin(ts, &timeout, sizeof(timeout)); if (error) @@ -445,13 +461,18 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) switch (args->op) { case LINUX_FUTEX_WAIT: + args->val3 = FUTEX_BITSET_MATCH_ANY; + /* FALLTHROUGH */ + + case LINUX_FUTEX_WAIT_BITSET: - LINUX_CTR2(sys_futex, "WAIT val %d uaddr %p", - args->val, args->uaddr); + LINUX_CTR3(sys_futex, "WAIT uaddr %p val %d val3 %d", + args->uaddr, args->val, args->val3); #ifdef DEBUG if (ldebug(sys_futex)) - printf(ARGS(sys_futex, "futex_wait val %d uaddr %p"), - args->val, args->uaddr); + printf(ARGS(sys_futex, + "futex_wait uaddr %p val %d val3 %d"), + args->uaddr, args->val, args->val3); #endif error = futex_get(args->uaddr, &wp, &f, FUTEX_CREATE_WP); if (error) @@ -464,19 +485,24 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) return (error); } if (val != args->val) { - LINUX_CTR3(sys_futex, "WAIT uaddr %p val %d != uval %d", - args->uaddr, args->val, val); + LINUX_CTR4(sys_futex, + "WAIT uaddr %p val %d != uval %d val3 %d", + args->uaddr, args->val, val, args->val3); futex_put(f, wp); return (EWOULDBLOCK); } - error = futex_wait(f, wp, args->timeout); + error = futex_wait(f, wp, args->timeout, args->val3); break; case LINUX_FUTEX_WAKE: + args->val3 = FUTEX_BITSET_MATCH_ANY; + /* FALLTHROUGH */ + + case LINUX_FUTEX_WAKE_BITSET: - LINUX_CTR2(sys_futex, "WAKE val %d uaddr %p", - args->val, args->uaddr); + LINUX_CTR3(sys_futex, "WAKE uaddr %p val % d val3 %d", + args->uaddr, args->val, args->val3); /* * XXX: Linux is able to cope with different addresses @@ -485,8 +511,8 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) */ #ifdef DEBUG if (ldebug(sys_futex)) - printf(ARGS(sys_futex, "futex_wake val %d uaddr %p"), - args->val, args->uaddr); + printf(ARGS(sys_futex, "futex_wake uaddr %p val %d val3 %d"), + args->uaddr, args->val, args->val3); #endif error = futex_get(args->uaddr, NULL, &f, FUTEX_DONTCREATE); if (error) @@ -495,7 +521,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) td->td_retval[0] = 0; return (error); } - td->td_retval[0] = futex_wake(f, args->val); + td->td_retval[0] = futex_wake(f, args->val, args->val3); futex_put(f, NULL); break; @@ -603,16 +629,16 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) return (EFAULT); } - ret = futex_wake(f, args->val); + ret = futex_wake(f, args->val, args->val3); if (op_ret > 0) { op_ret = 0; nrwake = (int)(unsigned long)args->timeout; if (f2 != NULL) - op_ret += futex_wake(f2, nrwake); + op_ret += futex_wake(f2, nrwake, args->val3); else - op_ret += futex_wake(f, nrwake); + op_ret += futex_wake(f, nrwake, args->val3); ret += op_ret; } @@ -660,13 +686,6 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) } return (EINVAL); - case LINUX_FUTEX_WAIT_BITSET: - /* not yet implemented */ - linux_msg(td, - "linux_sys_futex: " - "op FUTEX_WAIT_BITSET not implemented\n"); - return (ENOSYS); - case LINUX_FUTEX_WAIT_REQUEUE_PI: /* not yet implemented */ linux_msg(td, @@ -775,7 +794,7 @@ retry: if (error) return (error); if (f != NULL) { - futex_wake(f, 1); + futex_wake(f, 1, FUTEX_BITSET_MATCH_ANY); futex_put(f, NULL); } } diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h index 4ccd46c..3eb38b2 100644 --- a/sys/compat/linux/linux_futex.h +++ b/sys/compat/linux/linux_futex.h @@ -49,6 +49,7 @@ extern struct mtx futex_mtx; #define LINUX_FUTEX_UNLOCK_PI 7 #define LINUX_FUTEX_TRYLOCK_PI 8 #define LINUX_FUTEX_WAIT_BITSET 9 +#define LINUX_FUTEX_WAKE_BITSET 10 #define LINUX_FUTEX_WAIT_REQUEUE_PI 11 #define LINUX_FUTEX_PRIVATE_FLAG 128 @@ -72,6 +73,7 @@ extern struct mtx futex_mtx; #define FUTEX_WAITERS 0x80000000 #define FUTEX_OWNER_DIED 0x40000000 #define FUTEX_TID_MASK 0x3fffffff +#define FUTEX_BITSET_MATCH_ANY 0xffffffff void release_futexes(struct proc *); |