#include <aio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <limits.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_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);
}