From 46f43c2e6e677a36c7b8955c116075492b1eda46 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 8 Oct 2024 14:50:05 -0400
Subject: [PATCH] asyncio: Remove `SDL_AsyncIOTask` from the public API.
---
include/SDL3/SDL_asyncio.h | 66 ++++++++++++++---------------------
src/dynapi/SDL_dynapi_procs.h | 8 ++---
src/file/SDL_asyncio.c | 57 +++++++++++++-----------------
3 files changed, 55 insertions(+), 76 deletions(-)
diff --git a/include/SDL3/SDL_asyncio.h b/include/SDL3/SDL_asyncio.h
index 4d90ddaa1b6e7..77f7c242d2d40 100644
--- a/include/SDL3/SDL_asyncio.h
+++ b/include/SDL3/SDL_asyncio.h
@@ -126,23 +126,6 @@ typedef struct SDL_AsyncIOOutcome
void *userdata; /**< pointer provided by the app when starting the task */
} SDL_AsyncIOOutcome;
-/**
- * An opaque handle for asynchronous I/O tasks.
- *
- * Each asynchronous read or write operation generates a task, which will
- * complete at some time in the future. This handle is used to track the
- * progress of that task.
- *
- * Tasks are added to an SDL_AsyncIOQueue, where they can be queried for
- * completion later.
- *
- * \since This struct is available since SDL 3.0.0.
- *
- * \sa SDL_ReadAsyncIO
- * \sa SDL_WriteAsyncIO
- */
-typedef struct SDL_AsyncIOTask SDL_AsyncIOTask;
-
/**
* A queue of completed asynchronous I/O tasks.
*
@@ -232,8 +215,8 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio);
* the system at any time until then. Do not allocate it on the stack, as this
* might take longer than the life of the calling function to complete!
*
- * An SDL_AsyncIOQueue must be specified. The newly-created SDL_AsyncIOTask
- * will be added to it when it completes its work.
+ * An SDL_AsyncIOQueue must be specified. The newly-created task will be added
+ * to it when it completes its work.
*
* \param asyncio a pointer to an SDL_AsyncIO structure.
* \param ptr a pointer to a buffer to read data into.
@@ -241,8 +224,8 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio);
* \param size the number of bytes to read from the data source.
* \param queue a queue to add the new SDL_AsyncIO to.
* \param userdata an app-defined pointer that will be provided with the task results.
- * \returns A new task handle if a task was started, NULL on complete failure;
- * call SDL_GetError() for more information.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ * information.
*
* \threadsafety It is safe to call this function from any thread.
*
@@ -252,7 +235,7 @@ extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio);
* \sa SDL_CreateAsyncIOQueue
* \sa SDL_GetAsyncIOTaskResult
*/
-extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
+extern SDL_DECLSPEC bool SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
/**
* Start an async write.
@@ -269,8 +252,8 @@ extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *async
* the system at any time until then. Do not allocate it on the stack, as this
* might take longer than the life of the calling function to complete!
*
- * An SDL_AsyncIOQueue must be specified. The newly-created SDL_AsyncIOTask
- * will be added to it when it completes its work.
+ * An SDL_AsyncIOQueue must be specified. The newly-created task will be added
+ * to it when it completes its work.
*
* \param asyncio a pointer to an SDL_AsyncIO structure.
* \param ptr a pointer to a buffer to write data from.
@@ -278,8 +261,8 @@ extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *async
* \param size the number of bytes to write to the data source.
* \param queue a queue to add the new SDL_AsyncIO to.
* \param userdata an app-defined pointer that will be provided with the task results.
- * \returns A new task handle if a task was started, NULL on complete failure;
- * call SDL_GetError() for more information.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ * information.
*
* \threadsafety It is safe to call this function from any thread.
*
@@ -290,7 +273,7 @@ extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *async
* \sa SDL_GetAsyncIOTaskResult
*/
-extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
+extern SDL_DECLSPEC bool SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
/**
* Close and free any allocated resources for an async I/O object.
@@ -305,10 +288,11 @@ extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyn
* a successfully-closed file can be lost if the system crashes or
* loses power in this small window. To prevent this, call this
* function with the `flush` parameter set to true. This will make
- * the operation take longer, but a successful result guarantees that
- * the data has made it to physical storage. Don't use this for
- * temporary files, caches, and unimportant data, and definitely use
- * it for crucial irreplaceable files, like game saves.
+ * the operation take longer, and perhaps increase system load in
+ * general, but a successful result guarantees that the data has made
+ * it to physical storage. Don't use this for temporary files, caches,
+ * and unimportant data, and definitely use it for crucial irreplaceable
+ * files, like game saves.
*
* This function guarantees that the close will happen after any other
* pending tasks to `asyncio`, so it's safe to open a file, start
@@ -322,22 +306,25 @@ extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyn
* app was using this value to track information, but it should not
* be used again.
*
- * If this function returns NULL, the close wasn't started at all, and
+ * If this function returns false, the close wasn't started at all, and
* it's safe to attempt to close again later.
*
+ * An SDL_AsyncIOQueue must be specified. The newly-created task will be added
+ * to it when it completes its work.
+ *
* \param asyncio a pointer to an SDL_AsyncIO structure to close.
* \param flush true if data should sync to disk before the task completes.
* \param queue a queue to add the new SDL_AsyncIO to.
* \param userdata an app-defined pointer that will be provided with the task results.
- * \returns A new task handle if a task was started, NULL on complete failure;
- * call SDL_GetError() for more information.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ * information.
*
* \threadsafety It is safe to call this function from any thread, but
* two threads should not attempt to close the same object.
*
* \since This function is available since SDL 3.0.0.
*/
-extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata);
+extern SDL_DECLSPEC bool SDLCALL SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata);
/**
* Create a task queue for tracking multiple I/O operations.
@@ -495,19 +482,20 @@ extern SDL_DECLSPEC void SDLCALL SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue *queue)
* deallocated by calling SDL_free() on SDL_AsyncIOOutcome's buffer field
* after completion.
*
- * An SDL_AsyncIOQueue must be specified. The newly-created SDL_AsyncIOTask
- * will be added to it when it completes its work.
+ * An SDL_AsyncIOQueue must be specified. The newly-created task will be added
+ * to it when it completes its work.
*
* \param file the path to read all available data from.
* \param queue a queue to add the new SDL_AsyncIO to.
* \param userdata an app-defined pointer that will be provided with the task results.
- * \returns an async task, to be queried for results later.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ * information.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_LoadFile_IO
*/
-extern SDL_DECLSPEC SDL_AsyncIOTask * SDLCALL SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata);
+extern SDL_DECLSPEC bool SDLCALL SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index ebf559f445f0f..df1542ce2b2b8 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1222,12 +1222,12 @@ SDL_DYNAPI_PROC(bool,SDL_IsAudioDevicePhysical,(SDL_AudioDeviceID a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_IsAudioDevicePlayback,(SDL_AudioDeviceID a),(a),return)
SDL_DYNAPI_PROC(SDL_AsyncIO*,SDL_AsyncIOFromFile,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(Sint64,SDL_GetAsyncIOSize,(SDL_AsyncIO *a),(a),return)
-SDL_DYNAPI_PROC(SDL_AsyncIOTask*,SDL_ReadAsyncIO,(SDL_AsyncIO *a, void *b, Uint64 c, Uint64 d, SDL_AsyncIOQueue *e, void *f),(a,b,c,d,e,f),return)
-SDL_DYNAPI_PROC(SDL_AsyncIOTask*,SDL_WriteAsyncIO,(SDL_AsyncIO *a, void *b, Uint64 c, Uint64 d, SDL_AsyncIOQueue *e, void *f),(a,b,c,d,e,f),return)
-SDL_DYNAPI_PROC(SDL_AsyncIOTask*,SDL_CloseAsyncIO,(SDL_AsyncIO *a, bool b, SDL_AsyncIOQueue *c, void *d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(bool,SDL_ReadAsyncIO,(SDL_AsyncIO *a, void *b, Uint64 c, Uint64 d, SDL_AsyncIOQueue *e, void *f),(a,b,c,d,e,f),return)
+SDL_DYNAPI_PROC(bool,SDL_WriteAsyncIO,(SDL_AsyncIO *a, void *b, Uint64 c, Uint64 d, SDL_AsyncIOQueue *e, void *f),(a,b,c,d,e,f),return)
+SDL_DYNAPI_PROC(bool,SDL_CloseAsyncIO,(SDL_AsyncIO *a, bool b, SDL_AsyncIOQueue *c, void *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_AsyncIOQueue*,SDL_CreateAsyncIOQueue,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_DestroyAsyncIOQueue,(SDL_AsyncIOQueue *a),(a),)
SDL_DYNAPI_PROC(bool,SDL_GetAsyncIOResult,(SDL_AsyncIOQueue *a, SDL_AsyncIOOutcome *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_WaitAsyncIOResult,(SDL_AsyncIOQueue *a, SDL_AsyncIOOutcome *b, Sint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_SignalAsyncIOQueue,(SDL_AsyncIOQueue *a),(a),)
-SDL_DYNAPI_PROC(SDL_AsyncIOTask*,SDL_LoadFileAsync,(const char *a, SDL_AsyncIOQueue *b, void *c),(a,b,c),return)
+SDL_DYNAPI_PROC(bool,SDL_LoadFileAsync,(const char *a, SDL_AsyncIOQueue *b, void *c),(a,b,c),return)
diff --git a/src/file/SDL_asyncio.c b/src/file/SDL_asyncio.c
index f25ffa8327467..a18f7b95eb0f9 100644
--- a/src/file/SDL_asyncio.c
+++ b/src/file/SDL_asyncio.c
@@ -83,22 +83,19 @@ Sint64 SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio)
return asyncio->iface.size(asyncio->userdata);
}
-static SDL_AsyncIOTask *RequestAsyncIO(bool reading, SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
+static bool RequestAsyncIO(bool reading, SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
{
if (!asyncio) {
- SDL_InvalidParamError("asyncio");
- return NULL;
+ return SDL_InvalidParamError("asyncio");
} else if (!ptr) {
- SDL_InvalidParamError("ptr");
- return NULL;
+ return SDL_InvalidParamError("ptr");
} else if (!queue) {
- SDL_InvalidParamError("queue");
- return NULL;
+ return SDL_InvalidParamError("queue");
}
SDL_AsyncIOTask *task = (SDL_AsyncIOTask *) SDL_calloc(1, sizeof (*task));
if (!task) {
- return NULL;
+ return false;
}
task->asyncio = asyncio;
@@ -113,8 +110,7 @@ static SDL_AsyncIOTask *RequestAsyncIO(bool reading, SDL_AsyncIO *asyncio, void
if (asyncio->closing) {
SDL_free(task);
SDL_UnlockMutex(asyncio->lock);
- SDL_SetError("SDL_AsyncIO is closing, can't start new tasks");
- return NULL;
+ return SDL_SetError("SDL_AsyncIO is closing, can't start new tasks");
}
LINKED_LIST_PREPEND(task, asyncio->tasks, asyncio);
SDL_AddAtomicInt(&queue->tasks_inflight, 1);
@@ -130,34 +126,31 @@ static SDL_AsyncIOTask *RequestAsyncIO(bool reading, SDL_AsyncIO *asyncio, void
task = NULL;
}
- return task;
+ return (task != NULL);
}
-SDL_AsyncIOTask *SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
+bool SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
{
return RequestAsyncIO(true, asyncio, ptr, offset, size, queue, userdata);
}
-SDL_AsyncIOTask *SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
+bool SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata)
{
return RequestAsyncIO(false, asyncio, ptr, offset, size, queue, userdata);
}
-SDL_AsyncIOTask *SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata)
+bool SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata)
{
if (!asyncio) {
- SDL_InvalidParamError("asyncio");
- return NULL;
+ return SDL_InvalidParamError("asyncio");
} else if (!queue) {
- SDL_InvalidParamError("queue");
- return NULL;
+ return SDL_InvalidParamError("queue");
}
SDL_LockMutex(asyncio->lock);
if (asyncio->closing) {
SDL_UnlockMutex(asyncio->lock);
- SDL_SetError("Already closing");
- return NULL;
+ return SDL_SetError("Already closing");
}
SDL_AsyncIOTask *task = (SDL_AsyncIOTask *) SDL_calloc(1, sizeof (*task));
@@ -185,7 +178,7 @@ SDL_AsyncIOTask *SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQ
SDL_UnlockMutex(asyncio->lock);
- return task;
+ return (task != NULL);
}
SDL_AsyncIOQueue *SDL_CreateAsyncIOQueue(void)
@@ -300,17 +293,15 @@ void SDL_QuitAsyncIO(void)
SDL_SYS_QuitAsyncIO();
}
-SDL_AsyncIOTask *SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata)
+bool SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata)
{
if (!file) {
- SDL_InvalidParamError("file");
- return NULL;
+ return SDL_InvalidParamError("file");
} else if (!queue) {
- SDL_InvalidParamError("queue");
- return NULL;
+ return SDL_InvalidParamError("queue");
}
- SDL_AsyncIOTask *task = NULL;
+ bool retval = false;
SDL_AsyncIO *asyncio = SDL_AsyncIOFromFile(file, "r");
if (asyncio) {
asyncio->oneshot = true;
@@ -321,16 +312,16 @@ SDL_AsyncIOTask *SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, vo
// !!! FIXME: check if flen > address space, since it'll truncate and we'll just end up with an incomplete buffer or a crash.
ptr = SDL_malloc((size_t) (flen + 1)); // over-allocate by one so we can add a null-terminator.
if (ptr) {
- task = SDL_ReadAsyncIO(asyncio, ptr, 0, (Uint64) flen, queue, userdata);
+ retval = SDL_ReadAsyncIO(asyncio, ptr, 0, (Uint64) flen, queue, userdata);
+ if (!retval) {
+ SDL_free(ptr);
+ }
}
}
- if (!task) {
- SDL_free(ptr);
- }
-
SDL_CloseAsyncIO(asyncio, false, queue, userdata); // if this fails, we'll have a resource leak, but this would already be a dramatic system failure.
}
- return task;
+ return retval;
}
+