asyncio: Windows IoRing support, other tweaks and fixes.

This commit is contained in:
Ryan C. Gordon
2024-10-07 16:56:35 -04:00
parent 3ca629ceb5
commit 4745aa3324
8 changed files with 621 additions and 34 deletions

View File

@@ -522,6 +522,7 @@
<ClCompile Include="..\..\src\filesystem\windows\SDL_sysfsops.c" />
<ClCompile Include="..\..\src\file\generic\SDL_asyncio_generic.c" />
<ClCompile Include="..\..\src\file\SDL_asyncio.c" />
<ClCompile Include="..\..\src\file\windows\SDL_asyncio_windows_ioring.c" />
<ClCompile Include="..\..\src\main\gdk\SDL_sysmain_runapp.cpp" />
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" />
<ClCompile Include="..\..\src\main\SDL_main_callbacks.c" />

View File

@@ -19,6 +19,9 @@
<ClCompile Include="..\..\src\file\SDL_asyncio.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="..\..\src\file\windows\SDL_asyncio_windows_ioring.c">
<Filter>file\windows</Filter>
</ClCompile>
<ClCompile Include="..\..\src\render\direct3d12\SDL_render_d3d12_xbox.cpp" />
<ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12_xboxone.cpp" />
<ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12_xboxseries.cpp" />

View File

@@ -415,6 +415,7 @@
<ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c" />
<ClCompile Include="..\..\src\filesystem\SDL_filesystem.c" />
<ClCompile Include="..\..\src\filesystem\windows\SDL_sysfsops.c" />
<ClCompile Include="..\..\src\file\windows\SDL_asyncio_windows_ioring.c" />
<ClCompile Include="..\..\src\gpu\SDL_gpu.c" />
<ClCompile Include="..\..\src\gpu\d3d12\SDL_gpu_d3d12.c" />
<ClCompile Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan.c" />

View File

@@ -214,6 +214,9 @@
<Filter Include="file\generic">
<UniqueIdentifier>{00004d6806b6238cae0ed62db5440000}</UniqueIdentifier>
</Filter>
<Filter Include="file\windows">
<UniqueIdentifier>{000028b2ea36d7190d13777a4dc70000}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\SDL3\SDL_begin_code.h">
@@ -962,6 +965,9 @@
<ClCompile Include="..\..\src\file\SDL_asyncio.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="..\..\src\file\windows\SDL_asyncio_windows_ioring.c">
<Filter>file\windows</Filter>
</ClCompile>
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c">
<Filter>main\generic</Filter>
</ClCompile>

View File

