Skip to content

Commit

Permalink
Fix #4 - added probe method to test supported operations
Browse files Browse the repository at this point in the history
  • Loading branch information
tchaloupka committed Nov 6, 2021
1 parent 6554d1b commit 30eff38
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 9 deletions.
10 changes: 7 additions & 3 deletions source/during/io_uring.d
Original file line number Diff line number Diff line change
Expand Up @@ -1268,18 +1268,22 @@ struct io_uring_probe_op
ubyte op;
ubyte resv;
ushort flags; /* IO_URING_OP_* flags */
uint resv2;
private uint resv2;
}

static assert(io_uring_probe_op.sizeof == 8);

struct io_uring_probe
{
ubyte last_op; /* last opcode supported */
ubyte ops_len; /* length of ops[] array below */
ushort resv;
uint[3] resv2;
private ushort resv;
private uint[3] resv2;
io_uring_probe_op[0] ops;
}

static assert(io_uring_probe.sizeof == 16);

struct io_uring_restriction
{
RestrictionOp opcode;
Expand Down
66 changes: 63 additions & 3 deletions source/during/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ nothrow @nogc:
*
* Returns: On succes it returns 0, `-errno` otherwise.
*/
int setup(ref Uring uring, uint entries = 128, SetupFlags flags = SetupFlags.NONE)
int setup(ref Uring uring, uint entries = 128, SetupFlags flags = SetupFlags.NONE) @safe
{
assert(uring.payload is null, "Uring is already initialized");
uring.payload = cast(UringDesc*)calloc(1, UringDesc.sizeof);
uring.payload = () @trusted { return cast(UringDesc*)calloc(1, UringDesc.sizeof); }();
if (uring.payload is null) return -errno;

uring.payload.params.flags = flags;
Expand All @@ -60,6 +60,52 @@ int setup(ref Uring uring, uint entries = 128, SetupFlags flags = SetupFlags.NON
return 0;
}

/**
* Simplified wrapper around `io_uring_probe` that is used to check what io_uring operations current
* kernel is actually supporting.
*/
struct Probe
{
static assert (Operation.max < 64, "Needs to be adjusted");
private
{
io_uring_probe probe;
io_uring_probe_op[64] ops;
int err;
}

const @safe pure nothrow @nogc:

/// Is operation supported?
bool isSupported(Operation op)
in (op <= Operation.max, "Invalid operation")
{
if (op > probe.last_op) return false;
assert(ops[op].op == op, "Operations differs");
return (ops[op].flags & IO_URING_OP_SUPPORTED) != 0;
}

/// Error code when we fail to get `Probe`.
@property int error() { return err; }

/// `true` if probe was sucesfully retrieved.
T opCast(T)() if (is(T == bool)) { return err == 0; }
}

/// Probes supported operations on a temporary created uring instance
Probe probe() @safe nothrow @nogc
{
Uring io;
immutable ret = io.setup(2);
if (ret < 0) {
Probe res;
res.err = ret;
return res;
}

return io.probe();
}

/**
* Main entry point to work with io_uring.
*
Expand Down Expand Up @@ -94,6 +140,20 @@ struct Uring
dispose(this);
}

/// Probes supported operations
Probe probe() @safe
in (payload !is null, "Uring hasn't been initialized yet")
{
Probe res;
immutable ret = () @trusted { return io_uring_register(
payload.fd,
RegisterOpCode.REGISTER_PROBE,
cast(void*)&res.probe, res.ops.length
); }();
if (ret < 0) res.err = ret;
return res;
}

/// Native io_uring file descriptor
int fd() const @safe pure
in (payload !is null, "Uring hasn't been initialized yet")
Expand Down Expand Up @@ -405,7 +465,7 @@ struct Uring
immutable r = io_uring_register(
payload.fd,
RegisterOpCode.REGISTER_BUFFERS,
cast(const(void)*)&payload.regBuffers[0], 1
cast(const(void)*)payload.regBuffers.ptr, 1
);

if (_expect(r < 0, false)) return -errno;
Expand Down
6 changes: 3 additions & 3 deletions tests/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ auto openFile(T)(T fname, int flags)
}

// Check if the kernel release of our system is at least at the major.minor version
bool checkKernelVersion(uint emajor, uint eminor)
bool checkKernelVersion(uint emajor, uint eminor) @safe
{
import core.stdc.stdio : sscanf, printf;
utsname buf;
if (syscall(SYS_uname, &buf) < 0) {
if (() @trusted { return syscall(SYS_uname, &buf); }() < 0) {
assert(0, "call to uname failed");
}

int major, minor;
sscanf(buf.release.ptr, "%d.%d", &major, &minor); // we only care about the first two numbers
() @trusted { sscanf(buf.release.ptr, "%d.%d", &major, &minor); }(); // we only care about the first two numbers
if (major < emajor) return false; // is our retrieved major below the expected major?
if (minor < eminor) return false; // is our retrieved minor below the expected minor?
return true;
Expand Down
25 changes: 25 additions & 0 deletions tests/register.d
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,28 @@ unittest
ret = io.unregisterEventFD();
assert(ret == 0);
}

@("probe")
@safe unittest
{
if (!checkKernelVersion(5, 6)) return;

{
auto prob = probe();
assert(prob);
assert(prob.error == 0);
assert(prob.isSupported(Operation.RECV));
}

{
// prepare uring
Uring io;
auto res = io.setup(4);
assert(res >= 0, "Error initializing IO");

auto prob = io.probe();
assert(prob);
assert(prob.error == 0);
assert(prob.isSupported(Operation.RECV));
}
}

0 comments on commit 30eff38

Please sign in to comment.