1 /* 2 DSDL 3 Copyright (C) 2025 Inochi2D Project <luna@foxgirls.gay> 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 23 Simple DirectMedia Layer 24 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> 25 26 This software is provided 'as-is', without any express or implied 27 warranty. In no event will the authors be held liable for any damages 28 arising from the use of this software. 29 30 Permission is granted to anyone to use this software for any purpose, 31 including commercial applications, and to alter it and redistribute it 32 freely, subject to the following restrictions: 33 34 1. The origin of this software must not be misrepresented; you must not 35 claim that you wrote the original software. If you use this software 36 in a product, an acknowledgment in the product documentation would be 37 appreciated but is not required. 38 2. Altered source versions must be plainly marked as such, and must not be 39 misrepresented as being the original software. 40 3. This notice may not be removed or altered from any source distribution. 41 */ 42 43 /** 44 SDL3 Asynchronous I/O 45 46 See_Also: 47 $(LINK2 https://wiki.libsdl.org/SDL3/CategoryAsyncIO, SDL3 AsyncIO Documentation) 48 49 Copyright: © 2025 Inochi2D Project, © 1997-2025 Sam Lantinga 50 License: Subject to the terms of the Zlib License, as written in the LICENSE file. 51 Authors: 52 Luna Nielsen 53 */ 54 module sdl.asyncio; 55 import sdl.stdc; 56 57 extern(C) nothrow @nogc: 58 59 /** 60 The asynchronous I/O operation structure. 61 62 This operates as an opaque handle. One can then request read or write 63 operations on it. 64 65 See_Also: 66 $(D SDL_AsyncIOFromFile) 67 68 History: 69 Available since SDL 3.2.0. 70 */ 71 struct SDL_AsyncIO; 72 73 /** 74 Types of asynchronous I/O tasks. 75 76 History: 77 Available since SDL 3.2.0. 78 */ 79 enum SDL_AsyncIOTaskType { 80 81 /** 82 A read operation. 83 */ 84 READ, 85 86 /** 87 A write operation. 88 */ 89 WRITE, 90 91 /** 92 A close operation. 93 */ 94 CLOSE 95 } 96 97 /** 98 Possible outcomes of an asynchronous I/O task. 99 100 History: 101 Available since SDL 3.2.0. 102 */ 103 enum SDL_AsyncIOResult { 104 105 /** 106 Request was completed without error. 107 */ 108 COMPLETE, 109 110 /** 111 Request failed for some reason; check SDL_GetError()! 112 */ 113 FAILURE, 114 115 /** 116 Request was canceled before completing. 117 */ 118 CANCELED 119 } 120 121 /** 122 Information about a completed asynchronous I/O request. 123 124 History: 125 Available since SDL 3.2.0. 126 */ 127 struct SDL_AsyncIOOutcome { 128 129 /** 130 What generated this task. 131 132 This pointer will be invalid if it was closed! 133 */ 134 SDL_AsyncIO* asyncio; 135 136 /** 137 What sort of task was this? Read, write, etc? 138 */ 139 SDL_AsyncIOTaskType type; 140 141 /** 142 The result of the work (success, failure, cancellation). 143 */ 144 SDL_AsyncIOResult result; 145 146 /** 147 Buffer where data was read/written. 148 */ 149 void* buffer; 150 151 /** 152 Offset in the SDL_AsyncIO where data was read/written. 153 */ 154 Uint64 offset; 155 156 /** 157 Number of bytes the task was to read/write. 158 */ 159 Uint64 bytes_requested; 160 161 /** 162 Actual number of bytes that were read/written. 163 */ 164 Uint64 bytes_transferred; 165 166 /** 167 Pointer provided by the app when starting the task 168 */ 169 void* userdata; 170 } 171 172 /** 173 A queue of completed asynchronous I/O tasks. 174 175 When starting an asynchronous operation, you specify a queue for the new 176 task. A queue can be asked later if any tasks in it have completed, 177 allowing an app to manage multiple pending tasks in one place, in whatever 178 order they complete. 179 180 History: 181 Available since SDL 3.2.0. 182 183 See_Also: 184 $(D SDL_CreateAsyncIOQueue) 185 $(D SDL_ReadAsyncIO) 186 $(D SDL_WriteAsyncIO) 187 $(D SDL_GetAsyncIOResult) 188 $(D SDL_WaitAsyncIOResult) 189 */ 190 struct SDL_AsyncIOQueue; 191 192 193 /** 194 Use this function to create a new SDL_AsyncIO object for reading from and/or writing to a named file. 195 196 The `mode` string understands the following values: 197 - `"r"`: Open a file for reading only. It must exist. 198 - `"w"`: Open a file for writing only. It will create missing files or 199 truncate existing ones. 200 - `"r+"`: Open a file for update both reading and writing. The file must 201 exist. 202 - `"w+"`: Create an empty file for both reading and writing. If a file with 203 the same name already exists its content is erased and the file is 204 treated as a new empty file. 205 206 There is no "b" mode, as there is only "binary" style I/O, and no "a" mode 207 for appending, since you specify the position when starting a task. 208 This function supports Unicode filenames, but they must be encoded in UTF-8 209 format, regardless of the underlying operating system. 210 211 This call is _not_ asynchronous; it will open the file before returning, 212 under the assumption that doing so is generally a fast operation. Future 213 reads and writes to the opened file will be async, however. 214 215 Params: 216 file = a UTF-8 string representing the filename to open. 217 mode = an ASCII string representing the mode to be used for opening 218 the file. 219 220 Returns: 221 a pointer to the SDL_AsyncIO structure that is created or NULL on failure; 222 call $(D SDL_GetError) for more information. 223 224 History: 225 Available since SDL 3.2.0. 226 227 See_Also: 228 $(D SDL_CloseAsyncIO) 229 $(D SDL_ReadAsyncIO) 230 $(D SDL_WriteAsyncIO) 231 */ 232 extern SDL_AsyncIO* SDL_AsyncIOFromFile(const(char)* file, const(char)* mode); 233 234 235 /** 236 Use this function to get the size of the data stream in an $(D SDL_AsyncIO). 237 238 This call is *not* asynchronous; it assumes that obtaining this info is a 239 non-blocking operation in most reasonable cases. 240 241 Params: 242 asyncio = The SDL_AsyncIO to get the size of the data stream from. 243 244 Returns: 245 the size of the data stream in the $(D SDL_IOStream) on success or a 246 negative error code on failure; call $(D SDL_GetError) for more 247 information. 248 249 Threadsafety: 250 It is safe to call this function from any thread. 251 252 History: 253 Available since SDL 3.2.0. 254 */ 255 extern Sint64 SDL_GetAsyncIOSize(SDL_AsyncIO* asyncio); 256 257 /** 258 Start an async read. 259 260 This function reads up to `size` bytes from `offset` position in the data 261 source to the area pointed at by `ptr`. This function may read less bytes 262 than requested. 263 264 This function returns as quickly as possible; it does not wait for the read 265 to complete. On a successful return, this work will continue in the 266 background. If the work begins, even failure is asynchronous: a failing 267 return value from this function only means the work couldn't start at all. 268 269 `ptr` must remain available until the work is done, and may be accessed by 270 the system at any time until then. Do not allocate it on the stack, as this 271 might take longer than the life of the calling function to complete! 272 273 An SDL_AsyncIOQueue must be specified. The newly-created task will be added 274 to it when it completes its work. 275 276 Param: 277 asyncio = a pointer to an SDL_AsyncIO structure. 278 ptr = a pointer to a buffer to read data into. 279 offset = the position to start reading in the data source. 280 size = the number of bytes to read from the data source. 281 queue = a queue to add the new SDL_AsyncIO to. 282 userdata = an app-defined pointer that will be provided with the task 283 results. 284 285 Returns: 286 $(D true) on success or $(D false) on failure; call $(D SDL_GetError) for more 287 information. 288 289 See_Also: 290 $(D SDL_WriteAsyncIO) 291 $(D SDL_CreateAsyncIOQueue) 292 293 Threadsafety: 294 It is safe to call this function from any thread. 295 296 History: 297 Available since SDL 3.2.0. 298 */ 299 extern bool SDL_ReadAsyncIO(SDL_AsyncIO* asyncio, void* ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue* queue, void* userdata); 300 301 /** 302 Start an async write. 303 304 This function writes `size` bytes from `offset` position in the data source 305 to the area pointed at by `ptr`. 306 307 This function returns as quickly as possible; it does not wait for the 308 write to complete. On a successful return, this work will continue in the 309 background. If the work begins, even failure is asynchronous: a failing 310 return value from this function only means the work couldn't start at all. 311 312 `ptr` must remain available until the work is done, and may be accessed by 313 the system at any time until then. Do not allocate it on the stack, as this 314 might take longer than the life of the calling function to complete! 315 316 An $(D SDL_AsyncIOQueue) must be specified. The newly-created task will be 317 added to it when it completes its work. 318 319 Params: 320 asyncio = a pointer to an SDL_AsyncIO structure. 321 ptr = a pointer to a buffer to write data from. 322 offset = the position to start writing to the data source. 323 size = the number of bytes to write to the data source. 324 queue = a queue to add the new SDL_AsyncIO to. 325 userdata = an app-defined pointer that will be provided with the task 326 results. 327 328 Returns: 329 $(D true) on success or $(D false) on failure; call $(D SDL_GetError) for more 330 information. 331 332 See_Also: 333 $(D SDL_ReadAsyncIO) 334 $(D SDL_CreateAsyncIOQueue) 335 336 Threadsafety: 337 It is safe to call this function from any thread. 338 339 History: 340 Available since SDL 3.2.0. 341 */ 342 extern bool SDL_WriteAsyncIO(SDL_AsyncIO* asyncio, void* ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue* queue, void* userdata); 343 344 /** 345 Close and free any allocated resources for an async I/O object. 346 347 Closing a file is *also* an asynchronous task! If a write failure were to 348 happen during the closing process, for example, the task results will 349 report it as usual. 350 351 Closing a file that has been written to does not guarantee the data has 352 made it to physical media; it may remain in the operating system's file 353 cache, for later writing to disk. This means that a successfully-closed 354 file can be lost if the system crashes or loses power in this small window. 355 To prevent this, call this function with the `flush` parameter set to true. 356 This will make the operation take longer, and perhaps increase system load 357 in general, but a successful result guarantees that the data has made it to 358 physical storage. Don't use this for temporary files, caches, and 359 unimportant data, and definitely use it for crucial irreplaceable files, 360 like game saves. 361 362 This function guarantees that the close will happen after any other pending 363 tasks to `asyncio`, so it's safe to open a file, start several operations, 364 close the file immediately, then check for all results later. This function 365 will not block until the tasks have completed. 366 367 Once this function returns true, `asyncio` is no longer valid, regardless 368 of any future outcomes. Any completed tasks might still contain this 369 pointer in their SDL_AsyncIOOutcome data, in case the app was using this 370 value to track information, but it should not be used again. 371 372 If this function returns false, the close wasn't started at all, and it's 373 safe to attempt to close again later. 374 375 An $(D SDL_AsyncIOQueue) must be specified. The newly-created task will be 376 added to it when it completes its work. 377 378 Params: 379 asyncio = a pointer to an SDL_AsyncIO structure to close. 380 flush = true if data should sync to disk before the task completes. 381 queue = a queue to add the new SDL_AsyncIO to. 382 userdata = an app-defined pointer that will be provided with the task 383 results. 384 385 Returns: 386 $(D true) on success or $(D false) on failure; call $(D SDL_GetError) 387 for more information. 388 389 Threadsafety: 390 It is safe to call this function from any thread. 391 392 History: 393 Available since SDL 3.2.0. 394 */ 395 extern bool SDL_CloseAsyncIO(SDL_AsyncIO* asyncio, bool flush, SDL_AsyncIOQueue* queue, void* userdata); 396 397 /** 398 Create a task queue for tracking multiple I/O operations. 399 400 Async I/O operations are assigned to a queue when started. The queue can be 401 checked for completed tasks thereafter. 402 403 Returns: 404 A new task queue object or $(D null) if there was an error; call 405 $(D SDL_GetError) for more information. 406 407 See_Also: 408 $(D SDL_DestroyAsyncIOQueue) 409 $(D SDL_GetAsyncIOResult) 410 $(D SDL_WaitAsyncIOResult) 411 412 Threadsafety: 413 It is safe to call this function from any thread. 414 415 History: 416 Available since SDL 3.2.0. 417 */ 418 extern SDL_AsyncIOQueue* SDL_CreateAsyncIOQueue(); 419 420 /** 421 Destroy a previously-created async I/O task queue. 422 423 If there are still tasks pending for this queue, this call will block until 424 those tasks are finished. All those tasks will be deallocated. Their 425 results will be lost to the app. 426 427 Any pending reads from $(D SDL_LoadFileAsync) that are still in this queue 428 will have their buffers deallocated by this function, to prevent a memory 429 leak. 430 431 Once this function is called, the queue is no longer valid and should not 432 be used, including by other threads that might access it while destruction 433 is blocking on pending tasks. 434 435 Do not destroy a queue that still has threads waiting on it through 436 $(D SDL_WaitAsyncIOResult). You can call $(D SDL_SignalAsyncIOQueue) first to 437 unblock those threads, and take measures (such as $(D SDL_WaitThread)) to make 438 sure they have finished their wait and won't wait on the queue again. 439 440 Params: 441 queue = the task queue to destroy. 442 443 Threadsafety: 444 It is safe to call this function from any thread, so long as 445 no other thread is waiting on the queue with 446 $(D SDL_WaitAsyncIOResult). 447 448 History: 449 Available since SDL 3.2.0. 450 */ 451 extern void SDL_DestroyAsyncIOQueue(SDL_AsyncIOQueue* queue); 452 453 /** 454 Query an async I/O task queue for completed tasks. 455 456 If a task assigned to this queue has finished, this will return true and 457 fill in `outcome` with the details of the task. If no task in the queue has 458 finished, this function will return false. This function does not block. 459 460 If a task has completed, this function will free its resources and the task 461 pointer will no longer be valid. The task will be removed from the queue. 462 463 It is safe for multiple threads to call this function on the same queue at 464 once; a completed task will only go to one of the threads. 465 466 Params: 467 queue = the async I/O task queue to query. 468 outcome = details of a finished task will be written here. 469 May not be $(D null). 470 Returns: 471 $(D true) if a task has completed, $(D false) otherwise. 472 473 See_Also: 474 $(D SDL_WaitAsyncIOResult) 475 476 Threadsafety: 477 It is safe to call this function from any thread. 478 479 History: 480 Available since SDL 3.2.0. 481 */ 482 extern bool SDL_GetAsyncIOResult(SDL_AsyncIOQueue* queue, SDL_AsyncIOOutcome* outcome); 483 484 /** 485 Block until an async I/O task queue has a completed task. 486 487 This function puts the calling thread to sleep until there a task assigned 488 to the queue that has finished. 489 490 If a task assigned to the queue has finished, this will return true and 491 fill in `outcome` with the details of the task. If no task in the queue has 492 finished, this function will return false. 493 494 If a task has completed, this function will free its resources and the task 495 pointer will no longer be valid. The task will be removed from the queue. 496 497 It is safe for multiple threads to call this function on the same queue at 498 once; a completed task will only go to one of the threads. 499 500 Note that by the nature of various platforms, more than one waiting thread 501 may wake to handle a single task, but only one will obtain it, so 502 `timeoutMS` is a *maximum* wait time, and this function may return false 503 sooner. 504 505 This function may return false if there was a system error, the OS 506 inadvertently awoke multiple threads, or if $(D SDL_SignalAsyncIOQueue) was 507 called to wake up all waiting threads without a finished task. 508 509 A timeout can be used to specify a maximum wait time, but rather than 510 polling, it is possible to have a timeout of -1 to wait forever, and use 511 $(D SDL_SignalAsyncIOQueue) to wake up the waiting threads later. 512 513 514 Params: 515 queue = the async I/O task queue to wait on. 516 outcome = details of a finished task will be written here. May not be 517 $(D null). 518 timeoutMS = the maximum time to wait, in milliseconds, or -1 to wait 519 indefinitely. 520 521 Returns: 522 $(D true) if task has completed, $(D false) otherwise. 523 524 See_Also: 525 $(D SDL_SignalAsyncIOQueue) 526 527 Threadsafety: 528 It is safe to call this function from any thread. 529 530 History: 531 Available since SDL 3.2.0. 532 */ 533 extern bool SDL_WaitAsyncIOResult(SDL_AsyncIOQueue* queue, SDL_AsyncIOOutcome* outcome, Sint32 timeoutMS); 534 535 /** 536 Wake up any threads that are blocking in $(D SDL_WaitAsyncIOResult). 537 538 This will unblock any threads that are sleeping in a call to 539 $(D SDL_WaitAsyncIOResult) for the specified queue, and cause them to return 540 from that function. 541 542 This can be useful when destroying a queue to make sure nothing is touching 543 it indefinitely. In this case, once this call completes, the caller should 544 take measures to make sure any previously-blocked threads have returned 545 from their wait and will not touch the queue again (perhaps by setting a 546 flag to tell the threads to terminate and then using $(D SDL_WaitThread) to 547 make sure they've done so). 548 549 Params: 550 queue = the async I/O task queue to signal. 551 552 See_Also: 553 $(D SDL_WaitAsyncIOResult) 554 555 Threadsafety: 556 It is safe to call this function from any thread. 557 558 History: 559 Available since SDL 3.2.0. 560 */ 561 extern void SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue* queue); 562 563 /** 564 Load all the data from a file path, asynchronously. 565 566 This function returns as quickly as possible; it does not wait for the read 567 to complete. On a successful return, this work will continue in the 568 background. If the work begins, even failure is asynchronous: a failing 569 return value from this function only means the work couldn't start at all. 570 571 The data is allocated with a zero byte at the end (null terminated) for 572 convenience. This extra byte is not included in $(D SDL_AsyncIOOutcome)'s 573 bytes_transferred value. 574 575 This function will allocate the buffer to contain the file. It must be 576 deallocated by calling $(D SDL_free) on $(D SDL_AsyncIOOutcome)'s buffer 577 field after completion. 578 579 An $(D SDL_AsyncIOQueue) must be specified. The newly-created task will 580 be added to it when it completes its work. 581 582 Params: 583 file = the path to read all available data from. 584 queue = a queue to add the new $(D SDL_AsyncIO) to. 585 userdata = an app-defined pointer that will be provided with the task 586 results. 587 588 Returns: 589 $(D true) on success or $(D false) on failure; call $(D SDL_GetError) 590 for more information. 591 592 See_Also: 593 $(D SDL_LoadFile_IO) 594 595 History: 596 Available since SDL 3.2.0. 597 */ 598 extern bool SDL_LoadFileAsync(const(char)* file, SDL_AsyncIOQueue* queue, void* userdata);