Implement a futex BITSET op.

Submitted by:	arundel
MFC after:	1 month.
This commit is contained in:
dchagin 2011-01-31 05:59:05 +00:00
parent 126cbabd2e
commit 6570332d31
2 changed files with 46 additions and 25 deletions

View File

@ -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 */
LINUX_CTR2(sys_futex, "WAIT val %d uaddr %p",
args->val, args->uaddr);
case LINUX_FUTEX_WAIT_BITSET:
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 */
LINUX_CTR2(sys_futex, "WAKE val %d uaddr %p",
args->val, args->uaddr);
case LINUX_FUTEX_WAKE_BITSET:
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 @@ handle_futex_death(struct proc *p, uint32_t *uaddr, int pi)
if (error)
return (error);
if (f != NULL) {
futex_wake(f, 1);
futex_wake(f, 1, FUTEX_BITSET_MATCH_ANY);
futex_put(f, NULL);
}
}

View File

@ -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 *);