@@ -552,6 +552,7 @@
00005081394CCF8322BE0000 /* SDL_sysasyncio.h in Headers */ = {isa = PBXBuildFile; fileRef = 0000585B2CAB450B40540000 /* SDL_sysasyncio.h */; };
000018AF97C08F2DAFFD0000 /* SDL_asyncio.h in Headers */ = {isa = PBXBuildFile; fileRef = 00004945A946DF5B1AED0000 /* SDL_asyncio.h */; settings = {ATTRIBUTES = (Public, ); }; };
00004D0B73767647AD550000 /* SDL_asyncio_generic.c in Sources */ = {isa = PBXBuildFile; fileRef = 0000FB02CDE4BE34A87E0000 /* SDL_asyncio_generic.c */; };
0000A03C0F32C43816F40000 /* SDL_asyncio_windows_ioring.c in Sources */ = {isa = PBXBuildFile; fileRef = 000030DD21496B5C0F210000 /* SDL_asyncio_windows_ioring.c */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -1134,6 +1135,7 @@
0000585B2CAB450B40540000 /* SDL_sysasyncio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_sysasyncio.h; path = SDL_sysasyncio.h; sourceTree = "<group>"; };
00004945A946DF5B1AED0000 /* SDL_asyncio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_asyncio.h; path = SDL3/SDL_asyncio.h; sourceTree = "<group>"; };
0000FB02CDE4BE34A87E0000 /* SDL_asyncio_generic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_asyncio_generic.c; path = SDL_asyncio_generic.c; sourceTree = "<group>"; };
000030DD21496B5C0F210000 /* SDL_asyncio_windows_ioring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_asyncio_windows_ioring.c; path = SDL_asyncio_windows_ioring.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -1947,6 +1949,7 @@
0000919399B1A908267F0000 /* SDL_asyncio_c.h */,
0000585B2CAB450B40540000 /* SDL_sysasyncio.h */,
000013C0F2EADC24ADC10000 /* generic */,
000064F9A2AAE947C1CD0000 /* windows */,
);
path = file;
sourceTree = "<group>";
@@ -2447,6 +2450,14 @@
path = generic;
sourceTree = "<group>";
};
000064F9A2AAE947C1CD0000 /* windows */ = {
isa = PBXGroup;
children = (
000030DD21496B5C0F210000 /* SDL_asyncio_windows_ioring.c */,
);
path = windows;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -3073,6 +3084,7 @@
6312C66D2B42341400A7BB00 /* SDL_murmur3.c in Sources */,
0000AEB9AE90228CA2D60000 /* SDL_asyncio.c in Sources */,
00004D0B73767647AD550000 /* SDL_asyncio_generic.c in Sources */,
0000A03C0F32C43816F40000 /* SDL_asyncio_windows_ioring.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -24,11 +24,17 @@
#ifndef SDL_sysasyncio_h_
#define SDL_sysasyncio_h_
#if defined(SDL_PLATFORM_WINDOWS) && defined(NTDDI_WIN10_CO)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && NTDDI_VERSION >= NTDDI_WIN10_CO
#define HAVE_IORINGAPI_H
#endif
#endif
// If your platform has an option other than the "generic" code, make sure this
// is #defined to 0 instead and implement the SDL_SYS_* functions below in your
// backend (having them maybe call into the SDL_SYS_*_Generic versions as a
// fallback if the platform has functionality that isn't always available).
#ifdef HAVE_LIBURING_H
#if defined(HAVE_LIBURING_H) || defined(HAVE_IORINGAPI_H)
#define SDL_ASYNCIO_ONLY_HAVE_GENERIC 0
#else
#define SDL_ASYNCIO_ONLY_HAVE_GENERIC 1

View File

@@ -130,6 +130,7 @@ static bool LoadLibUring(void)
result = LoadLibUringSyms();
if (result) {
static const int needed_ops[] = {
IORING_OP_NOP,
IORING_OP_FSYNC,
IORING_OP_TIMEOUT,
IORING_OP_CLOSE,
@@ -193,16 +194,21 @@ static void liburing_asyncioqueue_cancel_task(void *userdata, SDL_AsyncIOTask *t
}
LibUringAsyncIOQueueData *queuedata = (LibUringAsyncIOQueueData *) userdata;
// have to hold a lock because otherwise two threads could get_sqe and submit while one request isn't fully set up.
SDL_LockMutex(queuedata->sqe_lock);
struct io_uring_sqe *sqe = liburing.io_uring_get_sqe(&queuedata->ring);
if (!sqe) {
SDL_free(cancel_task);
return; // oh well, the task can just finish on its own.
SDL_UnlockMutex(queuedata->sqe_lock);
SDL_free(cancel_task); // oh well, the task can just finish on its own.
return;
}
cancel_task->app_userdata = task;
liburing.io_uring_prep_cancel(sqe, task, 0);
liburing.io_uring_sqe_set_data(sqe, cancel_task);
liburing_asyncioqueue_queue_task(userdata, task);
SDL_UnlockMutex(queuedata->sqe_lock);
}
static SDL_AsyncIOTask *ProcessCQE(LibUringAsyncIOQueueData *queuedata, struct io_uring_cqe *cqe)
@@ -375,15 +381,15 @@ static bool liburing_asyncio_read(void *userdata, SDL_AsyncIOTask *task)
// have to hold a lock because otherwise two threads could get_sqe and submit while one request isn't fully set up.
SDL_LockMutex(queuedata->sqe_lock);
bool retval;
struct io_uring_sqe *sqe = liburing.io_uring_get_sqe(&queuedata->ring);
if (!sqe) {
return SDL_SetError("io_uring: submission queue is full");
}
retval = SDL_SetError("io_uring: submission queue is full");
} else {
liburing.io_uring_prep_read(sqe, fd, task->buffer, (unsigned) task->requested_size, task->offset);
liburing.io_uring_sqe_set_data(sqe, task);
const bool retval = task->queue->iface.queue_task(task->queue->userdata, task);
retval = task->queue->iface.queue_task(task->queue->userdata, task);
}
SDL_UnlockMutex(queuedata->sqe_lock);
return retval;
}
@@ -401,15 +407,15 @@ static bool liburing_asyncio_write(void *userdata, SDL_AsyncIOTask *task)
// have to hold a lock because otherwise two threads could get_sqe and submit while one request isn't fully set up.
SDL_LockMutex(queuedata->sqe_lock);
bool retval;
struct io_uring_sqe *sqe = liburing.io_uring_get_sqe(&queuedata->ring);
if (!sqe) {
return SDL_SetError("io_uring: submission queue is full");
}
retval = SDL_SetError("io_uring: submission queue is full");
} else {
liburing.io_uring_prep_write(sqe, fd, task->buffer, (unsigned) task->requested_size, task->offset);
liburing.io_uring_sqe_set_data(sqe, task);
const bool retval = task->queue->iface.queue_task(task->queue->userdata, task);
retval = task->queue->iface.queue_task(task->queue->userdata, task);
}
SDL_UnlockMutex(queuedata->sqe_lock);
return retval;
}
@@ -421,11 +427,11 @@ static bool liburing_asyncio_close(void *userdata, SDL_AsyncIOTask *task)
// have to hold a lock because otherwise two threads could get_sqe and submit while one request isn't fully set up.
SDL_LockMutex(queuedata->sqe_lock);
bool retval;
struct io_uring_sqe *sqe = liburing.io_uring_get_sqe(&queuedata->ring);
if (!sqe) {
return SDL_SetError("io_uring: submission queue is full");
}
retval = SDL_SetError("io_uring: submission queue is full");
} else {
if (task->flush) {
struct io_uring_sqe *flush_sqe = sqe;
sqe = liburing.io_uring_get_sqe(&queuedata->ring); // this will be our actual close task.
@@ -433,9 +439,9 @@ static bool liburing_asyncio_close(void *userdata, SDL_AsyncIOTask *task)
liburing.io_uring_prep_nop(flush_sqe); // we already have the first sqe, just make it a NOP.
liburing.io_uring_sqe_set_data(flush_sqe, NULL);
task->queue->iface.queue_task(task->queue->userdata, task);
SDL_UnlockMutex(queuedata->sqe_lock);
return SDL_SetError("io_uring: submission queue is full");
}
liburing.io_uring_prep_fsync(flush_sqe, fd, IORING_FSYNC_DATASYNC);
liburing.io_uring_sqe_set_data(flush_sqe, task);
liburing.io_uring_sqe_set_flags(flush_sqe, IOSQE_IO_HARDLINK); // must complete before next sqe starts, and next sqe should run even if this fails.
@@ -444,7 +450,8 @@ static bool liburing_asyncio_close(void *userdata, SDL_AsyncIOTask *task)
liburing.io_uring_prep_close(sqe, fd);
liburing.io_uring_sqe_set_data(sqe, task);
const bool retval = task->queue->iface.queue_task(task->queue->userdata, task);
retval = task->queue->iface.queue_task(task->queue->userdata, task);
}
SDL_UnlockMutex(queuedata->sqe_lock);
return retval;
}

File diff suppressed because it is too large Load Diff