| 1 | /* |
| 2 | Simple DirectMedia Layer |
| 3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
| 4 | |
| 5 | This software is provided 'as-is', without any express or implied |
| 6 | warranty. In no event will the authors be held liable for any damages |
| 7 | arising from the use of this software. |
| 8 | |
| 9 | Permission is granted to anyone to use this software for any purpose, |
| 10 | including commercial applications, and to alter it and redistribute it |
| 11 | freely, subject to the following restrictions: |
| 12 | |
| 13 | 1. The origin of this software must not be misrepresented; you must not |
| 14 | claim that you wrote the original software. If you use this software |
| 15 | in a product, an acknowledgment in the product documentation would be |
| 16 | appreciated but is not required. |
| 17 | 2. Altered source versions must be plainly marked as such, and must not be |
| 18 | misrepresented as being the original software. |
| 19 | 3. This notice may not be removed or altered from any source distribution. |
| 20 | */ |
| 21 | |
| 22 | /* WIKI CATEGORY: AsyncIO */ |
| 23 | |
| 24 | /** |
| 25 | * # CategoryAsyncIO |
| 26 | * |
| 27 | * SDL offers a way to perform I/O asynchronously. This allows an app to read |
| 28 | * or write files without waiting for data to actually transfer; the functions |
| 29 | * that request I/O never block while the request is fulfilled. |
| 30 | * |
| 31 | * Instead, the data moves in the background and the app can check for results |
| 32 | * at their leisure. |
| 33 | * |
| 34 | * This is more complicated than just reading and writing files in a |
| 35 | * synchronous way, but it can allow for more efficiency, and never having |
| 36 | * framerate drops as the hard drive catches up, etc. |
| 37 | * |
| 38 | * The general usage pattern for async I/O is: |
| 39 | * |
| 40 | * - Create one or more SDL_AsyncIOQueue objects. |
| 41 | * - Open files with SDL_AsyncIOFromFile. |
| 42 | * - Start I/O tasks to the files with SDL_ReadAsyncIO or SDL_WriteAsyncIO, |
| 43 | * putting those tasks into one of the queues. |
| 44 | * - Later on, use SDL_GetAsyncIOResult on a queue to see if any task is |
| 45 | * finished without blocking. Tasks might finish in any order with success |
| 46 | * or failure. |
| 47 | * - When all your tasks are done, close the file with SDL_CloseAsyncIO. This |
| 48 | * also generates a task, since it might flush data to disk! |
| 49 | * |
| 50 | * This all works, without blocking, in a single thread, but one can also wait |
| 51 | * on a queue in a background thread, sleeping until new results have arrived: |
| 52 | * |
| 53 | * - Call SDL_WaitAsyncIOResult from one or more threads to efficiently block |
| 54 | * until new tasks complete. |
| 55 | * - When shutting down, call SDL_SignalAsyncIOQueue to unblock any sleeping |
| 56 | * threads despite there being no new tasks completed. |
| 57 | * |
| 58 | * And, of course, to match the synchronous SDL_LoadFile, we offer |
| 59 | * SDL_LoadFileAsync as a convenience function. This will handle allocating a |
| 60 | * buffer, slurping in the file data, and null-terminating it; you still check |
| 61 | * for results later. |
| 62 | * |
| 63 | * Behind the scenes, SDL will use newer, efficient APIs on platforms that |
| 64 | * support them: Linux's io_uring and Windows 11's IoRing, for example. If |
| 65 | * those technologies aren't available, SDL will offload the work to a thread |
| 66 | * pool that will manage otherwise-synchronous loads without blocking the app. |
| 67 | * |
| 68 | * ## Best Practices |
| 69 | * |
| 70 | * Simple non-blocking I/O--for an app that just wants to pick up data |
| 71 | * whenever it's ready without losing framerate waiting on disks to spin--can |
| 72 | * use whatever pattern works well for the program. In this case, simply call |
| 73 | * SDL_ReadAsyncIO, or maybe SDL_LoadFileAsync, as needed. Once a frame, call |
| 74 | * SDL_GetAsyncIOResult to check for any completed tasks and deal with the |
| 75 | * data as it arrives. |
| 76 | * |
| 77 | * If two separate pieces of the same program need their own I/O, it is legal |
| 78 | * for each to create their own queue. This will prevent either piece from |
| 79 | * accidentally consuming the other's completed tasks. Each queue does require |
| 80 | * some amount of resources, but it is not an overwhelming cost. Do not make a |
| 81 | * queue for each task, however. It is better to put many tasks into a single |
| 82 | * queue. They will be reported in order of completion, not in the order they |
| 83 | * were submitted, so it doesn't generally matter what order tasks are |
| 84 | * started. |
| 85 | * |
| 86 | * One async I/O queue can be shared by multiple threads, or one thread can |
| 87 | * have more than one queue, but the most efficient way--if ruthless |
| 88 | * efficiency is the goal--is to have one queue per thread, with multiple |
| 89 | * threads working in parallel, and attempt to keep each queue loaded with |
| 90 | * tasks that are both started by and consumed by the same thread. On modern |
| 91 | * platforms that can use newer interfaces, this can keep data flowing as |
| 92 | * efficiently as possible all the way from storage hardware to the app, with |
| 93 | * no contention between threads for access to the same queue. |
| 94 | * |
| 95 | * Written data is not guaranteed to make it to physical media by the time a |
| 96 | * closing task is completed, unless SDL_CloseAsyncIO is called with its |
| 97 | * `flush` parameter set to true, which is to say that a successful result |
| 98 | * here can still result in lost data during an unfortunately-timed power |
| 99 | * outage if not flushed. However, flushing will take longer and may be |
| 100 | * unnecessary, depending on the app's needs. |
| 101 | */ |
| 102 | |
| 103 | #ifndef SDL_asyncio_h_ |
| 104 | #define SDL_asyncio_h_ |
| 105 | |
| 106 | #include <SDL3/SDL_stdinc.h> |
| 107 | |
| 108 | #include <SDL3/SDL_begin_code.h> |
| 109 | /* Set up for C function definitions, even when using C++ */ |
| 110 | #ifdef __cplusplus |
| 111 | extern "C" { |
| 112 | #endif |
| 113 | |
| 114 | /** |
| 115 | * The asynchronous I/O operation structure. |
| 116 | * |
| 117 | * This operates as an opaque handle. One can then request read or write |
| 118 | * operations on it. |
| 119 | * |
| 120 | * \since This struct is available since SDL 3.2.0. |
| 121 | * |
| 122 | * \sa SDL_AsyncIOFromFile |
| 123 | */ |
| 124 | typedef struct SDL_AsyncIO SDL_AsyncIO; |
| 125 | |
| 126 | /** |
| 127 | * Types of asynchronous I/O tasks. |
| 128 | * |
| 129 | * \since This enum is available since SDL 3.2.0. |
| 130 | */ |
| 131 | typedef enum SDL_AsyncIOTaskType |
| 132 | { |
| 133 | SDL_ASYNCIO_TASK_READ, /**< A read operation. */ |
| 134 | SDL_ASYNCIO_TASK_WRITE, /**< A write operation. */ |
| 135 | SDL_ASYNCIO_TASK_CLOSE /**< A close operation. */ |
| 136 | } SDL_AsyncIOTaskType; |
| 137 | |
| 138 | /** |
| 139 | * Possible outcomes of an asynchronous I/O task. |
| 140 | * |
| 141 | * \since This enum is available since SDL 3.2.0. |
| 142 | */ |
| 143 | typedef enum SDL_AsyncIOResult |
| 144 | { |
| 145 | SDL_ASYNCIO_COMPLETE, /**< request was completed without error */ |
| 146 | SDL_ASYNCIO_FAILURE, /**< request failed for some reason; check SDL_GetError()! */ |
| 147 | SDL_ASYNCIO_CANCELED /**< request was canceled before completing. */ |
| 148 | } SDL_AsyncIOResult; |
| 149 | |
| 150 | /** |
| 151 | * Information about a completed asynchronous I/O request. |
| 152 | * |
| 153 | * \since This struct is available since SDL 3.2.0. |
| 154 | */ |
| 155 | typedef struct SDL_AsyncIOOutcome |
| 156 | { |
| 157 | SDL_AsyncIO *asyncio; /**< what generated this task. This pointer will be invalid if it was closed! */ |
| 158 | SDL_AsyncIOTaskType type; /**< What sort of task was this? Read, write, etc? */ |
| 159 | SDL_AsyncIOResult result; /**< the result of the work (success, failure, cancellation). */ |
| 160 | void *buffer; /**< buffer where data was read/written. */ |
| 161 | Uint64 offset; /**< offset in the SDL_AsyncIO where data was read/written. */ |
| 162 | Uint64 bytes_requested; /**< number of bytes the task was to read/write. */ |
| 163 | Uint64 bytes_transferred; /**< actual number of bytes that were read/written. */ |
| 164 | void *userdata; /**< pointer provided by the app when starting the task */ |
| 165 | } SDL_AsyncIOOutcome; |
| 166 | |
| 167 | /** |
| 168 | * A queue of completed asynchronous I/O tasks. |
| 169 | * |
| 170 | * When starting an asynchronous operation, you specify a queue for the new |
| 171 | * task. A queue can be asked later if any tasks in it have completed, |
| 172 | * allowing an app to manage multiple pending tasks in one place, in whatever |
| 173 | * order they complete. |
| 174 | * |
| 175 | * \since This struct is available since SDL 3.2.0. |
| 176 | * |
| 177 | * \sa SDL_CreateAsyncIOQueue |
| 178 | * \sa SDL_ReadAsyncIO |
| 179 | * \sa SDL_WriteAsyncIO |
| 180 | * \sa SDL_GetAsyncIOResult |
| 181 | * \sa SDL_WaitAsyncIOResult |
| 182 | */ |
| 183 | typedef struct SDL_AsyncIOQueue SDL_AsyncIOQueue; |
| 184 | |
| 185 | /** |
| 186 | * Use this function to create a new SDL_AsyncIO object for reading from |
| 187 | * and/or writing to a named file. |
| 188 | * |
| 189 | * The `mode` string understands the following values: |
| 190 | * |
| 191 | * - "r": Open a file for reading only. It must exist. |
| 192 | * - "w": Open a file for writing only. It will create missing files or |
| 193 | * truncate existing ones. |
| 194 | * - "r+": Open a file for update both reading and writing. The file must |
| 195 | * exist. |
| 196 | * - "w+": Create an empty file for both reading and writing. If a file with |
| 197 | * the same name already exists its content is erased and the file is |
| 198 | * treated as a new empty file. |
| 199 | * |
| 200 | * There is no "b" mode, as there is only "binary" style I/O, and no "a" mode |
| 201 | * for appending, since you specify the position when starting a task. |
| 202 | * |
| 203 | * This function supports Unicode filenames, but they must be encoded in UTF-8 |
| 204 | * format, regardless of the underlying operating system. |
| 205 | * |
| 206 | * This call is _not_ asynchronous; it will open the file before returning, |
| 207 | * under the assumption that doing so is generally a fast operation. Future |
| 208 | * reads and writes to the opened file will be async, however. |
| 209 | * |
| 210 | * \param file a UTF-8 string representing the filename to open. |
| 211 | * \param mode an ASCII string representing the mode to be used for opening |
| 212 | * the file. |
| 213 | * \returns a pointer to the SDL_AsyncIO structure that is created or NULL on |
| 214 | * failure; call SDL_GetError() for more information. |
| 215 | * |
| 216 | * \since This function is available since SDL 3.2.0. |
| 217 | * |
| 218 | * \sa SDL_CloseAsyncIO |
| 219 | * \sa SDL_ReadAsyncIO |
| 220 | * \sa SDL_WriteAsyncIO |
| 221 | */ |
| 222 | extern SDL_DECLSPEC SDL_AsyncIO * SDLCALL SDL_AsyncIOFromFile(const char *file, const char *mode); |
| 223 | |
| 224 | /** |
| 225 | * Use this function to get the size of the data stream in an SDL_AsyncIO. |
| 226 | * |
| 227 | * This call is _not_ asynchronous; it assumes that obtaining this info is a |
| 228 | * non-blocking operation in most reasonable cases. |
| 229 | * |
| 230 | * \param asyncio the SDL_AsyncIO to get the size of the data stream from. |
| 231 | * \returns the size of the data stream in the SDL_IOStream on success or a |
| 232 | * negative error code on failure; call SDL_GetError() for more |
| 233 | * information. |
| 234 | * |
| 235 | * \threadsafety It is safe to call this function from any thread. |
| 236 | * |
| 237 | * \since This function is available since SDL 3.2.0. |
| 238 | */ |
| 239 | extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio); |
| 240 | |
| 241 | /** |
| 242 | * Start an async read. |
| 243 | * |
| 244 | * This function reads up to `size` bytes from `offset` position in the data |
| 245 | * source to the area pointed at by `ptr`. This function may read less bytes |
| 246 | * than requested. |
| 247 | * |
| 248 | * This function returns as quickly as possible; it does not wait for the read |
| 249 | * to complete. On a successful return, this work will continue in the |
| 250 | * background. If the work begins, even failure is asynchronous: a failing |
| 251 | * return value from this function only means the work couldn't start at all. |
| 252 | * |
| 253 | * `ptr` must remain available until the work is done, and may be accessed by |
| 254 | * the system at any time until then. Do not allocate it on the stack, as this |
| 255 | * might take longer than the life of the calling function to complete! |
| 256 | * |
| 257 | * An SDL_AsyncIOQueue must be specified. The newly-created task will be added |
| 258 | * to it when it completes its work. |
| 259 | * |
| 260 | * \param asyncio a pointer to an SDL_AsyncIO structure. |
| 261 | * \param ptr a pointer to a buffer to read data into. |
| 262 | * \param offset the position to start reading in the data source. |
| 263 | * \param size the number of bytes to read from the data source. |
| 264 | * \param queue a queue to add the new SDL_AsyncIO to. |
| 265 | * \param userdata an app-defined pointer that will be provided with the task |
| 266 | * results. |
| 267 | * \returns true on success or false on failure; call SDL_GetError() for more |
| 268 | * information. |
| 269 | * |
| 270 | * \threadsafety It is safe to call this function from any thread. |
| 271 | * |
| 272 | * \since This function is available since SDL 3.2.0. |
| 273 | * |
| 274 | * \sa SDL_WriteAsyncIO |
| 275 | * \sa SDL_CreateAsyncIOQueue |
| 276 | */ |
| 277 | extern SDL_DECLSPEC bool SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata); |
| 278 | |
| 279 | /** |
| 280 | * Start an async write. |
| 281 | * |
| 282 | * This function writes `size` bytes from `offset` position in the data source |
| 283 | * to the area pointed at by `ptr`. |
| 284 | * |
| 285 | * This function returns as quickly as possible; it does not wait for the |
| 286 | * write to complete. On a successful return, this work will continue in the |
| 287 | * background. If the work begins, even failure is asynchronous: a failing |
| 288 | * return value from this function only means the work couldn't start at all. |
| 289 | * |
| 290 | * `ptr` must remain available until the work is done, and may be accessed by |
| 291 | * the system at any time until then. Do not allocate it on the stack, as this |
| 292 | * might take longer than the life of the calling function to complete! |
| 293 | * |
| 294 | * An SDL_AsyncIOQueue must be specified. The newly-created task will be added |
| 295 | * to it when it completes its work. |
| 296 | * |
| 297 | * \param asyncio a pointer to an SDL_AsyncIO structure. |
| 298 | * \param ptr a pointer to a buffer to write data from. |
| 299 | * \param offset the position to start writing to the data source. |
| 300 | * \param size the number of bytes to write to the data source. |
| 301 | * \param queue a queue to add the new SDL_AsyncIO to. |
| 302 | * \param userdata an app-defined pointer that will be provided with the task |
| 303 | * results. |
| 304 | * \returns true on success or false on failure; call SDL_GetError() for more |
| 305 | * information. |
| 306 | * |
| 307 | * \threadsafety It is safe to call this function from any thread. |
| 308 | * |
| 309 | * \since This function is available since SDL 3.2.0. |
| 310 | * |
| 311 | * \sa SDL_ReadAsyncIO |
| 312 | * \sa SDL_CreateAsyncIOQueue |
| 313 | */ |
| 314 | extern SDL_DECLSPEC bool SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata); |
| 315 | |
| 316 | /** |
| 317 | * Close and free any allocated resources for an async I/O object. |
| 318 | * |
| 319 | * Closing a file is _also_ an asynchronous task! If a write failure were to |
| 320 | * happen during the closing process, for example, the task results will |
| 321 | * report it as usual. |
| 322 | * |
| 323 | * Closing a file that has been written to does not guarantee the data has |
| 324 | * made it to physical media; it may remain in the operating system's file |
| 325 | * cache, for later writing to disk. This means that a successfully-closed |
| 326 | * file can be lost if the system crashes or loses power in this small window. |
| 327 | * To prevent this, call this function with the `flush` parameter set to true. |
| 328 | * This will make the operation take longer, and perhaps increase system load |
| 329 | * in general, but a successful result guarantees that the data has made it to |
| 330 | * physical storage. Don't use this for temporary files, caches, and |
| 331 | * unimportant data, and definitely use it for crucial irreplaceable files, |
| 332 | * like game saves. |
| 333 | * |
| 334 | * This function guarantees that the close will happen after any other pending |
| 335 | * tasks to `asyncio`, so it's safe to open a file, start several operations, |
| 336 | * close the file immediately, then check for all results later. This function |
| 337 | * will not block until the tasks have completed. |
| 338 | * |
| 339 | * Once this function returns true, `asyncio` is no longer valid, regardless |
| 340 | * of any future outcomes. Any completed tasks might still contain this |
| 341 | * pointer in their SDL_AsyncIOOutcome data, in case the app was using this |
| 342 | * value to track information, but it should not be used again. |
| 343 | * |
| 344 | * If this function returns false, the close wasn't started at all, and it's |
| 345 | * safe to attempt to close again later. |
| 346 | * |
| 347 | * An SDL_AsyncIOQueue must be specified. The newly-created task will be added |
| 348 | * to it when it completes its work. |
| 349 | * |
| 350 | * \param asyncio a pointer to an SDL_AsyncIO structure to close. |
| 351 | * \param flush true if data should sync to disk before the task completes. |
| 352 | * \param queue a queue to add the new SDL_AsyncIO to. |
| 353 | * \param userdata an app-defined pointer that will be provided with the task |
| 354 | * results. |
| 355 | * \returns true on success or false on failure; call SDL_GetError() for more |
| 356 | * information. |
| 357 | * |
| 358 | * \threadsafety It is safe to call this function from any thread, but two |
| 359 | * threads should not attempt to close the same object. |
| 360 | * |
| 361 | * \since This function is available since SDL 3.2.0. |
| 362 | */ |
| 363 | extern SDL_DECLSPEC bool SDLCALL SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata); |
| 364 | |
| 365 | /** |
| 366 | * Create a task queue for tracking multiple I/O operations. |
| 367 | * |
| 368 | * Async I/O operations are assigned to a queue when started. The queue can be |
| 369 | * checked for completed tasks thereafter. |
| 370 | * |
| 371 | * \returns a new task queue object or NULL if there was an error; call |
| 372 | * SDL_GetError() for more information. |
| 373 | * |
| 374 | * \threadsafety It is safe to call this function from any thread. |
| 375 | * |
| 376 | * \since This function is available since SDL 3.2.0. |
| 377 | * |
| 378 | * \sa SDL_DestroyAsyncIOQueue |
| 379 | * \sa SDL_GetAsyncIOResult |
| 380 | * \sa SDL_WaitAsyncIOResult |
| 381 | */ |
| 382 | extern SDL_DECLSPEC SDL_AsyncIOQueue * SDLCALL SDL_CreateAsyncIOQueue(void); |
| 383 | |
| 384 | /** |
| 385 | * Destroy a previously-created async I/O task queue. |
| 386 | * |
| 387 | * If there are still tasks pending for this queue, this call will block until |
| 388 | * those tasks are finished. All those tasks will be deallocated. Their |
| 389 | * results will be lost to the app. |
| 390 | * |
| 391 | * Any pending reads from SDL_LoadFileAsync() that are still in this queue |
| 392 | * will have their buffers deallocated by this function, to prevent a memory |
| 393 | * leak. |
| 394 | * |
| 395 | * Once this function is called, the queue is no longer valid and should not |
| 396 | * be used, including by other threads that might access it while destruction |
| 397 | * is blocking on pending tasks. |
| 398 | * |
| 399 | * Do not destroy a queue that still has threads waiting on it through |
| 400 | * SDL_WaitAsyncIOResult(). You can call SDL_SignalAsyncIOQueue() first to |
| 401 | * unblock those threads, and take measures (such as SDL_WaitThread()) to make |
| 402 | * sure they have finished their wait and won't wait on the queue again. |
| 403 | * |
| 404 | * \param queue the task queue to destroy. |
| 405 | * |
| 406 | * \threadsafety It is safe to call this function from any thread, so long as |
| 407 | * no other thread is waiting on the queue with |
| 408 | * SDL_WaitAsyncIOResult. |
| 409 | * |
| 410 | * \since This function is available since SDL 3.2.0. |
| 411 | */ |
| 412 | extern SDL_DECLSPEC void SDLCALL SDL_DestroyAsyncIOQueue(SDL_AsyncIOQueue *queue); |
| 413 | |
| 414 | /** |
| 415 | * Query an async I/O task queue for completed tasks. |
| 416 | * |
| 417 | * If a task assigned to this queue has finished, this will return true and |
| 418 | * fill in `outcome` with the details of the task. If no task in the queue has |
| 419 | * finished, this function will return false. This function does not block. |
| 420 | * |
| 421 | * If a task has completed, this function will free its resources and the task |
| 422 | * pointer will no longer be valid. The task will be removed from the queue. |
| 423 | * |
| 424 | * It is safe for multiple threads to call this function on the same queue at |
| 425 | * once; a completed task will only go to one of the threads. |
| 426 | * |
| 427 | * \param queue the async I/O task queue to query. |
| 428 | * \param outcome details of a finished task will be written here. May not be |
| 429 | * NULL. |
| 430 | * \returns true if a task has completed, false otherwise. |
| 431 | * |
| 432 | * \threadsafety It is safe to call this function from any thread. |
| 433 | * |
| 434 | * \since This function is available since SDL 3.2.0. |
| 435 | * |
| 436 | * \sa SDL_WaitAsyncIOResult |
| 437 | */ |
| 438 | extern SDL_DECLSPEC bool SDLCALL SDL_GetAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome); |
| 439 | |
| 440 | /** |
| 441 | * Block until an async I/O task queue has a completed task. |
| 442 | * |
| 443 | * This function puts the calling thread to sleep until there a task assigned |
| 444 | * to the queue that has finished. |
| 445 | * |
| 446 | * If a task assigned to the queue has finished, this will return true and |
| 447 | * fill in `outcome` with the details of the task. If no task in the queue has |
| 448 | * finished, this function will return false. |
| 449 | * |
| 450 | * If a task has completed, this function will free its resources and the task |
| 451 | * pointer will no longer be valid. The task will be removed from the queue. |
| 452 | * |
| 453 | * It is safe for multiple threads to call this function on the same queue at |
| 454 | * once; a completed task will only go to one of the threads. |
| 455 | * |
| 456 | * Note that by the nature of various platforms, more than one waiting thread |
| 457 | * may wake to handle a single task, but only one will obtain it, so |
| 458 | * `timeoutMS` is a _maximum_ wait time, and this function may return false |
| 459 | * sooner. |
| 460 | * |
| 461 | * This function may return false if there was a system error, the OS |
| 462 | * inadvertently awoke multiple threads, or if SDL_SignalAsyncIOQueue() was |
| 463 | * called to wake up all waiting threads without a finished task. |
| 464 | * |
| 465 | * A timeout can be used to specify a maximum wait time, but rather than |
| 466 | * polling, it is possible to have a timeout of -1 to wait forever, and use |
| 467 | * SDL_SignalAsyncIOQueue() to wake up the waiting threads later. |
| 468 | * |
| 469 | * \param queue the async I/O task queue to wait on. |
| 470 | * \param outcome details of a finished task will be written here. May not be |
| 471 | * NULL. |
| 472 | * \param timeoutMS the maximum time to wait, in milliseconds, or -1 to wait |
| 473 | * indefinitely. |
| 474 | * \returns true if task has completed, false otherwise. |
| 475 | * |
| 476 | * \threadsafety It is safe to call this function from any thread. |
| 477 | * |
| 478 | * \since This function is available since SDL 3.2.0. |
| 479 | * |
| 480 | * \sa SDL_SignalAsyncIOQueue |
| 481 | */ |
| 482 | extern SDL_DECLSPEC bool SDLCALL SDL_WaitAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome, Sint32 timeoutMS); |
| 483 | |
| 484 | /** |
| 485 | * Wake up any threads that are blocking in SDL_WaitAsyncIOResult(). |
| 486 | * |
| 487 | * This will unblock any threads that are sleeping in a call to |
| 488 | * SDL_WaitAsyncIOResult for the specified queue, and cause them to return |
| 489 | * from that function. |
| 490 | * |
| 491 | * This can be useful when destroying a queue to make sure nothing is touching |
| 492 | * it indefinitely. In this case, once this call completes, the caller should |
| 493 | * take measures to make sure any previously-blocked threads have returned |
| 494 | * from their wait and will not touch the queue again (perhaps by setting a |
| 495 | * flag to tell the threads to terminate and then using SDL_WaitThread() to |
| 496 | * make sure they've done so). |
| 497 | * |
| 498 | * \param queue the async I/O task queue to signal. |
| 499 | * |
| 500 | * \threadsafety It is safe to call this function from any thread. |
| 501 | * |
| 502 | * \since This function is available since SDL 3.2.0. |
| 503 | * |
| 504 | * \sa SDL_WaitAsyncIOResult |
| 505 | */ |
| 506 | extern SDL_DECLSPEC void SDLCALL SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue *queue); |
| 507 | |
| 508 | /** |
| 509 | * Load all the data from a file path, asynchronously. |
| 510 | * |
| 511 | * This function returns as quickly as possible; it does not wait for the read |
| 512 | * to complete. On a successful return, this work will continue in the |
| 513 | * background. If the work begins, even failure is asynchronous: a failing |
| 514 | * return value from this function only means the work couldn't start at all. |
| 515 | * |
| 516 | * The data is allocated with a zero byte at the end (null terminated) for |
| 517 | * convenience. This extra byte is not included in SDL_AsyncIOOutcome's |
| 518 | * bytes_transferred value. |
| 519 | * |
| 520 | * This function will allocate the buffer to contain the file. It must be |
| 521 | * deallocated by calling SDL_free() on SDL_AsyncIOOutcome's buffer field |
| 522 | * after completion. |
| 523 | * |
| 524 | * An SDL_AsyncIOQueue must be specified. The newly-created task will be added |
| 525 | * to it when it completes its work. |
| 526 | * |
| 527 | * \param file the path to read all available data from. |
| 528 | * \param queue a queue to add the new SDL_AsyncIO to. |
| 529 | * \param userdata an app-defined pointer that will be provided with the task |
| 530 | * results. |
| 531 | * \returns true on success or false on failure; call SDL_GetError() for more |
| 532 | * information. |
| 533 | * |
| 534 | * \since This function is available since SDL 3.2.0. |
| 535 | * |
| 536 | * \sa SDL_LoadFile_IO |
| 537 | */ |
| 538 | extern SDL_DECLSPEC bool SDLCALL SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata); |
| 539 | |
| 540 | /* Ends C function definitions when using C++ */ |
| 541 | #ifdef __cplusplus |
| 542 | } |
| 543 | #endif |
| 544 | #include <SDL3/SDL_close_code.h> |
| 545 | |
| 546 | #endif /* SDL_asyncio_h_ */ |
| 547 | |