Closed YoSTEALTH closed 5 months ago
It's a bit confusing because futex2 is really just a modified futex API. In particular, things like futex waitv falls under futex2.
Any of the flags that are named FUTEX2_* are the ones you can pass in ->futex_flags, see:
for example. These all/mostly have mirrors in the regular futex flags. Outside of that, the API can just be considered as described in futex(2).
Linux 6.7.4
I added the basic defines: https://github.com/YoSTEALTH/Liburing/blob/master/src/liburing/lib/futex.pxd
I think it would be nice for define names to be similar, either all the defines should be FUTEX_*
or FUTEX2_*
, having both futex and futex2 is just confusing.
I have also re-coded couple of C test into Python from test/futex.c
:
def test_multi_wake():
val = 0
mask = liburing.FUTEX_BITSET_MATCH_ANY
futex = array.array('I', [0])
futex_flags = liburing.FUTEX2_SIZE_U32
ring = liburing.io_uring()
cqe = liburing.io_uring_cqe()
try:
assert liburing.io_uring_queue_init(8, ring) == 0
# Submit two futex waits
sqe = liburing.io_uring_get_sqe(ring)
liburing.io_uring_prep_futex_wait(sqe, futex, val, mask, futex_flags)
sqe.user_data = 1
sqe = liburing.io_uring_get_sqe(ring)
liburing.io_uring_prep_futex_wait(sqe, futex, val, mask, futex_flags)
sqe.user_data = 2
assert liburing.io_uring_submit(ring) == 2
# Now submit wake for just one futex
futex[0] = 1
sqe = liburing.io_uring_get_sqe(ring)
liburing.io_uring_prep_futex_wake(sqe, futex, 2, mask, futex_flags)
sqe.user_data = 100
assert liburing.io_uring_submit(ring) == 1
# We expect to find completions for the both futex waits, and the futex wake.
for i in range(3):
assert liburing.io_uring_wait_cqe(ring, cqe) == 0
assert cqe.res >= 0
liburing.io_uring_cqe_seen(ring, cqe)
assert liburing.io_uring_peek_cqe(ring, cqe) == -errno.EAGAIN
finally:
liburing.io_uring_queue_exit(ring)
This test fails cqe.user_data != 2
:
def test_futex_wake_zero():
val = 0
mask = liburing.FUTEX_BITSET_MATCH_ANY
futex = array.array('I', [0])
futex_flags = liburing.FUTEX2_SIZE_U32
ring = liburing.io_uring()
cqe = liburing.io_uring_cqe()
try:
assert liburing.io_uring_queue_init(8, ring) == 0
sqe = liburing.io_uring_get_sqe(ring)
liburing.io_uring_prep_futex_wait(sqe, futex, val, mask, futex_flags)
sqe.user_data = 1
assert liburing.io_uring_submit(ring) == 1
sqe = liburing.io_uring_get_sqe(ring)
liburing.io_uring_prep_futex_wake(sqe, futex, val, mask, futex_flags)
sqe.user_data = 2
assert liburing.io_uring_submit(ring) == 1
assert liburing.io_uring_wait_cqe(ring, cqe) == 0
# Should get zero res and it should be the wake
assert cqe.res == 0
assert cqe.user_data != 2 # *** This is where it fails `2 != 2` ***
liburing.io_uring_cqe_seen(ring, cqe)
# Should not have the wait complete
with pytest.raises(BlockingIOError):
liburing.trap_error(liburing.io_uring_peek_cqe(ring, cqe))
finally:
del futex
liburing.io_uring_queue_exit(ring)
This is where the C code is, https://github.com/axboe/liburing/blob/master/test/futex.c#L363-L365 logic doesn't match comment? &&
vs ||
?
You probably got the wait completion first? You seem to be making assumptions about the wake posting first, and the above sequence will post two of them.
It is a logic error in the test, but it'll pass just fine with &&
as well.
Ya, going with your comment, this works:
# Should get zero res and it should be the wake
assert cqe.res == 0 and cqe.user_data == 2
FUTEX_CLOCK_REALTIME
is not used or supported by io_uring
right?
Not sure why this is closed! futex2
manual is still needed to be created though or io_uring_futex_*
manual needs to be improved... futex2
being added into io_uring
is an amazing thing. I can see lots of people using it, better to be prepared vs everyone having to spends days readings bit here and there to figure out how to actually use it.
Thanks Jens and sorry to be nitpicking.
I'm not going to write the futex2(2) man page, and the guy behind it is on leave right now. I'll be happy to add the relevant futex flags to the liburing man page, though.
I'm not going to write the futex2(2) man page, and the guy behind it is on leave right now.
I see, makes sense.
I'll be happy to add the relevant futex flags to the liburing man page, though.
Cool.
I found 6.8.0-rc6
https://docs.kernel.org/userspace-api/futex2.html in it mentioned "32 bit sized futex" being supported . Clearly in futex.h
there is FUTEX2_SIZE_U8, FUTEX2_SIZE_U16, FUTEX2_SIZE_U32, ...
confusing.
Is there any advantage to using io_uring_prep_futex_waitv
the interface with struct and having to pass external managed futex_state
(available, unavailable) is quite cumbersome.
I been looking all over for
futex2(2)
manual, referenced inman io_uring_prep_futex_*
, ... I can't find it. I am trying to define properfutex_flags
.