#include <atf-c.h>
#include <aio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
static int mktemp_file(char *, size_t);
static void fill_pattern(uint8_t *, size_t, uint8_t);
static void wait_all(const struct aiocb * const [], size_t);
static int
mktemp_file(char *path, size_t pathlen)
{
int fd, n;
n = snprintf(path, pathlen, "t_aio_rw.XXXXXX");
ATF_REQUIRE(n > 0 && (size_t)n < pathlen);
fd = mkstemp(path);
ATF_REQUIRE(fd >= 0);
return fd;
}
static void
fill_pattern(uint8_t *buf, size_t len, uint8_t seed)
{
size_t i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t)(seed + (i & 0xff));
}
}
static void
wait_all(const struct aiocb * const list[], size_t nent)
{
size_t i;
int pending, rv, error;
for (;;) {
pending = 0;
for (i = 0; i < nent; i++) {
if (list[i] == NULL) {
continue;
}
error = aio_error(list[i]);
if (error == EINPROGRESS) {
pending = 1;
}
}
if (!pending) {
break;
}
rv = aio_suspend(list, (int)nent, NULL);
ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s",
strerror(errno));
}
}
ATF_TC_WITHOUT_HEAD(write_then_read_back);
ATF_TC_BODY(write_then_read_back, tc)
{
char path[64];
int fd, rv;
const size_t blksz = 0x2000;
uint8_t *wbuf, *rbuf;
struct aiocb wcb, rcb;
const struct aiocb *wlist[1], *rlist[1];
fd = mktemp_file(path, sizeof(path));
wbuf = malloc(blksz);
rbuf = calloc(1, blksz);
ATF_REQUIRE(wbuf != NULL && rbuf != NULL);
fill_pattern(wbuf, blksz, 0xA0);
memset(&wcb, 0, sizeof(wcb));
wcb.aio_fildes = fd;
wcb.aio_buf = wbuf;
wcb.aio_nbytes = blksz;
wcb.aio_offset = 0;
rv = aio_write(&wcb);
ATF_REQUIRE_EQ(0, rv);
wlist[0] = &wcb;
wait_all(wlist, 1);
ATF_REQUIRE_EQ(0, aio_error(&wcb));
ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&wcb));
memset(&rcb, 0, sizeof(rcb));
rcb.aio_fildes = fd;
rcb.aio_buf = rbuf;
rcb.aio_nbytes = blksz;
rcb.aio_offset = 0;
rv = aio_read(&rcb);
ATF_REQUIRE_EQ(0, rv);
rlist[0] = &rcb;
wait_all(rlist, 1);
ATF_REQUIRE_EQ(0, aio_error(&rcb));
ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&rcb));
ATF_REQUIRE_EQ(0, memcmp(wbuf, rbuf, blksz));
rv = close(fd);
ATF_REQUIRE_EQ(0, rv);
rv = unlink(path);
ATF_REQUIRE_EQ(0, rv);
free(wbuf);
free(rbuf);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, write_then_read_back);
return atf_no_error();
}