diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-09-09 01:07:38 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-09-09 01:07:38 -0400 |
commit | b4de6f93aed733b8fc8d103e5ced69ebe7d659e6 (patch) | |
tree | 33664a468c80b6b37a079d7d9bdbadf5adf4f93c /src/aio/aio_readwrite.c | |
parent | 96cea94ad258be262ecf15b33d13cf775e59720d (diff) | |
download | musl-b4de6f93aed733b8fc8d103e5ced69ebe7d659e6.tar.gz musl-b4de6f93aed733b8fc8d103e5ced69ebe7d659e6.tar.xz musl-b4de6f93aed733b8fc8d103e5ced69ebe7d659e6.zip |
implement POSIX asynchronous io
some features are not yet supported, and only minimal testing has been performed. should be considered experimental at this point.
Diffstat (limited to 'src/aio/aio_readwrite.c')
-rw-r--r-- | src/aio/aio_readwrite.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/aio/aio_readwrite.c b/src/aio/aio_readwrite.c new file mode 100644 index 00000000..27168f25 --- /dev/null +++ b/src/aio/aio_readwrite.c @@ -0,0 +1,104 @@ +#include <aio.h> +#include <fcntl.h> +#include "pthread_impl.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 = __pthread_self()->pid, + .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_filedes; + 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 (cb->aio_sigevent.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; +} + +ssize_t aio_read(struct aiocb *cb) +{ + cb->aio_lio_opcode = LIO_READ; + return new_req(cb); +} + +ssize_t aio_write(struct aiocb *cb) +{ + cb->aio_lio_opcode = LIO_WRITE; + return new_req(cb); +} |