int do_test (int argc, char *argv[]) { struct aiocb cbs[10]; struct aiocb cbs_fsync; struct aiocb *cbp[10]; struct aiocb *cbp_fsync[1]; char buf[1000]; size_t cnt; int result = 0; /* Preparation. */ for (cnt = 0; cnt < 10; ++cnt) { cbs[cnt].aio_fildes = fd; cbs[cnt].aio_reqprio = 0; cbs[cnt].aio_buf = memset (&buf[cnt * 100], '0' + cnt, 100); cbs[cnt].aio_nbytes = 100; cbs[cnt].aio_offset = cnt * 100; cbs[cnt].aio_sigevent.sigev_notify = SIGEV_NONE; cbp[cnt] = &cbs[cnt]; } /* First a simple test. */ for (cnt = 10; cnt > 0; ) if (aio_write (cbp[--cnt]) < 0 && errno == ENOSYS) { error (0, 0, "no aio support in this configuration"); return 0; } /* Wait 'til the results are there. */ result |= do_wait (cbp, 10, 0); /* Test this. */ result |= test_file (buf, sizeof (buf), fd, "aio_write"); /* Read now as we've written it. */ memset (buf, '\0', sizeof (buf)); /* Issue the commands. */ for (cnt = 10; cnt > 0; ) { --cnt; cbp[cnt] = &cbs[cnt]; aio_read (cbp[cnt]); } /* Wait 'til the results are there. */ result |= do_wait (cbp, 10, 0); /* Test this. */ for (cnt = 0; cnt < 1000; ++cnt) if (buf[cnt] != '0' + (cnt / 100)) { result = 1; error (0, 0, "comparison failed for aio_read test"); break; } if (cnt == 1000) puts ("aio_read test ok"); /* Remove the test file contents. */ if (ftruncate (fd, 0) < 0) { error (0, errno, "ftruncate failed\n"); result = 1; } /* Test lio_listio. */ for (cnt = 0; cnt < 10; ++cnt) { cbs[cnt].aio_lio_opcode = LIO_WRITE; cbp[cnt] = &cbs[cnt]; } /* Issue the command. */ lio_listio (LIO_WAIT, cbp, 10, NULL); /* ...and immediately test it since we started it in wait mode. */ result |= test_file (buf, sizeof (buf), fd, "lio_listio (write)"); /* Test aio_fsync. */ cbs_fsync.aio_fildes = fd; cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE; cbp_fsync[0] = &cbs_fsync; /* Remove the test file contents first. */ if (ftruncate (fd, 0) < 0) { error (0, errno, "ftruncate failed\n"); result = 1; } /* Write again. */ for (cnt = 10; cnt > 0; ) aio_write (cbp[--cnt]); if (aio_fsync (O_SYNC, &cbs_fsync) < 0) { error (0, errno, "aio_fsync failed\n"); result = 1; } result |= do_wait (cbp_fsync, 1, 0); /* ...and test since all data should be on disk now. */ result |= test_file (buf, sizeof (buf), fd, "aio_fsync (aio_write)"); /* Test aio_cancel. */ /* Remove the test file contents first. */ if (ftruncate (fd, 0) < 0) { error (0, errno, "ftruncate failed\n"); result = 1; } /* Write again. */ for (cnt = 10; cnt > 0; ) aio_write (cbp[--cnt]); /* Cancel all requests. */ if (aio_cancel (fd, NULL) == -1) printf ("aio_cancel (fd, NULL) cannot cancel anything\n"); result |= do_wait (cbp, 10, ECANCELED); /* Another test for aio_cancel. */ /* Remove the test file contents first. */ if (ftruncate (fd, 0) < 0) { error (0, errno, "ftruncate failed\n"); result = 1; } /* Write again. */ for (cnt = 10; cnt > 0; ) { --cnt; cbp[cnt] = &cbs[cnt]; aio_write (cbp[cnt]); } puts ("finished3"); /* Cancel all requests. */ for (cnt = 10; cnt > 0; ) if (aio_cancel (fd, cbp[--cnt]) == -1) /* This is not an error. The request can simply be finished. */ printf ("aio_cancel (fd, cbp[%Zd]) cannot be canceled\n", cnt); puts ("finished2"); result |= do_wait (cbp, 10, ECANCELED); puts ("finished"); return result; }
static int do_test (int argc, char *argv[]) { char name[] = "/tmp/aio3.XXXXXX"; int fd; struct aiocb *arr[1]; struct aiocb cb; static const char buf[] = "Hello World\n"; fd = mkstemp (name); if (fd == -1) { printf ("cannot open temp name: %m\n"); return 1; } unlink (name); if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("barrier_init failed"); return 1; } arr[0] = &cb; cb.aio_fildes = fd; cb.aio_lio_opcode = LIO_WRITE; cb.aio_reqprio = 0; cb.aio_buf = (void *) buf; cb.aio_nbytes = sizeof (buf) - 1; cb.aio_offset = 0; cb.aio_sigevent.sigev_notify = SIGEV_THREAD; cb.aio_sigevent.sigev_notify_function = thrfct; cb.aio_sigevent.sigev_notify_attributes = NULL; cb.aio_sigevent.sigev_value.sival_ptr = NULL; if (lio_listio (LIO_NOWAIT, arr, 1, NULL) < 0) { if (errno == ENOSYS) { puts ("no aio support in this configuration"); return 0; } printf ("lio_listio failed: %m\n"); return 1; } if (aio_suspend ((const struct aiocb *const *) arr, 1, NULL) < 0) { printf ("aio_suspend failed: %m\n"); return 1; } int e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("parent: barrier_wait failed"); return 1; } puts ("all OK"); return 0; }
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs) { int rc = VINF_SUCCESS; PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx; /* Parameter checks */ AssertPtrReturn(pCtxInt, VERR_INVALID_HANDLE); AssertReturn(cReqs != 0, VERR_INVALID_POINTER); AssertPtrReturn(pahReqs, VERR_INVALID_PARAMETER); rtFileAioCtxDump(pCtxInt); /* Check that we don't exceed the limit */ if (ASMAtomicUoReadS32(&pCtxInt->cRequests) + cReqs > pCtxInt->cMaxRequests) return VERR_FILE_AIO_LIMIT_EXCEEDED; PRTFILEAIOREQINTERNAL pHead = NULL; do { int rcPosix = 0; size_t cReqsSubmit = 0; size_t i = 0; PRTFILEAIOREQINTERNAL pReqInt; while ( (i < cReqs) && (i < AIO_LISTIO_MAX)) { pReqInt = pahReqs[i]; if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt)) { /* Undo everything and stop submitting. */ for (size_t iUndo = 0; iUndo < i; iUndo++) { pReqInt = pahReqs[iUndo]; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; /* Unlink from the list again. */ PRTFILEAIOREQINTERNAL pNext, pPrev; pNext = pReqInt->pNext; pPrev = pReqInt->pPrev; if (pNext) pNext->pPrev = pPrev; if (pPrev) pPrev->pNext = pNext; else pHead = pNext; } rc = VERR_INVALID_HANDLE; break; } pReqInt->pCtxInt = pCtxInt; if (pReqInt->fFlush) break; /* Link them together. */ pReqInt->pNext = pHead; if (pHead) pHead->pPrev = pReqInt; pReqInt->pPrev = NULL; pHead = pReqInt; RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED); cReqsSubmit++; i++; } if (cReqsSubmit) { rcPosix = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL); if (RT_UNLIKELY(rcPosix < 0)) { size_t cReqsSubmitted = cReqsSubmit; if (errno == EAGAIN) rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; else rc = RTErrConvertFromErrno(errno); /* Check which ones were not submitted. */ for (i = 0; i < cReqsSubmit; i++) { pReqInt = pahReqs[i]; rcPosix = aio_error(&pReqInt->AioCB); if ((rcPosix != EINPROGRESS) && (rcPosix != 0)) { cReqsSubmitted--; #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) if (errno == EINVAL) #else if (rcPosix == EINVAL) #endif { /* Was not submitted. */ RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); } else { /* An error occurred. */ RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); /* * Looks like Apple and glibc interpret the standard in different ways. * glibc returns the error code which would be in errno but Apple returns * -1 and sets errno to the appropriate value */ #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) Assert(rcPosix == -1); pReqInt->Rc = RTErrConvertFromErrno(errno); #elif defined(RT_OS_LINUX) pReqInt->Rc = RTErrConvertFromErrno(rcPosix); #endif pReqInt->cbTransfered = 0; } /* Unlink from the list. */ PRTFILEAIOREQINTERNAL pNext, pPrev; pNext = pReqInt->pNext; pPrev = pReqInt->pPrev; if (pNext) pNext->pPrev = pPrev; if (pPrev) pPrev->pNext = pNext; else pHead = pNext; pReqInt->pNext = NULL; pReqInt->pPrev = NULL; } } ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmitted); AssertMsg(pCtxInt->cRequests >= 0, ("Adding requests resulted in overflow\n")); break; } ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit); AssertMsg(pCtxInt->cRequests >= 0, ("Adding requests resulted in overflow\n")); cReqs -= cReqsSubmit; pahReqs += cReqsSubmit; } /* * Check if we have a flush request now. * If not we hit the AIO_LISTIO_MAX limit * and will continue submitting requests * above. */ if (cReqs && RT_SUCCESS_NP(rc)) { pReqInt = pahReqs[0]; if (pReqInt->fFlush) { /* * lio_listio does not work with flush requests so * we have to use aio_fsync directly. */ rcPosix = aio_fsync(O_SYNC, &pReqInt->AioCB); if (RT_UNLIKELY(rcPosix < 0)) { if (errno == EAGAIN) { rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); } else { rc = RTErrConvertFromErrno(errno); RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); pReqInt->Rc = rc; } pReqInt->cbTransfered = 0; break; } /* Link them together. */ pReqInt->pNext = pHead; if (pHead) pHead->pPrev = pReqInt; pReqInt->pPrev = NULL; pHead = pReqInt; RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED); ASMAtomicIncS32(&pCtxInt->cRequests); AssertMsg(pCtxInt->cRequests >= 0, ("Adding requests resulted in overflow\n")); cReqs--; pahReqs++; } } } while ( cReqs && RT_SUCCESS_NP(rc)); if (pHead) { /* * Forward successfully submitted requests to the thread waiting for requests. * We search for a free slot first and if we don't find one * we will grab the first one and append our list to the existing entries. */ unsigned iSlot = 0; while ( (iSlot < RT_ELEMENTS(pCtxInt->apReqsNewHead)) && !ASMAtomicCmpXchgPtr(&pCtxInt->apReqsNewHead[iSlot], pHead, NULL)) iSlot++; if (iSlot == RT_ELEMENTS(pCtxInt->apReqsNewHead)) { /* Nothing found. */ PRTFILEAIOREQINTERNAL pOldHead = ASMAtomicXchgPtrT(&pCtxInt->apReqsNewHead[0], NULL, PRTFILEAIOREQINTERNAL); /* Find the end of the current head and link the old list to the current. */ PRTFILEAIOREQINTERNAL pTail = pHead; while (pTail->pNext) pTail = pTail->pNext; pTail->pNext = pOldHead; ASMAtomicWritePtr(&pCtxInt->apReqsNewHead[0], pHead); } /* Set the internal wakeup flag and wakeup the thread if possible. */ bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUpInternal, true); if (!fWokenUp) rtFileAioCtxWakeup(pCtxInt); } rtFileAioCtxDump(pCtxInt); return rc; }
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs) { /* * Parameter validation. */ int rc = VINF_SUCCESS; PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx; RTFILEAIOCTX_VALID_RETURN(pCtxInt); AssertReturn(cReqs > 0, VERR_INVALID_PARAMETER); AssertPtrReturn(pahReqs, VERR_INVALID_POINTER); do { int rcBSD = 0; size_t cReqsSubmit = 0; size_t i = 0; PRTFILEAIOREQINTERNAL pReqInt; while ( (i < cReqs) && (i < AIO_LISTIO_MAX)) { pReqInt = pahReqs[i]; if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt)) { /* Undo everything and stop submitting. */ for (size_t iUndo = 0; iUndo < i; iUndo++) { pReqInt = pahReqs[iUndo]; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = 0; } rc = VERR_INVALID_HANDLE; break; } pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = pCtxInt->iKQueue; pReqInt->pCtxInt = pCtxInt; RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED); if (pReqInt->fFlush) break; cReqsSubmit++; i++; } if (cReqsSubmit) { rcBSD = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL); if (RT_UNLIKELY(rcBSD < 0)) { if (errno == EAGAIN) rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; else rc = RTErrConvertFromErrno(errno); /* Check which requests got actually submitted and which not. */ for (i = 0; i < cReqs; i++) { pReqInt = pahReqs[i]; rcBSD = aio_error(&pReqInt->AioCB); if ( rcBSD == -1 && errno == EINVAL) { /* Was not submitted. */ RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; } else if (rcBSD != EINPROGRESS) { /* The request encountered an error. */ RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); pReqInt->Rc = RTErrConvertFromErrno(rcBSD); pReqInt->pCtxInt = NULL; pReqInt->cbTransfered = 0; } } break; } ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit); cReqs -= cReqsSubmit; pahReqs += cReqsSubmit; } /* Check if we have a flush request now. */ if (cReqs && RT_SUCCESS_NP(rc)) { pReqInt = pahReqs[0]; RTFILEAIOREQ_VALID_RETURN(pReqInt); if (pReqInt->fFlush) { /* * lio_listio does not work with flush requests so * we have to use aio_fsync directly. */ rcBSD = aio_fsync(O_SYNC, &pReqInt->AioCB); if (RT_UNLIKELY(rcBSD < 0)) { if (rcBSD == EAGAIN) { /* Was not submitted. */ RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; return VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; } else { RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); pReqInt->Rc = RTErrConvertFromErrno(errno); pReqInt->cbTransfered = 0; return pReqInt->Rc; } } ASMAtomicIncS32(&pCtxInt->cRequests); cReqs--; pahReqs++; } } } while (cReqs); return rc; }
void *POSIX_Init( void *argument ) { int sc; TEST_BEGIN(); puts( "lio_listio -- ENOSYS" ); sc = lio_listio( 0, NULL, 0, NULL ); check_enosys( sc ); puts( "aio_suspend -- ENOSYS" ); sc = aio_suspend( NULL, 0, NULL ); check_enosys( sc ); puts( "clock_getcpuclockid -- ENOSYS" ); sc = clock_getcpuclockid( 0, NULL ); check_enosys( sc ); puts( "clock_getenable_attr -- ENOSYS" ); sc = clock_getenable_attr( 0, NULL ); check_enosys( sc ); puts( "clock_setenable_attr -- ENOSYS" ); sc = clock_setenable_attr( 0, 0 ); check_enosys( sc ); puts( "execl -- ENOSYS" ); sc = execl( NULL, NULL, (char*)0 ); check_enosys( sc ); puts( "execle -- ENOSYS" ); sc = execle( NULL, NULL, (char*)0, NULL ); check_enosys( sc ); puts( "execlp -- ENOSYS" ); sc = execlp( NULL, NULL, (char*)0 ); check_enosys( sc ); puts( "execv -- ENOSYS" ); sc = execv( NULL, NULL ); check_enosys( sc ); puts( "execve -- ENOSYS" ); sc = execve( NULL, NULL, NULL ); check_enosys( sc ); puts( "execvp -- ENOSYS" ); sc = execvp( NULL, NULL ); check_enosys( sc ); puts( "fork -- ENOSYS" ); sc = fork(); check_enosys( sc ); puts( "pthread_atfork -- ENOSYS" ); sc = pthread_atfork( NULL, NULL, NULL ); check_enosys( sc ); puts( "pthread_getcpuclockid -- ENOSYS" ); sc = pthread_getcpuclockid( 0, NULL ); check_enosys( sc ); puts( "sched_setparam -- ENOSYS" ); sc = sched_setparam( 0, NULL ); check_enosys( sc ); puts( "sched_getparam -- ENOSYS" ); sc = sched_getparam( 0, NULL ); check_enosys( sc ); puts( "sched_setscheduler -- ENOSYS" ); sc = sched_setscheduler( 0, 0, NULL ); check_enosys( sc ); puts( "sched_getscheduler -- ENOSYS" ); sc = sched_getscheduler( 0 ); check_enosys( sc ); puts( "wait -- ENOSYS" ); sc = wait( NULL ); check_enosys( sc ); puts( "waitpid -- ENOSYS" ); sc = waitpid( 0, NULL, 0 ); check_enosys( sc ); puts( "mprotect -- stub implementation - OK" ); sc = mprotect( NULL, 0, 0 ); posix_service_failed( sc, "mprotect" ); puts( "vfork -- stub implementation - OK" ); sc = vfork(); if ( sc != -1 ) { puts( "vfork did not return -1" ); rtems_test_exit( 0 ); } TEST_END(); rtems_test_exit( 0 ); return NULL; /* just so the compiler thinks we returned something */ }
int main(void) { char tmpfname[256]; int fd; struct aiocb **aiocbs; struct aiocb *plist[2]; char *bufs; struct sigaction action; struct sigevent event; struct timespec ts = {0, 1000}; /* 10 ms */ int errors = 0; int ret; int err; int i; if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) return PTS_UNSUPPORTED; snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_aio_suspend_7_1_%d", getpid()); unlink(tmpfname); fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { printf(TNAME " Error at open(): %s\n", strerror(errno)); exit(PTS_UNRESOLVED); } unlink(tmpfname); bufs = malloc(NUM_AIOCBS*BUF_SIZE); if (bufs == NULL) { printf(TNAME " Error at malloc(): %s\n", strerror(errno)); close(fd); exit(PTS_UNRESOLVED); } if (write (fd, bufs, NUM_AIOCBS*BUF_SIZE) != (NUM_AIOCBS*BUF_SIZE)) { printf(TNAME " Error at write(): %s\n", strerror(errno)); free(bufs); close(fd); exit(PTS_UNRESOLVED); } aiocbs = malloc(sizeof(struct aiocb *) * NUM_AIOCBS); /* Queue up a bunch of aio reads */ for (i = 0; i < NUM_AIOCBS; i++) { aiocbs[i] = (struct aiocb*)malloc(sizeof(struct aiocb)); memset(aiocbs[i], 0, sizeof(struct aiocb)); aiocbs[i]->aio_fildes = fd; aiocbs[i]->aio_offset = i * BUF_SIZE; aiocbs[i]->aio_buf = &bufs[i*BUF_SIZE]; aiocbs[i]->aio_nbytes = BUF_SIZE; aiocbs[i]->aio_lio_opcode = LIO_READ; } /* Use SIGRTMIN + 1 for list completion */ event.sigev_notify = SIGEV_SIGNAL; event.sigev_signo = SIGRTMIN + 1; event.sigev_value.sival_ptr = NULL; /* Setup handler for list completion */ action.sa_sigaction = sigrt1_handler; sigemptyset(&action.sa_mask); action.sa_flags = SA_SIGINFO|SA_RESTART; sigaction(SIGRTMIN + 1, &action, NULL); /* Setup suspend list */ plist[0] = NULL; plist[1] = aiocbs[WAIT_FOR_AIOCB]; /* Submit request list */ ret = lio_listio(LIO_NOWAIT, aiocbs, NUM_AIOCBS, &event); if (ret) { printf(TNAME " Error at lio_listio() %d: %s\n", errno, strerror(errno)); for (i=0; i<NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); free(aiocbs); close(fd); exit(PTS_UNRESOLVED); } /* Check selected request has not completed yet */ if (aio_error(aiocbs[WAIT_FOR_AIOCB]) != EINPROGRESS) { printf(TNAME " Error : AIOCB %d already completed before suspend\n", WAIT_FOR_AIOCB); for (i=0; i<NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); free(aiocbs); close(fd); exit(PTS_FAIL); } /* Suspend on selected request */ ret = aio_suspend((const struct aiocb **)plist, 2, &ts); /* Check selected request has not completed */ if (aio_error(aiocbs[WAIT_FOR_AIOCB]) != EINPROGRESS) { printf(TNAME " Error : AIOCB %d should not have completed after timed out suspend\n", WAIT_FOR_AIOCB); for (i=0; i<NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); free(aiocbs); close(fd); exit(PTS_FAIL); } /* timed out aio_suspend should return -1 and set errno to EAGAIN */ if (ret != -1) { printf(TNAME " aio_suspend() should return -1\n"); for (i=0; i<NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); free(aiocbs); close(fd); exit(PTS_FAIL); } if (errno != EAGAIN) { printf(TNAME " aio_suspend() should set errno to EAGAIN: %d (%s)\n", errno, strerror(errno)); for (i=0; i<NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); free(aiocbs); close(fd); exit(PTS_FAIL); } /* Wait for list processing completion */ while (!received_all) sleep(1); /* Check return code and free things */ for (i = 0; i < NUM_AIOCBS; i++) { err = aio_error(aiocbs[i]); ret = aio_return(aiocbs[i]); if ((err != 0) && (ret != BUF_SIZE)) { printf(TNAME " req %d: error = %d - return = %d\n", i, err, ret); errors++; } free(aiocbs[i]); } free(bufs); free(aiocbs); close(fd); if (errors != 0) exit(PTS_FAIL); printf(TNAME " PASSED\n"); return PTS_PASS; }
static int do_test (int argc, char *argv[]) { char name[] = "/tmp/aio4.XXXXXX"; int fd; struct aiocb *arr[1]; struct aiocb cb; static const char buf[] = "Hello World\n"; struct aioinit init = {10, 20, 0}; struct sigaction sa; struct sigevent ev; if (SIGRTMIN == -1) { printf ("RT signals not supported.\n"); return 0; } /* Select a signal from the middle of the available choices... */ my_signo = (SIGRTMAX + SIGRTMIN) / 2; fd = mkstemp (name); if (fd == -1) { printf ("cannot open temp name: %m\n"); return 1; } unlink (name); /* Test also aio_init. */ aio_init (&init); arr[0] = &cb; cb.aio_fildes = fd; cb.aio_lio_opcode = LIO_WRITE; cb.aio_reqprio = 0; cb.aio_buf = (void *) buf; cb.aio_nbytes = sizeof (buf) - 1; cb.aio_offset = 0; cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; cb.aio_sigevent.sigev_notify_function = NULL; cb.aio_sigevent.sigev_notify_attributes = NULL; cb.aio_sigevent.sigev_signo = my_signo; cb.aio_sigevent.sigev_value.sival_ptr = NULL; ev.sigev_notify = SIGEV_SIGNAL; ev.sigev_notify_function = NULL; ev.sigev_notify_attributes = NULL; ev.sigev_signo = my_signo; sa.sa_handler = sighandler; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction (my_signo, &sa, NULL) < 0) { printf ("sigaction failed: %m\n"); return 1; } flag = 0; /* First use aio_write. */ if (aio_write (arr[0]) < 0) { if (errno == ENOSYS) { puts ("no aio support in this configuration"); return 0; } printf ("aio_write failed: %m\n"); return 1; } if (wait_flag ()) return 1; puts ("aio_write OK"); flag = 0; /* Again with lio_listio. */ if (lio_listio (LIO_NOWAIT, arr, 1, &ev) < 0) { printf ("lio_listio failed: %m\n"); return 1; } if (wait_flag ()) return 1; puts ("all OK"); return 0; }
static int do_test (int argc, char *argv[]) { char name[] = "/tmp/aio2.XXXXXX"; int fd; struct aiocb *arr[1]; struct aiocb cb; static const char buf[] = "Hello World\n"; fd = mkstemp (name); if (fd == -1) { printf ("cannot open temp name: %m\n"); return 1; } unlink (name); if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("barrier_init failed"); return 1; } arr[0] = &cb; void *p; int sz = set_o_direct (fd); if (sz != -1) { int err = posix_memalign (&p, sz, sz); if (err) { errno = err; printf ("cannot allocate memory: %m\n"); return 1; } memcpy (p, buf, sizeof (buf) - 1); memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1); printf ("Using O_DIRECT with block size %d\n", sz); } else { p = (void *) buf; sz = sizeof (buf) - 1; } cb.aio_fildes = fd; cb.aio_lio_opcode = LIO_WRITE; cb.aio_reqprio = 0; cb.aio_buf = p; cb.aio_nbytes = sz; cb.aio_offset = 0; cb.aio_sigevent.sigev_notify = SIGEV_THREAD; cb.aio_sigevent.sigev_notify_function = thrfct; cb.aio_sigevent.sigev_notify_attributes = NULL; cb.aio_sigevent.sigev_value.sival_ptr = NULL; if (lio_listio (LIO_WAIT, arr, 1, NULL) < 0) { if (errno == ENOSYS) { puts ("no aio support in this configuration"); return 0; } printf ("lio_listio failed: %m\n"); return 1; } puts ("lio_listio returned"); int e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("barrier_wait failed"); return 1; } puts ("all OK"); return 0; }
int main(){ struct aiocb a_write, a_read; struct aiocb *cblist[MAX]; int err_r, err_w; int read_n = 0; int read_fd,write_fd; char read_buf[BUFFER_SIZE]; char write_buf[BUFFER_SIZE]; /* Open Read.txt file for reading */ read_fd = open("Read.txt", O_RDONLY); /* Open Write.txt file for writing */ write_fd = open("Write.txt", O_CREAT | O_WRONLY, 0644); /* Its good practice to clear the aiocbs before * using them */ memset(&a_write, 0 , sizeof(struct aiocb)); memset(&a_read, 0 , sizeof(struct aiocb)); /* populate aiocbs to defaults */ populate_aiocb(&a_read, read_fd, 0, BUFFER_SIZE-1, read_buf,LIO_READ); populate_aiocb(&a_write, write_fd, 0, BUFFER_SIZE-1, write_buf,LIO_WRITE); /* Start async read. The function will read a_read.aio_nbytes bytes * from file a_read.aio_fildes starting from a_read.aio_offset into * buffer a_read.aio_buf. On success 0 is returned. This function will * return immediately after queueing the request */ cblist[0] = &a_read; cblist[1] = &a_write; while(1) { //aio_read(&a_read); lio_listio(LIO_NOWAIT, cblist, 2, NULL); /* After starting any async operation (read or write), you can get its status * using aio_error function. This function returns EINPROGRESS if the request has not been completed * It returns ECANCELED if the request was cancelled.It returns 0 * if the request completed successfully. Otherwise an error value is returned */ if((err_r = aio_error(&a_read)) == EINPROGRESS || (err_w = aio_error(&a_write)) == EINPROGRESS){ cblist[0] = &a_read; cblist[1] = &a_write; aio_suspend(cblist, 2, NULL); } /* aio_error returns 0 that is success. Call aio_return to find of number of * bytes read. The function should be called only once after aio_error returns * something other than EINPROGRESS. */ read_n = aio_return(&a_read); strcpy(write_buf,read_buf); /* Setup write control block. Call aio_write to queue write request. The function * will write a_write.aio_nbytes bytes from buffer a_write.aio_buf to file a_write.aio_fildes * at offset a_write.aio_offset. Returns 0 on success */ a_write.aio_nbytes = read_n; aio_write(&a_write); if(read_n!=BUFFER_SIZE-1) break; else { /* update read & write offset */ a_read.aio_offset += read_n; a_write.aio_offset += aio_return(&a_write); } } close(read_fd); close(write_fd); }
int main() { char tmpfname[256]; int fd; struct aiocb *aiocbs[NUM_AIOCBS]; char *bufs; int errors = 0; int ret; int err; int i; if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) exit(PTS_UNSUPPORTED); snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_lio_listio_12_1_%d", getpid()); unlink(tmpfname); fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { printf(TNAME " Error at open(): %s\n", strerror(errno)); exit(PTS_UNRESOLVED); } unlink(tmpfname); bufs = (char *)malloc(NUM_AIOCBS * BUF_SIZE); if (bufs == NULL) { printf(TNAME " Error at malloc(): %s\n", strerror(errno)); close(fd); exit(PTS_UNRESOLVED); } /* Queue up a bunch of aio writes */ for (i = 0; i < NUM_AIOCBS; i++) { aiocbs[i] = (struct aiocb *)malloc(sizeof(struct aiocb)); memset(aiocbs[i], 0, sizeof(struct aiocb)); aiocbs[i]->aio_fildes = fd; aiocbs[i]->aio_offset = 0; aiocbs[i]->aio_buf = &bufs[i * BUF_SIZE]; aiocbs[i]->aio_nbytes = BUF_SIZE; aiocbs[i]->aio_lio_opcode = LIO_WRITE; } /* Submit request list */ ret = lio_listio(LIO_WAIT, aiocbs, NUM_AIOCBS, NULL); if (ret) { printf(TNAME " Error at lio_listio() %d: %s\n", errno, strerror(errno)); for (i = 0; i < NUM_AIOCBS; i++) free(aiocbs[i]); free(bufs); close(fd); exit(PTS_FAIL); } /* Check return code and free things */ for (i = 0; i < NUM_AIOCBS; i++) { err = aio_error(aiocbs[i]); ret = aio_return(aiocbs[i]); if ((err != 0) && (ret != BUF_SIZE)) { printf(TNAME " req %d: error = %d - return = %d\n", i, err, ret); errors++; } free(aiocbs[i]); } free(bufs); close(fd); if (errors != 0) exit(PTS_FAIL); printf(TNAME " PASSED\n"); return PTS_PASS; }
int main() { char tmpfname[256]; int fd; struct aiocb *aiocbs[NUM_AIOCBS]; char *bufs; struct sigaction action; struct sigevent event; int errors = 0; int ret; int err; int i; if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) exit(PTS_UNSUPPORTED); snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_lio_listio_2_1_%d", getpid()); unlink(tmpfname); fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { printf(TNAME " Error at open(): %s\n", strerror(errno)); exit(PTS_UNRESOLVED); } unlink(tmpfname); bufs = (char *) malloc (NUM_AIOCBS*BUF_SIZE); if (bufs == NULL) { printf (TNAME " Error at malloc(): %s\n", strerror (errno)); close (fd); exit(PTS_UNRESOLVED); } /* Queue up a bunch of aio writes */ for (i = 0; i < NUM_AIOCBS; i++) { aiocbs[i] = (struct aiocb *)malloc(sizeof(struct aiocb)); memset(aiocbs[i], 0, sizeof(struct aiocb)); aiocbs[i]->aio_fildes = fd; aiocbs[i]->aio_offset = 0; aiocbs[i]->aio_buf = &bufs[i*BUF_SIZE]; aiocbs[i]->aio_nbytes = BUF_SIZE; aiocbs[i]->aio_lio_opcode = LIO_WRITE; /* Use SIRTMIN+1 for individual completions */ aiocbs[i]->aio_sigevent.sigev_notify = SIGEV_SIGNAL; aiocbs[i]->aio_sigevent.sigev_signo = SIGRTMIN+1; aiocbs[i]->aio_sigevent.sigev_value.sival_int = i; } /* Use SIGRTMIN+2 for list completion */ event.sigev_notify = SIGEV_SIGNAL; event.sigev_signo = SIGRTMIN+2; event.sigev_value.sival_ptr = NULL; /* Setup handler for individual operation completion */ action.sa_sigaction = sigrt1_handler; sigemptyset(&action.sa_mask); action.sa_flags = SA_SIGINFO|SA_RESTART; sigaction(SIGRTMIN+1, &action, NULL); /* Setup handler for list completion */ action.sa_sigaction = sigrt2_handler; sigemptyset(&action.sa_mask); action.sa_flags = SA_SIGINFO|SA_RESTART; sigaction(SIGRTMIN+2, &action, NULL); /* Submit request list */ ret = lio_listio(LIO_NOWAIT, aiocbs, NUM_AIOCBS, &event); if (ret) { printf(TNAME " Error at lio_listio() %d: %s\n", errno, strerror(errno)); for (i=0; i<NUM_AIOCBS; i++) free (aiocbs[i]); free (bufs); close (fd); exit (PTS_FAIL); } if (received_selected == NUM_AIOCBS-1) { printf(TNAME " lio_listio() waited\n"); for (i=0; i<NUM_AIOCBS; i++) free (aiocbs[i]); free (bufs); close (fd); exit (PTS_FAIL); } if (received_all != 0) { printf(TNAME " Error lio_listio() waited for list completion\n"); for (i=0; i<NUM_AIOCBS; i++) free (aiocbs[i]); free (bufs); close (fd); exit (PTS_FAIL); } while (received_all == 0) sleep (1); /* Check return code and free things */ for (i = 0; i < NUM_AIOCBS; i++) { err = aio_error(aiocbs[i]); ret = aio_return(aiocbs[i]); if ((err != 0) && (ret != BUF_SIZE)) { printf(TNAME " req %d: error = %d - return = %d\n", i, err, ret); errors++; } free (aiocbs[i]); } free (bufs); close(fd); if (errors != 0) exit (PTS_FAIL); printf (TNAME " PASSED\n"); return PTS_PASS; }
int main(void) { char tmpfname[256]; int fd; struct aiocb *aiocbs[NUM_AIOCBS]; char *bufs; int ret; if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) exit(PTS_UNSUPPORTED); snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_lio_listio_18_1_%d", getpid()); unlink(tmpfname); fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { printf(TNAME " Error at open(): %s\n", strerror(errno)); exit(PTS_UNRESOLVED); } unlink(tmpfname); bufs = malloc(NUM_AIOCBS * BUF_SIZE); if (bufs == NULL) { printf(TNAME " Error at malloc(): %s\n", strerror(errno)); close(fd); exit(PTS_UNRESOLVED); } aiocbs[0] = malloc(sizeof(struct aiocb)); memset(aiocbs[0], 0, sizeof(struct aiocb)); aiocbs[0]->aio_fildes = fd; aiocbs[0]->aio_offset = 0; aiocbs[0]->aio_buf = bufs; aiocbs[0]->aio_nbytes = BUF_SIZE; aiocbs[0]->aio_lio_opcode = LIO_WRITE; /* Submit request list */ ret = lio_listio(-1, aiocbs, NUM_AIOCBS, NULL); if (ret != -1) { printf(TNAME " Error lio_listio() should have returned -1: %d\n", ret); free(aiocbs[0]); free(bufs); close(fd); exit(PTS_FAIL); } if (errno != EINVAL) { printf(TNAME " Error lio_listio() should have set errno to EINVAL: %d (%s)\n", errno, strerror(errno)); free(aiocbs[0]); free(bufs); close(fd); exit(PTS_FAIL); } free(aiocbs[0]); free(bufs); close(fd); printf(TNAME " PASSED\n"); return PTS_PASS; }
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs) { /* * Parameter validation. */ int rc = VINF_SUCCESS; PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx; RTFILEAIOCTX_VALID_RETURN(pCtxInt); AssertReturn(cReqs > 0, VERR_INVALID_PARAMETER); AssertPtrReturn(pahReqs, VERR_INVALID_POINTER); size_t i = cReqs; do { int rcSol = 0; size_t cReqsSubmit = 0; PRTFILEAIOREQINTERNAL pReqInt; while(i-- > 0) { pReqInt = pahReqs[i]; if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt)) { /* Undo everything and stop submitting. */ for (size_t iUndo = 0; iUndo < i; iUndo++) { pReqInt = pahReqs[iUndo]; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; } rc = VERR_INVALID_HANDLE; break; } pReqInt->PortNotifier.portnfy_port = pCtxInt->iPort; pReqInt->pCtxInt = pCtxInt; RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED); if (pReqInt->fFlush) break; cReqsSubmit++; } if (cReqsSubmit) { rcSol = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL); if (RT_UNLIKELY(rcSol < 0)) { if (rcSol == EAGAIN) rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; else rc = RTErrConvertFromErrno(errno); /* Check which requests got actually submitted and which not. */ for (i = 0; i < cReqs; i++) { pReqInt = pahReqs[i]; rcSol = aio_error(&pReqInt->AioCB); if (rcSol == EINVAL) { /* Was not submitted. */ RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; } else if (rcSol != EINPROGRESS) { /* The request encountered an error. */ RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); } } break; } ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit); cReqs -= cReqsSubmit; pahReqs += cReqsSubmit; } if (cReqs) { pReqInt = pahReqs[0]; RTFILEAIOREQ_VALID_RETURN(pReqInt); /* * If there are still requests left we have a flush request. * lio_listio does not work with this requests so * we have to use aio_fsync directly. */ rcSol = aio_fsync(O_SYNC, &pReqInt->AioCB); if (RT_UNLIKELY(rcSol < 0)) { RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); rc = RTErrConvertFromErrno(errno); break; } ASMAtomicIncS32(&pCtxInt->cRequests); cReqs--; pahReqs++; } } while (cReqs); return rc; }
int main(int argc, char *argv[]) { if (argc != 3) { printf("error syntaxe :%s source.txt dest.txt \n", argv[0]); exit(EXIT_FAILURE); } const char* source_file = argv[1]; const char* dest_file = argv[2]; int desc_source; int desc_dest; struct aiocb cb_ecr[BUF_SIZE]; /** bloc controle IO **/ struct aiocb * lio[BUF_SIZE]; /** liste des opérations IO à lancer **/ struct sigevent lio_sigev; /** événement à déclancher à la fin de toutes les opérations**/ char buffer[BUF_SIZE] = { 0 }; /** ouverture des fichiers **/ if ((desc_source = open(source_file, O_RDONLY | 0666)) < 0) { perror("open source_file"); exit(EXIT_FAILURE); } if ((desc_dest = open(dest_file, O_CREAT | O_RDWR | O_TRUNC, 0666)) < 0) { perror("open dest_file"); exit(EXIT_FAILURE); } int i; for (i = 0; i < BUF_SIZE; ++i) { /** init l'ecriture **/ cb_ecr[i].aio_fildes = desc_dest; cb_ecr[i].aio_lio_opcode = LIO_WRITE; cb_ecr[i].aio_nbytes = 1; cb_ecr[i].aio_reqprio = 0; cb_ecr[i].aio_sigevent.sigev_notify = SIGEV_NONE; } /** événement à déclancher à la fin de toutes les opérations**/ lio_sigev.sigev_notify = SIGEV_NONE; long int octet_lus = 0; int nb_tour = 0; while ((octet_lus = read(desc_source, buffer, BUF_SIZE)) > 0) { printf("buffer lu %ld \n", octet_lus); for (i = 0; i < octet_lus; ++i) { printf("%c \n", buffer[octet_lus - i - 1]); cb_ecr[i].aio_buf = &buffer[octet_lus - i - 1]; cb_ecr[i].aio_offset = nb_tour * BUF_SIZE + i; lio[i] = &cb_ecr[i]; } /*** lancer une suite d'AIOs ***/ if (lio_listio(LIO_WAIT, lio, octet_lus, &lio_sigev) < 0) { perror("lio_listio"); exit(EXIT_FAILURE); } nb_tour++; } /**Fermeture des desc **/ close(desc_source); close(desc_dest); return EXIT_SUCCESS; }