#include #include #include #include #include #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_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 (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; } 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); }