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