Implementation of IO Ring in Windows
Fixing the two compilation warnings.
This commit is contained in:
285
ioringapi.c
Normal file
285
ioringapi.c
Normal file
@@ -0,0 +1,285 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
|
||||
// Forward declarations
|
||||
typedef struct IORING_HANDLE_REF IORING_HANDLE_REF;
|
||||
typedef struct IORING_BUFFER_REF IORING_BUFFER_REF;
|
||||
typedef void *HIORING;
|
||||
|
||||
/* --------------------- Types declaration --------------------- */
|
||||
typedef enum IORING_CREATE_ADVISORY_FLAGS {
|
||||
IORING_CREATE_ADVISORY_FLAGS_NONE,
|
||||
IORING_CREATE_SKIP_BUILDER_PARAM_CHECKS
|
||||
} IORING_CREATE_ADVISORY_FLAGS;
|
||||
// Specifies advisory flags for creating an I/O ring with a call to
|
||||
// CreateIoRing.
|
||||
|
||||
typedef enum IORING_CREATE_REQUIRED_FLAGS {
|
||||
IORING_CREATE_REQUIRED_FLAGS_NONE
|
||||
} IORING_CREATE_REQUIRED_FLAGS;
|
||||
// Specifies required flags for creating an I/O ring with a call to
|
||||
// CreateIoRing.
|
||||
|
||||
typedef enum IORING_REF_KIND {
|
||||
IORING_REF_RAW = 0,
|
||||
IORING_REF_REGISTERED = 1,
|
||||
} IORING_REF_KIND;
|
||||
// Specifies the type of an IORING_HANDLE_REF structure.
|
||||
|
||||
typedef enum IORING_SQE_FLAGS {
|
||||
IOSQE_FLAGS_NONE,
|
||||
IOSQE_FLAGS_DRAIN_PRECEDING_OPS
|
||||
} IORING_SQE_FLAGS;
|
||||
// Specifies kernel behavior options for I/O ring submission queue entries
|
||||
|
||||
// IORING_REGISTERED_BUFFER structure
|
||||
typedef struct IORING_REGISTERED_BUFFER {
|
||||
UINT32 Index;
|
||||
UINT32 Offset;
|
||||
} IORING_REGISTERED_BUFFER;
|
||||
|
||||
// IORING_HANDLE_REF
|
||||
struct IORING_HANDLE_REF {
|
||||
IORING_REF_KIND Kind;
|
||||
union {
|
||||
HANDLE Handle;
|
||||
UINT32 Index;
|
||||
} HandleUnion;
|
||||
};
|
||||
// Represents a reference to a file handle used in an I/O ring operation
|
||||
|
||||
// IORING_BUFFER_REF
|
||||
struct IORING_BUFFER_REF {
|
||||
IORING_REF_KIND Kind;
|
||||
union {
|
||||
void *Address;
|
||||
IORING_REGISTERED_BUFFER IndexAndOffset;
|
||||
} BufferUnion;
|
||||
};
|
||||
|
||||
typedef struct IORING_BUFFER_INFO {
|
||||
void *Address;
|
||||
UINT32 Length;
|
||||
} IORING_BUFFER_INFO;
|
||||
|
||||
// IORING_BUFFER_REF represents a reference to a buffer used in an I/O ring
|
||||
// operation
|
||||
|
||||
// IORING_VERSION enumeration
|
||||
typedef enum IORING_VERSION {
|
||||
IORING_VERSION_INVALID = 0,
|
||||
IORING_VERSION_1 = 1,
|
||||
IORING_VERSION_2 = 2,
|
||||
IORING_VERSION_3 = 3,
|
||||
IORING_VERSION_4 = 4,
|
||||
} IORING_VERSION;
|
||||
|
||||
typedef enum IORING_FEATURE_FLAGS {
|
||||
IORING_FEATURE_FLAGS_NONE = 0,
|
||||
IORING_FEATURE_UM_EMULATION = 1
|
||||
} IORING_FEATURE_FLAGS;
|
||||
|
||||
// IORING_CAPABILITIES structure
|
||||
typedef struct IORING_CAPABILITIES {
|
||||
IORING_VERSION MaxVersion;
|
||||
UINT32 MaxSubmissionQueueSize;
|
||||
UINT32 MaxCompletionQueueSize;
|
||||
IORING_FEATURE_FLAGS FeatureFlags;
|
||||
} IORING_CAPABILITIES;
|
||||
// Represents the IORING API capabilities.
|
||||
|
||||
// IORING_CQE structure
|
||||
typedef struct IORING_CQE {
|
||||
UINT_PTR UserData;
|
||||
HRESULT ResultCode;
|
||||
ULONG_PTR Information;
|
||||
} IORING_CQE;
|
||||
// Represents a completed I/O ring queue entry.
|
||||
|
||||
// IORING_CREATE_FLAGS structure
|
||||
typedef struct IORING_CREATE_FLAGS {
|
||||
IORING_CREATE_REQUIRED_FLAGS Required;
|
||||
IORING_CREATE_ADVISORY_FLAGS Advisory;
|
||||
} IORING_CREATE_FLAGS;
|
||||
// Specifies flags for creating an I/O ring with a call to CreateIoRing.
|
||||
|
||||
// IORING_INFO structure
|
||||
typedef struct IORING_INFO {
|
||||
IORING_VERSION IoRingVersion;
|
||||
IORING_CREATE_FLAGS Flags;
|
||||
UINT32 SubmissionQueueSize;
|
||||
UINT32 CompletionQueueSize;
|
||||
} IORING_INFO;
|
||||
// Represents the shape and version information for the specified I/O ring
|
||||
|
||||
// IORING_OP_CODE for IsIoRingOpSupported
|
||||
typedef enum IORING_OP_CODE {
|
||||
IORING_OP_NOP = 0,
|
||||
IORING_OP_READ = 1,
|
||||
IORING_OP_WRITE = 2,
|
||||
IORING_OP_FLUSH = 3,
|
||||
IORING_OP_REGISTER_BUFFERS = 4,
|
||||
IORING_OP_REGISTER_FILES = 5,
|
||||
IORING_OP_CANCEL = 6,
|
||||
} IORING_OP_CODE;
|
||||
|
||||
/* --------------------- Dynamic loader --------------------- */
|
||||
// Function pointer types
|
||||
typedef BOOL(WINAPI *IsIoRingOpSupported_t)(HIORING, IORING_OP_CODE);
|
||||
typedef HRESULT(WINAPI *QueryIoRingCapabilities_t)(IORING_CAPABILITIES *);
|
||||
typedef HRESULT(WINAPI *GetIoRingInfo_t)(HIORING, IORING_INFO *);
|
||||
typedef HRESULT(WINAPI *CreateIoRing_t)(IORING_VERSION, IORING_CREATE_FLAGS,
|
||||
UINT32, UINT32, HIORING *);
|
||||
typedef HRESULT(WINAPI *CloseIoRing_t)(HIORING);
|
||||
typedef HRESULT(WINAPI *SubmitIoRing_t)(HIORING, UINT32, UINT32, UINT32 *);
|
||||
typedef HRESULT(WINAPI *PopIoRingCompletion_t)(HIORING, IORING_CQE *);
|
||||
typedef HRESULT(WINAPI *SetIoRingCompletionEvent_t)(HIORING, HANDLE);
|
||||
typedef HRESULT(WINAPI *BuildIoRingCancelRequest_t)(HIORING, IORING_HANDLE_REF,
|
||||
UINT_PTR, UINT_PTR);
|
||||
typedef HRESULT(WINAPI *BuildIoRingReadFile_t)(HIORING, IORING_HANDLE_REF,
|
||||
IORING_BUFFER_REF, UINT32,
|
||||
UINT64, UINT_PTR,
|
||||
IORING_SQE_FLAGS);
|
||||
typedef HRESULT(WINAPI *BuildIoRingRegisterBuffers_t)(
|
||||
HIORING, UINT32, IORING_BUFFER_INFO const[], UINT_PTR);
|
||||
|
||||
typedef HRESULT(WINAPI *BuildIoRingRegisterFileHandles_t)(HIORING, UINT32,
|
||||
HANDLE const[],
|
||||
UINT_PTR);
|
||||
|
||||
// Core:
|
||||
// Queries the support of the specified operation for the specified I/O ring
|
||||
static IsIoRingOpSupported_t IsIoRingOpSupported = NULL;
|
||||
|
||||
// Queries the OS for the supported capabilities for IORINGs
|
||||
static QueryIoRingCapabilities_t QueryIoRingCapabilities = NULL;
|
||||
|
||||
// Gets information about the API version and queue sizes of an I/O ring
|
||||
static GetIoRingInfo_t GetIoRingInfo = NULL;
|
||||
|
||||
// Creates a new instance of an I/O ring submission/completion queue pair and
|
||||
// returns a handle for referencing the I/O ring
|
||||
static CreateIoRing_t CreateIoRing = NULL;
|
||||
|
||||
// Closes an HIORING handle that was previously opened with a call to
|
||||
// CreateIoRing
|
||||
static CloseIoRing_t CloseIoRing = NULL;
|
||||
|
||||
// Submission / completion:
|
||||
// Submits all constructed but not yet submitted entries to the kernel’s queue
|
||||
// and optionally waits for a set of operations to complete
|
||||
static SubmitIoRing_t SubmitIoRing = NULL;
|
||||
|
||||
// Pops a single entry from the completion queue, if one is available
|
||||
static PopIoRingCompletion_t PopIoRingCompletion = NULL;
|
||||
|
||||
// Registers a completion queue event with an IORING
|
||||
static SetIoRingCompletionEvent_t SetIoRingCompletionEvent = NULL;
|
||||
|
||||
// Operations:
|
||||
// Performs an asynchronous read from a file using an I/O ring
|
||||
static BuildIoRingReadFile_t BuildIoRingReadFile = NULL;
|
||||
|
||||
// Attempts to cancel a previously submitted I/O ring operation
|
||||
static BuildIoRingCancelRequest_t BuildIoRingCancelRequest = NULL;
|
||||
|
||||
// Registers an array of buffers with the system for future I/O ring operations
|
||||
static BuildIoRingRegisterBuffers_t BuildIoRingRegisterBuffers = NULL;
|
||||
|
||||
// Registers an array of file handles with the system for future I/O ring
|
||||
// operations
|
||||
static BuildIoRingRegisterFileHandles_t BuildIoRingRegisterFileHandles = NULL;
|
||||
|
||||
static int io_ring_loaded = 0;
|
||||
|
||||
static int io_ring_load_functions(void) {
|
||||
if (io_ring_loaded)
|
||||
return 1;
|
||||
|
||||
HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
|
||||
if (!hKernel)
|
||||
return 0;
|
||||
|
||||
IsIoRingOpSupported =
|
||||
(IsIoRingOpSupported_t)GetProcAddress(hKernel, "IsIoRingOpSupported");
|
||||
QueryIoRingCapabilities = (QueryIoRingCapabilities_t)GetProcAddress(
|
||||
hKernel, "QueryIoRingCapabilities");
|
||||
GetIoRingInfo = (GetIoRingInfo_t)GetProcAddress(hKernel, "GetIoRingInfo");
|
||||
CreateIoRing = (CreateIoRing_t)GetProcAddress(hKernel, "CreateIoRing");
|
||||
CloseIoRing = (CloseIoRing_t)GetProcAddress(hKernel, "CloseIoRing");
|
||||
SubmitIoRing = (SubmitIoRing_t)GetProcAddress(hKernel, "SubmitIoRing");
|
||||
PopIoRingCompletion =
|
||||
(PopIoRingCompletion_t)GetProcAddress(hKernel, "PopIoRingCompletion");
|
||||
SetIoRingCompletionEvent = (SetIoRingCompletionEvent_t)GetProcAddress(
|
||||
hKernel, "SetIoRingCompletionEvent");
|
||||
BuildIoRingReadFile =
|
||||
(BuildIoRingReadFile_t)GetProcAddress(hKernel, "BuildIoRingReadFile");
|
||||
BuildIoRingCancelRequest = (BuildIoRingCancelRequest_t)GetProcAddress(
|
||||
hKernel, "BuildIoRingCancelRequest");
|
||||
BuildIoRingRegisterBuffers = (BuildIoRingRegisterBuffers_t)GetProcAddress(
|
||||
hKernel, "BuildIoRingRegisterBuffers");
|
||||
BuildIoRingRegisterFileHandles =
|
||||
(BuildIoRingRegisterFileHandles_t)GetProcAddress(
|
||||
hKernel, "BuildIoRingRegisterFileHandles");
|
||||
|
||||
io_ring_loaded =
|
||||
(IsIoRingOpSupported && QueryIoRingCapabilities && CreateIoRing &&
|
||||
CloseIoRing && SubmitIoRing && PopIoRingCompletion &&
|
||||
SetIoRingCompletionEvent && BuildIoRingReadFile &&
|
||||
BuildIoRingCancelRequest && BuildIoRingRegisterBuffers &&
|
||||
BuildIoRingRegisterFileHandles);
|
||||
|
||||
if (io_ring_loaded)
|
||||
printf("[I/O Ring] Functions loaded\n");
|
||||
else
|
||||
printf("[I/O Ring] Some functions not available\n");
|
||||
|
||||
return io_ring_loaded;
|
||||
}
|
||||
|
||||
/* ------------- Standard helper functions definition ------------- */
|
||||
// Creates an instance of the IORING_BUFFER_REF structure with the provided
|
||||
// buffer index and offset
|
||||
static inline IORING_BUFFER_REF
|
||||
IoRingBufferRefFromIndexAndOffset(UINT32 index, UINT32 offset) {
|
||||
IORING_BUFFER_REF ref;
|
||||
ref.Kind = IORING_REF_REGISTERED;
|
||||
ref.BufferUnion.IndexAndOffset.Index = index;
|
||||
ref.BufferUnion.IndexAndOffset.Offset = offset;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// Creates an instance of the IORING_BUFFER_REF structure from the provided
|
||||
// pointer
|
||||
static IORING_BUFFER_REF IoRingBufferRefFromPointer(void *addr) {
|
||||
IORING_BUFFER_REF ref;
|
||||
ref.Kind = IORING_REF_RAW;
|
||||
ref.BufferUnion.Address = addr;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// Creates an instance of the IORING_HANDLE_REF structure from the provided file
|
||||
// handle
|
||||
static IORING_HANDLE_REF IoRingHandleRefFromHandle(HANDLE h) {
|
||||
IORING_HANDLE_REF ref;
|
||||
ref.Kind = IORING_REF_RAW;
|
||||
ref.HandleUnion.Handle = h;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// Creates an instance of the IORING_HANDLE_REF structure from the provided
|
||||
// index
|
||||
static inline IORING_HANDLE_REF IoRingHandleRefFromIndex(UINT32 index) {
|
||||
IORING_HANDLE_REF ref;
|
||||
ref.Kind = IORING_REF_REGISTERED; // MUST be registered
|
||||
ref.HandleUnion.Index = index;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// NOTE: If you are using index-based buffers or handles, make sure you have
|
||||
// successfully called BuildIoRingRegisterBuffers or
|
||||
// BuildIoRingRegisterFileHandles first so the kernel has a valid table to look
|
||||
// into, otherwise the kernel will treat the index as an invalid memory
|
||||
// address/handle.
|
||||
Reference in New Issue
Block a user