From 4e8a3561652ebcda6a126b3162fc545573889dc4 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Fri, 13 Feb 2015 00:27:45 -0500 Subject: overhaul aio implementation for correctness previously, aio operations were not tracked by file descriptor; each operation was completely independent. this resulted in non-conforming behavior for non-seekable/append-mode writes (which are required to be ordered) and made it impossible to implement aio_cancel, which in turn made closing file descriptors with outstanding aio operations unsafe. the new implementation is significantly heavier (roughly twice the size, and seems to be slightly slower) and presently aims mainly at correctness, not performance. most of the public interfaces have been moved into a single file, aio.c, because there is little benefit to be had from splitting them. whenever any aio functions are used, aio_cancel and the internal queue lifetime management and fd-to-queue mapping code must be linked, and these functions make up the bulk of the code size. the close function's interaction with aio is implemented with weak alias magic, to avoid pulling in heavy aio cancellation code in programs that don't use aio, and the expensive cancellation path (which includes signal blocking) is optimized out when there are no active aio queues. --- src/aio/aio_readwrite.c | 110 ------------------------------------------------ 1 file changed, 110 deletions(-) delete mode 100644 src/aio/aio_readwrite.c (limited to 'src/aio/aio_readwrite.c') diff --git a/src/aio/aio_readwrite.c b/src/aio/aio_readwrite.c deleted file mode 100644 index 8753ffda..00000000 --- a/src/aio/aio_readwrite.c +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include -#include -#include "pthread_impl.h" -#include "libc.h" - -static void dummy(void) -{ -} - -weak_alias(dummy, __aio_wake); - -static void notify_signal(struct sigevent *sev) -{ - siginfo_t si = { - .si_signo = sev->sigev_signo, - .si_value = sev->sigev_value, - .si_code = SI_ASYNCIO, - .si_pid = getpid(), - .si_uid = getuid() - }; - __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); -} - -static void *io_thread(void *p) -{ - struct aiocb *cb = p; - int fd = cb->aio_fildes; - void *buf = (void *)cb->aio_buf; - size_t len = cb->aio_nbytes; - off_t off = cb->aio_offset; - int op = cb->aio_lio_opcode; - struct sigevent sev = cb->aio_sigevent; - ssize_t ret; - - if (op == LIO_WRITE) { - if ( (fcntl(fd, F_GETFL) & O_APPEND) - ||((ret = pwrite(fd, buf, len, off))<0 && errno==ESPIPE) ) - ret = write(fd, buf, len); - } else if (op == LIO_READ) { - if ( (ret = pread(fd, buf, len, off))<0 && errno==ESPIPE ) - ret = read(fd, buf, len); - } else { - ret = 0; - } - cb->__ret = ret; - - if (ret < 0) a_store(&cb->__err, errno); - else a_store(&cb->__err, 0); - - __aio_wake(); - - switch (sev.sigev_notify) { - case SIGEV_SIGNAL: - notify_signal(&sev); - break; - case SIGEV_THREAD: - sev.sigev_notify_function(sev.sigev_value); - break; - } - - return 0; -} - -static int new_req(struct aiocb *cb) -{ - int ret = 0; - pthread_attr_t a; - sigset_t set; - pthread_t td; - - if (cb->aio_sigevent.sigev_notify == SIGEV_THREAD) { - if (cb->aio_sigevent.sigev_notify_attributes) - a = *cb->aio_sigevent.sigev_notify_attributes; - else - pthread_attr_init(&a); - } else { - pthread_attr_init(&a); - pthread_attr_setstacksize(&a, PAGE_SIZE); - pthread_attr_setguardsize(&a, 0); - } - pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); - sigfillset(&set); - pthread_sigmask(SIG_BLOCK, &set, &set); - cb->__err = EINPROGRESS; - if (pthread_create(&td, &a, io_thread, cb)) { - errno = EAGAIN; - ret = -1; - } - pthread_sigmask(SIG_SETMASK, &set, 0); - cb->__td = td; - - return ret; -} - -int aio_read(struct aiocb *cb) -{ - cb->aio_lio_opcode = LIO_READ; - return new_req(cb); -} - -int aio_write(struct aiocb *cb) -{ - cb->aio_lio_opcode = LIO_WRITE; - return new_req(cb); -} - -LFS64(aio_read); -LFS64(aio_write); -- cgit v1.2.1