diff --git a/include/SDL3/SDL_asyncio.h b/include/SDL3/SDL_asyncio.h index 4d90ddaa1b..77f7c242d2 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 ebf559f445..df1542ce2b 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 f25ffa8327..a18f7b95eb 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; } +