Baselib_FileIO.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #pragma once
  2. // Baselib FileIO
  3. //
  4. // This is a file reading abstraction api heavily influenced by next-gen async API's like io_uring, windows register I/O, etc.
  5. // This api allows for platform independent async file reading.
  6. #include "Baselib_ErrorState.h"
  7. #include "Baselib_Memory.h"
  8. #include "Internal/Baselib_EnumSizeCheck.h"
  9. #ifdef __cplusplus
  10. BASELIB_C_INTERFACE
  11. {
  12. #endif
  13. // Event queue handle.
  14. typedef struct Baselib_FileIO_EventQueue {void* handle;} Baselib_FileIO_EventQueue;
  15. // Async file handle.
  16. typedef struct Baselib_FileIO_AsyncFile {void* handle;} Baselib_FileIO_AsyncFile;
  17. // Sync file handle.
  18. typedef struct Baselib_FileIO_SyncFile {void* handle;} Baselib_FileIO_SyncFile;
  19. // Event queue handle invalid constant.
  20. static const Baselib_FileIO_EventQueue Baselib_FileIO_EventQueue_Invalid = { NULL };
  21. // Async file handle invalid constant.
  22. static const Baselib_FileIO_AsyncFile Baselib_FileIO_AsyncFile_Invalid = { NULL };
  23. // Sync file handle invalid constant.
  24. static const Baselib_FileIO_SyncFile Baselib_FileIO_SyncFile_Invalid = { (void*)-1 };
  25. typedef enum Baselib_FileIO_OpenFlags_t
  26. {
  27. // Allows read access to the file.
  28. Baselib_FileIO_OpenFlags_Read = 0x01,
  29. // Allows write access to the file.
  30. Baselib_FileIO_OpenFlags_Write = 0x02,
  31. // Opens existing file without changes or creates 0 size file if file doesn't exist.
  32. // On some platforms open will implicitly add write flag if required by native API's.
  33. Baselib_FileIO_OpenFlags_OpenAlways = 0x04,
  34. // Always creates 0 size file.
  35. // On some platforms open will implicitly add write flag if required by native API's.
  36. Baselib_FileIO_OpenFlags_CreateAlways = 0x08,
  37. } Baselib_FileIO_OpenFlags_t;
  38. typedef uint32_t Baselib_FileIO_OpenFlags;
  39. // File IO read request.
  40. typedef struct Baselib_FileIO_ReadRequest
  41. {
  42. // Offset in a file to read from.
  43. // If offset+size is pointing pass EOF, will read up to EOF bytes.
  44. // If offset is pointing pass EOF, will read 0 bytes.
  45. uint64_t offset;
  46. // Buffer to read to, must be available for duration of operation.
  47. void* buffer;
  48. // Size of requested read.
  49. // If 0 is passed will read 0 bytes and raise no error.
  50. uint64_t size;
  51. } Baselib_FileIO_ReadRequest;
  52. // File IO priorities.
  53. // First we process all requests with high priority, then with normal priority.
  54. // There's no round-robin, and high priority can starve normal priority.
  55. typedef enum Baselib_FileIO_Priority
  56. {
  57. Baselib_FileIO_Priority_Normal = 0,
  58. Baselib_FileIO_Priority_High = 1
  59. } Baselib_FileIO_Priority;
  60. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_FileIO_Priority);
  61. typedef enum Baselib_FileIO_EventQueue_ResultType
  62. {
  63. // Upon receiving this event, please call the provided callback with provided data argument.
  64. Baselib_FileIO_EventQueue_Callback = 1,
  65. // Result of open file operation.
  66. Baselib_FileIO_EventQueue_OpenFile = 2,
  67. // Result of read file operation.
  68. Baselib_FileIO_EventQueue_ReadFile = 3,
  69. // Result of close file operation.
  70. Baselib_FileIO_EventQueue_CloseFile = 4
  71. } Baselib_FileIO_EventQueue_ResultType;
  72. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_FileIO_EventQueue_ResultType);
  73. typedef void (*EventQueueCallback)(uint64_t userdata);
  74. typedef struct Baselib_FileIO_EventQueue_Result_Callback
  75. {
  76. // Please invoke this callback with userdata from the event.
  77. EventQueueCallback callback;
  78. } Baselib_FileIO_EventQueue_Result_Callback;
  79. typedef struct Baselib_FileIO_EventQueue_Result_OpenFile
  80. {
  81. // Size of the file as seen on during open.
  82. uint64_t fileSize;
  83. } Baselib_FileIO_EventQueue_Result_OpenFile;
  84. typedef struct Baselib_FileIO_EventQueue_Result_ReadFile
  85. {
  86. // Bytes transferred during read.
  87. uint64_t bytesTransferred;
  88. } Baselib_FileIO_EventQueue_Result_ReadFile;
  89. // Event queue result.
  90. typedef struct Baselib_FileIO_EventQueue_Result
  91. {
  92. // Event type.
  93. Baselib_FileIO_EventQueue_ResultType type;
  94. // Userdata as provided to the request.
  95. uint64_t userdata;
  96. // Error state of the operation.
  97. Baselib_ErrorState errorState;
  98. union
  99. {
  100. Baselib_FileIO_EventQueue_Result_Callback callback;
  101. Baselib_FileIO_EventQueue_Result_OpenFile openFile;
  102. Baselib_FileIO_EventQueue_Result_ReadFile readFile;
  103. };
  104. } Baselib_FileIO_EventQueue_Result;
  105. // Creates event queue.
  106. //
  107. // \returns Event queue.
  108. BASELIB_API Baselib_FileIO_EventQueue Baselib_FileIO_EventQueue_Create(void);
  109. // Frees event queue.
  110. //
  111. // \param eq event queue to free.
  112. BASELIB_API void Baselib_FileIO_EventQueue_Free(
  113. Baselib_FileIO_EventQueue eq
  114. );
  115. // Dequeue events from event queue.
  116. //
  117. // \param eq Event queue to dequeue from.
  118. // \param results Results array to dequeue elements into.
  119. // If null will return 0.
  120. // \param count Amount of elements in results array.
  121. // If equals 0 will return 0.
  122. // \param timeoutInMilliseconds If no elements are present in the queue,
  123. // waits for any elements to be appear for specified amount of time.
  124. // If 0 is passed, wait is omitted.
  125. // If elements are present, dequeues up-to-count elements, and wait is omitted.
  126. //
  127. // File operations errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  128. // Possible error codes:
  129. // - InvalidPathname: Requested pathname is invalid (not found, a directory, etc).
  130. // - RequestedAccessIsNotAllowed: Access to requested pathname is not allowed.
  131. // - IOError: IO error occured.
  132. //
  133. // \returns Amount of results filled.
  134. BASELIB_API uint64_t Baselib_FileIO_EventQueue_Dequeue(
  135. Baselib_FileIO_EventQueue eq,
  136. Baselib_FileIO_EventQueue_Result results[],
  137. uint64_t count,
  138. uint32_t timeoutInMilliseconds // 0 will return immediately
  139. );
  140. // Request dequeue to shutdown
  141. //
  142. // \param eq Event queue to shutdown.
  143. // \param threadCount Number of threads to signal termination
  144. //
  145. // An empty queue will hang in Baselib_FileIO_EventQueue_Dequeue for as long as the timeout lasts.
  146. // This function can be used to exit such a condition
  147. BASELIB_API void Baselib_FileIO_EventQueue_Shutdown(
  148. Baselib_FileIO_EventQueue eq,
  149. uint32_t threadCount
  150. );
  151. // Asynchronously opens a file.
  152. //
  153. // \param eq Event queue to associate file with.
  154. // File can only be associated with one event queue,
  155. // but one event queue can be associated with multiple files.
  156. // If invalid event queue is passed, will return invalid file handle.
  157. // \param pathname Platform defined pathname of a file.
  158. // Can be freed after this function returns.
  159. // If null is passed will return invalid file handle.
  160. // \param userdata Userdata to be set in the completion event.
  161. // \param priority Priority for file opening operation.
  162. //
  163. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  164. // Possible error codes:
  165. // - InvalidPathname: Requested pathname is invalid (not found, a directory, etc).
  166. // - RequestedAccessIsNotAllowed: Access to requested pathname is not allowed.
  167. // - IOError: IO error occured.
  168. //
  169. // \returns Async file handle, which can be used immediately for scheduling other operations.
  170. // In case if file opening fails, all scheduled operations will fail as well.
  171. // In case if invalid arguments are passed, might return invalid file handle (see args descriptions).
  172. BASELIB_API Baselib_FileIO_AsyncFile Baselib_FileIO_AsyncOpen(
  173. Baselib_FileIO_EventQueue eq,
  174. const char* pathname,
  175. uint64_t userdata,
  176. Baselib_FileIO_Priority priority
  177. );
  178. // Asynchronously reads data from a file.
  179. //
  180. // Note scheduling reads on closed file is undefined.
  181. //
  182. // \param file Async file to read from.
  183. // If invalid file handle is passed, will no-op.
  184. // If file handle was already closed, behavior is undefined.
  185. // \param requests Requests to schedule.
  186. // If more than 1 provided,
  187. // will provide completion event per individual request in the array.
  188. // If null is passed, will no-op.
  189. // \param count Amount of requests in requests array.
  190. // If 0 is passed, will no-op.
  191. // \param userdata Userdata to be set in the completion event(s).
  192. // \param priority Priority for file reading operation(s).
  193. //
  194. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  195. // If file is invalid handle, error can not be reported because event queue is not known.
  196. // Possible error codes:
  197. // - IOError: IO error occured.
  198. BASELIB_API void Baselib_FileIO_AsyncRead(
  199. Baselib_FileIO_AsyncFile file,
  200. Baselib_FileIO_ReadRequest requests[],
  201. uint64_t count,
  202. uint64_t userdata,
  203. Baselib_FileIO_Priority priority
  204. );
  205. // Asynchronously closes a file.
  206. //
  207. // Will wait for all pending operations to complete,
  208. // after that will close a file and put a completion event.
  209. //
  210. // \param file Async file to close.
  211. // If invalid file handle is passed, will no-op.
  212. //
  213. // Please note errors are reported via Baselib_FileIO_EventQueue_Result::errorState
  214. // If file is invalid handle, error can not be reported because event queue is not known.
  215. // Possible error codes:
  216. // - IOError: IO error occured.
  217. BASELIB_API void Baselib_FileIO_AsyncClose(
  218. Baselib_FileIO_AsyncFile file
  219. );
  220. // Synchronously opens a file.
  221. //
  222. // Will try use the most open access permissions options that are available for each platform.
  223. // Meaning it might be possible for other process to write to file opened via this API.
  224. // On most platforms file can be simultaneously opened with different open flags.
  225. // If you require more strict options, or platform specific access configuration, please use Baselib_FileIO_SyncFileFromNativeHandle.
  226. //
  227. // \param pathname Platform defined pathname to open.
  228. // \param openFlags Open flags.
  229. // If file is created because one of Create flags is passed, it will have size of 0 bytes.
  230. //
  231. // Possible error codes:
  232. // - InvalidArgument: Invalid argument was passed.
  233. // - RequestedAccessIsNotAllowed: Request access is not allowed.
  234. // - IOError: Generic IO error occured.
  235. //
  236. // \returns SyncFile handle.
  237. BASELIB_API Baselib_FileIO_SyncFile Baselib_FileIO_SyncOpen(
  238. const char* pathname,
  239. Baselib_FileIO_OpenFlags openFlags,
  240. Baselib_ErrorState* errorState
  241. );
  242. // Transfer ownership of native handle to Baselib_FileIO_SyncFile handle.
  243. //
  244. // This function transfers ownership, meaning you don't need to close native handle yourself,
  245. // instead returned SyncFile must closed via Baselib_FileIO_SyncClose.
  246. // Implementations might cache information about the file state,
  247. // so native handle shouldn't be used after transfering ownership.
  248. //
  249. // \param handle Platform defined native handle.
  250. // If invalid native handle is passed, will return Baselib_FileIO_SyncFile_Invalid.
  251. // \param type Platform defined native handle type from Baselib_FileIO_NativeHandleType enum.
  252. // If unsupported type is passed, will return Baselib_FileIO_SyncFile_Invalid.
  253. //
  254. // \returns SyncFile handle.
  255. BASELIB_API Baselib_FileIO_SyncFile Baselib_FileIO_SyncFileFromNativeHandle(
  256. uint64_t handle,
  257. uint32_t type
  258. );
  259. // Synchronously reads data from a file.
  260. //
  261. // \param file File to read from.
  262. // If invalid file handle is passed, will raise InvalidArgument error and return 0.
  263. // \param offset Offset in the file to read data at.
  264. // If offset+size goes past end-of-file (EOF), function will read until EOF.
  265. // If offset points past EOF, will return 0.
  266. // \param buffer Pointer to data to read into.
  267. // \param size Size of data to read.
  268. //
  269. // Possible error codes:
  270. // - InvalidArgument: Invalid argument was passed.
  271. // - IOError: Generic IO error occured.
  272. //
  273. // \returns Amount of bytes read.
  274. BASELIB_API uint64_t Baselib_FileIO_SyncRead(
  275. Baselib_FileIO_SyncFile file,
  276. uint64_t offset,
  277. void* buffer,
  278. uint64_t size,
  279. Baselib_ErrorState* errorState
  280. );
  281. // Synchronously writes data to a file.
  282. //
  283. // \param file File to write to.
  284. // If invalid file handle is passed, will raise InvalidArgument error and return 0.
  285. // \param offset Offset in the file to write data at.
  286. // If offset+size goes past end-of-file (EOF), then file will be resized.
  287. // \param buffer Pointer to data to write.
  288. // \param size Size of data to write.
  289. //
  290. // Possible error codes:
  291. // - InvalidArgument: Invalid argument was passed.
  292. // - IOError: Generic IO error occured.
  293. //
  294. // \returns Amount of bytes written.
  295. BASELIB_API uint64_t Baselib_FileIO_SyncWrite(
  296. Baselib_FileIO_SyncFile file,
  297. uint64_t offset,
  298. const void* buffer,
  299. uint64_t size,
  300. Baselib_ErrorState* errorState
  301. );
  302. // Synchronously flushes file buffers.
  303. //
  304. // Operating system might buffer some write operations.
  305. // Flushing buffers is required to guarantee (best effort) writing data to disk.
  306. //
  307. // \param file File to flush.
  308. // If invalid file handle is passed, will no-op.
  309. //
  310. // Possible error codes:
  311. // - InvalidArgument: Invalid argument was passed.
  312. // - IOError: Generic IO error occured.
  313. BASELIB_API void Baselib_FileIO_SyncFlush(
  314. Baselib_FileIO_SyncFile file,
  315. Baselib_ErrorState* errorState
  316. );
  317. // Synchronously changes file size.
  318. //
  319. // \param file File to get size of.
  320. // If invalid file handle is passed, will raise invalid argument error.
  321. // \param size New file size.
  322. //
  323. // Possible error codes:
  324. // - InvalidArgument: Invalid argument was passed.
  325. // - IOError: Generic IO error occured.
  326. //
  327. // \returns File size.
  328. BASELIB_API void Baselib_FileIO_SyncSetFileSize(
  329. Baselib_FileIO_SyncFile file,
  330. uint64_t size,
  331. Baselib_ErrorState* errorState
  332. );
  333. // Synchronously retrieves file size.
  334. //
  335. // \param file File to get size of.
  336. // If invalid file handle is passed, will return 0.
  337. //
  338. // Possible error codes:
  339. // - InvalidArgument: Invalid argument was passed.
  340. // - IOError: Generic IO error occured.
  341. //
  342. // \returns File size.
  343. BASELIB_API uint64_t Baselib_FileIO_SyncGetFileSize(
  344. Baselib_FileIO_SyncFile file,
  345. Baselib_ErrorState* errorState
  346. );
  347. // Synchronously closes a file.
  348. //
  349. // Close does not guarantee that the data was written to disk,
  350. // Please use Baselib_FileIO_SyncFlush to guarantee (best effort) that data was written to disk.
  351. //
  352. // \param file File to close.
  353. // If invalid file handle is passed, will no-op.
  354. //
  355. // Possible error codes:
  356. // - InvalidArgument: Invalid argument was passed.
  357. // - IOError: Generic IO error occured.
  358. BASELIB_API void Baselib_FileIO_SyncClose(
  359. Baselib_FileIO_SyncFile file,
  360. Baselib_ErrorState* errorState
  361. );
  362. #include <C/Baselib_FileIO.inl.h>
  363. #ifdef __cplusplus
  364. } // BASELIB_C_INTERFACE
  365. #endif