aio.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2017/12/30 Bernard The first version.
  9. * 2024/03/26 TroyMitchelle Added some function comments
  10. * 2024/03/27 TroyMitchelle Fix the issue of incorrect return of invalid parameters in aio_write
  11. */
  12. #include <rtthread.h>
  13. #include <rthw.h>
  14. #include <stdint.h>
  15. #include <unistd.h>
  16. #include <fcntl.h>
  17. #include <sys/errno.h>
  18. #include "aio.h"
  19. struct rt_workqueue* aio_queue = NULL;
  20. /**
  21. * The aio_cancel() function shall attempt to cancel one or more asynchronous I/O
  22. * requests currently outstanding against file descriptor fildes. The aiocbp
  23. * argument points to the asynchronous I/O control block for a particular request
  24. * to be canceled. If aiocbp is NULL, then all outstanding cancelable asynchronous
  25. * I/O requests against fildes shall be canceled.
  26. *
  27. * Normal asynchronous notification shall occur for asynchronous I/O operations
  28. * that are successfully canceled. If there are requests that cannot be canceled,
  29. * then the normal asynchronous completion process shall take place for those
  30. * requests when they are completed.
  31. *
  32. * For requested operations that are successfully canceled, the associated error
  33. * status shall be set to [ECANCELED] and the return status shall be -1. For
  34. * requested operations that are not successfully canceled, the aiocbp shall not
  35. * be modified by aio_cancel().
  36. *
  37. * If aiocbp is not NULL, then if fildes does not have the same value as the file
  38. * descriptor with which the asynchronous operation was initiated, unspecified results occur.
  39. *
  40. * Which operations are cancelable is implementation-defined.
  41. */
  42. int aio_cancel(int fd, struct aiocb *cb)
  43. {
  44. rt_err_t ret;
  45. if (!cb) return -EINVAL;
  46. if (cb->aio_fildes != fd) return -EINVAL;
  47. ret = rt_workqueue_cancel_work_sync(aio_queue, &(cb->aio_work));
  48. if (ret == RT_EOK)
  49. {
  50. errno = -ECANCELED;
  51. return -1;
  52. }
  53. return 0;
  54. }
  55. /**
  56. * The aio_error() function shall return the error status associated with the
  57. * aiocb structure referenced by the aiocbp argument. The error status for an
  58. * asynchronous I/O operation is the errno value that would be set by the corresponding
  59. * read(), write(),
  60. */
  61. int aio_error(const struct aiocb *cb)
  62. {
  63. if (cb)
  64. {
  65. return cb->aio_result;
  66. }
  67. return -EINVAL;
  68. }
  69. /**
  70. * The aio_fsync() function shall asynchronously perform a file synchronization
  71. * operation, as specified by the op argument, for I/O operations associated with
  72. * the file indicated by the file descriptor aio_fildes member of the aiocb
  73. * structure referenced by the aiocbp argument and queued at the time of the
  74. * call to aio_fsync(). The function call shall return when the synchronization
  75. * request has been initiated or queued to the file or device (even when the data
  76. * cannot be synchronized immediately).
  77. *
  78. * option: If op is O_DSYNC, all currently queued I/O operations shall be completed
  79. * as if by a call to fdatasync(); that is, as defined for synchronized I/O data
  80. * integrity completion.
  81. *
  82. * option: If op is O_SYNC, all currently queued I/O operations shall be completed
  83. * as if by a call to fsync(); that is, as defined for synchronized I/O file integrity
  84. * completion. If the aio_fsync() function fails, or if the operation queued by
  85. * aio_fsync() fails, then outstanding I/O operations are not guaranteed to have
  86. * been completed.
  87. *
  88. * If aio_fsync() succeeds, then it is only the I/O that was queued at the time
  89. * of the call to aio_fsync() that is guaranteed to be forced to the relevant
  90. * completion state. The completion of subsequent I/O on the file descriptor is
  91. * not guaranteed to be completed in a synchronized fashion.
  92. *
  93. * The aiocbp argument refers to an asynchronous I/O control block. The aiocbp
  94. * value may be used as an argument to aio_error() and aio_return() in order to
  95. * determine the error status and return status, respectively, of the asynchronous
  96. * operation while it is proceeding. When the request is queued, the error status
  97. * for the operation is [EINPROGRESS]. When all data has been successfully transferred,
  98. * the error status shall be reset to reflect the success or failure of the operation.
  99. * If the operation does not complete successfully, the error status for the
  100. * operation shall be set to indicate the error. The aio_sigevent member determines
  101. * the asynchronous notification to occur as specified in Signal Generation and
  102. * Delivery when all operations have achieved synchronized I/O completion. All
  103. * other members of the structure referenced by aiocbp are ignored. If the control
  104. * block referenced by aiocbp becomes an illegal address prior to asynchronous
  105. * I/O completion, then the behavior is undefined.
  106. *
  107. * If the aio_fsync() function fails or aiocbp indicates an error condition,
  108. * data is not guaranteed to have been successfully transferred.
  109. */
  110. static void aio_fync_work(struct rt_work* work, void* work_data)
  111. {
  112. int result;
  113. rt_base_t level;
  114. struct aiocb *cb = (struct aiocb*)work_data;
  115. RT_ASSERT(cb != RT_NULL);
  116. result = fsync(cb->aio_fildes);
  117. /* modify result */
  118. level = rt_hw_interrupt_disable();
  119. if (result < 0)
  120. cb->aio_result = errno;
  121. else
  122. cb->aio_result = 0;
  123. rt_hw_interrupt_enable(level);
  124. return ;
  125. }
  126. /**
  127. * @brief Initiates an asynchronous fsync operation.
  128. *
  129. * This function initiates an asynchronous fsync operation on the file associated
  130. * with the specified aiocb structure. The operation is queued to the workqueue
  131. * for execution.
  132. *
  133. * @param op The operation to be performed. This parameter is ignored.
  134. * @param cb Pointer to the aiocb structure representing the asynchronous fsync operation.
  135. *
  136. * @return Returns 0 on success.
  137. */
  138. int aio_fsync(int op, struct aiocb *cb)
  139. {
  140. rt_base_t level;
  141. if (!cb) return -EINVAL;
  142. level = rt_hw_interrupt_disable();
  143. cb->aio_result = -EINPROGRESS;
  144. rt_hw_interrupt_enable(level);
  145. rt_work_init(&(cb->aio_work), aio_fync_work, cb);
  146. rt_workqueue_dowork(aio_queue, &(cb->aio_work));
  147. return 0;
  148. }
  149. /**
  150. * @brief Worker function for asynchronous read operation.
  151. *
  152. * This function performs the actual reading of data from the file associated with
  153. * the specified aiocb structure. It sets the result of the operation in the
  154. * aio_result field of the aiocb structure.
  155. *
  156. * @param work Pointer to the work item.
  157. * @param work_data Pointer to the aiocb structure representing the asynchronous read operation.
  158. */
  159. static void aio_read_work(struct rt_work* work, void* work_data)
  160. {
  161. int len;
  162. rt_base_t level;
  163. uint8_t *buf_ptr;
  164. struct aiocb *cb = (struct aiocb*)work_data;
  165. buf_ptr = (uint8_t*)cb->aio_buf;
  166. /* seek to offset */
  167. lseek(cb->aio_fildes, cb->aio_offset, SEEK_SET);
  168. len = read(cb->aio_fildes, &buf_ptr[cb->aio_offset], cb->aio_nbytes);
  169. /* modify result */
  170. level = rt_hw_interrupt_disable();
  171. if (len <= 0)
  172. cb->aio_result = errno;
  173. else
  174. cb->aio_result = len;
  175. rt_hw_interrupt_enable(level);
  176. return ;
  177. }
  178. /**
  179. * The aio_read() function shall read aiocbp->aio_nbytes from the file associated
  180. * with aiocbp->aio_fildes into the buffer pointed to by aiocbp->aio_buf. The
  181. * function call shall return when the read request has been initiated or queued
  182. * to the file or device (even when the data cannot be delivered immediately).
  183. *
  184. * If prioritized I/O is supported for this file, then the asynchronous operation
  185. * shall be submitted at a priority equal to a base scheduling priority minus
  186. * aiocbp->aio_reqprio. If Thread Execution Scheduling is not supported, then
  187. * the base scheduling priority is that of the calling process;
  188. *
  189. * otherwise, the base scheduling priority is that of the calling thread.
  190. *
  191. * The aiocbp value may be used as an argument to aio_error() and aio_return()
  192. * in order to determine the error status and return status, respectively, of
  193. * the asynchronous operation while it is proceeding. If an error condition is
  194. * encountered during queuing, the function call shall return without having
  195. * initiated or queued the request. The requested operation takes place at the
  196. * absolute position in the file as given by aio_offset, as if lseek() were called
  197. * immediately prior to the operation with an offset equal to aio_offset and a
  198. * whence equal to SEEK_SET. After a successful call to enqueue an asynchronous
  199. * I/O operation, the value of the file offset for the file is unspecified.
  200. *
  201. * The aio_sigevent member specifies the notification which occurs when the
  202. * request is completed.
  203. *
  204. * The aiocbp->aio_lio_opcode field shall be ignored by aio_read().
  205. *
  206. * The aiocbp argument points to an aiocb structure. If the buffer pointed to by
  207. * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal
  208. * address prior to asynchronous I/O completion, then the behavior is undefined.
  209. *
  210. * Simultaneous asynchronous operations using the same aiocbp produce undefined
  211. * results.
  212. *
  213. * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes,
  214. * the behavior of this function shall be according to the definitions of synchronized
  215. * I/O data integrity completion and synchronized I/O file integrity completion.
  216. *
  217. * For any system action that changes the process memory space while an asynchronous
  218. * I/O is outstanding to the address range being changed, the result of that action
  219. * is undefined.
  220. *
  221. * For regular files, no data transfer shall occur past the offset maximum
  222. * established in the open file description associated with aiocbp->aio_fildes.
  223. *
  224. */
  225. int aio_read(struct aiocb *cb)
  226. {
  227. rt_base_t level;
  228. if (!cb) return -EINVAL;
  229. if (cb->aio_offset < 0) return -EINVAL;
  230. level = rt_hw_interrupt_disable();
  231. cb->aio_result = -EINPROGRESS;
  232. rt_hw_interrupt_enable(level);
  233. /* en-queue read work */
  234. rt_work_init(&(cb->aio_work), aio_read_work, cb);
  235. rt_workqueue_dowork(aio_queue, &(cb->aio_work));
  236. return 0;
  237. }
  238. /**
  239. * The aio_return() function shall return the return status associated with the
  240. * aiocb structure referenced by the aiocbp argument. The return status for an
  241. * asynchronous I/O operation is the value that would be returned by the corresponding
  242. * read(), write(), or fsync() function call. If the error status for the operation
  243. * is equal to [EINPROGRESS], then the return status for the operation is undefined.
  244. * The aio_return() function may be called exactly once to retrieve the return
  245. * status of a given asynchronous operation; thereafter, if the same aiocb structure
  246. * is used in a call to aio_return() or aio_error(), an error may be returned.
  247. * When the aiocb structure referred to by aiocbp is used to submit another asynchronous
  248. * operation, then aio_return() may be successfully used to retrieve the return
  249. * status of that operation.
  250. */
  251. ssize_t aio_return(struct aiocb *cb)
  252. {
  253. if (cb)
  254. {
  255. if (cb->aio_result < 0)
  256. rt_set_errno(cb->aio_result);
  257. return cb->aio_result;
  258. }
  259. return -EINVAL;
  260. }
  261. /**
  262. * The aio_suspend() function shall suspend the calling thread until at least
  263. * one of the asynchronous I/O operations referenced by the list argument has
  264. * completed, until a signal interrupts the function, or, if timeout is not NULL,
  265. * until the time interval specified by timeout has passed. If any of the aiocb
  266. * structures in the list correspond to completed asynchronous I/O operations
  267. * (that is, the error status for the operation is not equal to [EINPROGRESS])
  268. * at the time of the call, the function shall return without suspending the
  269. * calling thread. The list argument is an array of pointers to asynchronous I/O
  270. * control blocks. The nent argument indicates the number of elements in the
  271. * array. Each aiocb structure pointed to has been used in initiating an asynchronous
  272. * I/O request via aio_read(), aio_write(), or lio_listio(). This array may
  273. * contain null pointers, which are ignored. If this array contains pointers
  274. * that refer to aiocb structures that have not been used in submitting asynchronous
  275. * I/O, the effect is undefined.
  276. *
  277. * If the time interval indicated in the timespec structure pointed to by timeout
  278. * passes before any of the I/O operations referenced by list are completed, then
  279. * aio_suspend() shall return with an error.
  280. */
  281. int aio_suspend(const struct aiocb *const list[], int nent,
  282. const struct timespec *timeout)
  283. {
  284. return -ENOSYS;
  285. }
  286. /**
  287. * @brief Worker function for asynchronous write operation.
  288. *
  289. * This function performs the actual writing of data to the file associated with
  290. * the specified aiocb structure. It sets the result of the operation in the
  291. * aio_result field of the aiocb structure.
  292. *
  293. * @param work Pointer to the work item.
  294. * @param work_data Pointer to the aiocb structure representing the asynchronous write operation.
  295. */
  296. static void aio_write_work(struct rt_work* work, void* work_data)
  297. {
  298. rt_base_t level;
  299. int len, oflags;
  300. uint8_t *buf_ptr;
  301. struct aiocb *cb = (struct aiocb*)work_data;
  302. buf_ptr = (uint8_t*)cb->aio_buf;
  303. /* whether seek offset */
  304. oflags = fcntl(cb->aio_fildes, F_GETFL, 0);
  305. if ((oflags & O_APPEND) == 0)
  306. {
  307. lseek(cb->aio_fildes, SEEK_SET, cb->aio_offset);
  308. }
  309. /* write data */
  310. len = write(cb->aio_fildes, buf_ptr, cb->aio_nbytes);
  311. /* modify result */
  312. level = rt_hw_interrupt_disable();
  313. if (len <= 0)
  314. cb->aio_result = errno;
  315. else
  316. cb->aio_result = len;
  317. rt_hw_interrupt_enable(level);
  318. return;
  319. }
  320. /**
  321. * The aio_write() function shall write aiocbp->aio_nbytes to the file associated
  322. * with aiocbp->aio_fildes from the buffer pointed to by aiocbp->aio_buf. The
  323. * function shall return when the write request has been initiated or, at a minimum,
  324. * queued to the file or device.
  325. *
  326. * The aiocbp argument may be used as an argument to aio_error() and aio_return()
  327. * in order to determine the error status and return status, respectively, of the
  328. * asynchronous operation while it is proceeding.
  329. *
  330. * The aiocbp argument points to an aiocb structure. If the buffer pointed to by
  331. * aiocbp->aio_buf or the control block pointed to by aiocbp becomes an illegal
  332. * address prior to asynchronous I/O completion, then the behavior is undefined.
  333. *
  334. * If O_APPEND is not set for the file descriptor aio_fildes, then the requested
  335. * operation shall take place at the absolute position in the file as given by
  336. * aio_offset, as if lseek() were called immediately prior to the operation with
  337. * an offset equal to aio_offset and a whence equal to SEEK_SET. If O_APPEND is
  338. * set for the file descriptor, or if aio_fildes is associated with a device that
  339. * is incapable of seeking, write operations append to the file in the same order
  340. * as the calls were made, except under circumstances described in Asynchronous
  341. * I/O. After a successful call to enqueue an asynchronous I/O operation, the value
  342. * of the file offset for the file is unspecified.
  343. *
  344. * The aio_sigevent member specifies the notification which occurs when the request
  345. * is completed.
  346. *
  347. * The aiocbp->aio_lio_opcode field shall be ignored by aio_write().
  348. *
  349. * Simultaneous asynchronous operations using the same aiocbp produce undefined
  350. * results.
  351. *
  352. * If synchronized I/O is enabled on the file associated with aiocbp->aio_fildes,
  353. * the behavior of this function shall be according to the definitions of synchronized
  354. * I/O data integrity completion, and synchronized I/O file integrity completion.
  355. *
  356. * For regular files, no data transfer shall occur past the offset maximum established
  357. * in the open file description associated with aiocbp->aio_fildes.
  358. */
  359. int aio_write(struct aiocb *cb)
  360. {
  361. int oflags;
  362. rt_base_t level;
  363. if (!cb || (cb->aio_buf == NULL)) return -EINVAL;
  364. /* check access mode */
  365. oflags = fcntl(cb->aio_fildes, F_GETFL, 0);
  366. /* If the flag is not in write only or read-write mode, it cannot be written then an invalid parameter is returned */
  367. if ((oflags & O_ACCMODE) != O_WRONLY &&
  368. (oflags & O_ACCMODE) != O_RDWR)
  369. return -EINVAL;
  370. level = rt_hw_interrupt_disable();
  371. cb->aio_result = -EINPROGRESS;
  372. rt_hw_interrupt_enable(level);
  373. rt_work_init(&(cb->aio_work), aio_write_work, cb);
  374. rt_workqueue_dowork(aio_queue, &(cb->aio_work));
  375. return 0;
  376. }
  377. /**
  378. * The lio_listio() function shall initiate a list of I/O requests with a single
  379. * function call.
  380. *
  381. * The mode argument takes one of the values LIO_WAIT or LIO_NOWAIT declared in
  382. * <aio.h> and determines whether the function returns when the I/O operations
  383. * have been completed, or as soon as the operations have been queued. If the
  384. * mode argument is LIO_WAIT, the function shall wait until all I/O is complete
  385. * and the sig argument shall be ignored.
  386. *
  387. * If the mode argument is LIO_NOWAIT, the function shall return immediately, and
  388. * asynchronous notification shall occur, according to the sig argument, when all
  389. * the I/O operations complete. If sig is NULL, then no asynchronous notification
  390. * shall occur. If sig is not NULL, asynchronous notification occurs as specified
  391. * in Signal Generation and Delivery when all the requests in list have completed.
  392. *
  393. * The I/O requests enumerated by list are submitted in an unspecified order.
  394. *
  395. * The list argument is an array of pointers to aiocb structures. The array contains
  396. * nent elements. The array may contain NULL elements, which shall be ignored.
  397. *
  398. * If the buffer pointed to by list or the aiocb structures pointed to by the
  399. * elements of the array list become illegal addresses before all asynchronous I/O
  400. * completed and, if necessary, the notification is sent, then the behavior is
  401. * undefined. If the buffers pointed to by the aio_buf member of the aiocb structure
  402. * pointed to by the elements of the array list become illegal addresses prior to
  403. * the asynchronous I/O associated with that aiocb structure being completed, the
  404. * behavior is undefined.
  405. *
  406. * The aio_lio_opcode field of each aiocb structure specifies the operation to be
  407. * performed. The supported operations are LIO_READ, LIO_WRITE, and LIO_NOP; these
  408. * symbols are defined in <aio.h>. The LIO_NOP operation causes the list entry to
  409. * be ignored. If the aio_lio_opcode element is equal to LIO_READ, then an I/O operation
  410. * is submitted as if by a call to aio_read() with the aiocbp equal to the address
  411. * of the aiocb structure. If the aio_lio_opcode element is equal to LIO_WRITE, then
  412. * an I/O operation is submitted as if by a call to aio_write() with the aiocbp equal
  413. * to the address of the aiocb structure.
  414. *
  415. * The aio_fildes member specifies the file descriptor on which the operation is to
  416. * be performed.
  417. *
  418. * The aio_buf member specifies the address of the buffer to or from which the data
  419. * is transferred.
  420. *
  421. * The aio_nbytes member specifies the number of bytes of data to be transferred.
  422. *
  423. * The members of the aiocb structure further describe the I/O operation to be
  424. * performed, in a manner identical to that of the corresponding aiocb structure
  425. * when used by the aio_read() and aio_write() functions.
  426. *
  427. * The nent argument specifies how many elements are members of the list; that is,
  428. * the length of the array.
  429. *
  430. * The behavior of this function is altered according to the definitions of synchronized
  431. * I/O data integrity completion and synchronized I/O file integrity completion if
  432. * synchronized I/O is enabled on the file associated with aio_fildes.
  433. *
  434. * For regular files, no data transfer shall occur past the offset maximum established
  435. * in the open file description associated with aiocbp->aio_fildes.
  436. *
  437. * If sig->sigev_notify is SIGEV_THREAD and sig->sigev_notify_attributes is a
  438. * non-null pointer and the block pointed to by this pointer becomes an illegal
  439. * address prior to all asynchronous I/O being completed, then the behavior is
  440. * undefined.
  441. */
  442. int lio_listio(int mode, struct aiocb * const list[], int nent,
  443. struct sigevent *sig)
  444. {
  445. return -ENOSYS;
  446. }
  447. /**
  448. * @brief Initializes the asynchronous I/O system.
  449. *
  450. * This function initializes the asynchronous I/O system by creating a workqueue
  451. * for asynchronous I/O operations.
  452. *
  453. * @return Returns 0 on success.
  454. */
  455. int aio_system_init(void)
  456. {
  457. aio_queue = rt_workqueue_create("aio", 2048, RT_THREAD_PRIORITY_MAX/2);
  458. RT_ASSERT(aio_queue != NULL);
  459. return 0;
  460. }
  461. INIT_COMPONENT_EXPORT(aio_system_init);