blob: d6ca793903cc39b31908c26e8902207963239c7e [file] [log] [blame]
/*
* Copyright (c) 2004, Bull SA. All rights reserved.
* Created by: Laurent.Vivier@bull.net
* Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
*
* This file is licensed under the GPL license. For the full content
* of this license, see the COPYING file at the top level of this
* source tree.
*/
/*
* assertion:
*
* aio_suspend() shall fail if:
* [EAGAIN] No AIO indicated in the list completed before timeout
*
* method:
*
* - write to a file
* - submit a list of read requests
* - check that the selected request has not completed
* - suspend on selected request
* - check that the suspend timed out and returned EAGAIN
*
*/
#define _XOPEN_SOURCE 600
#include <sys/stat.h>
#include <aio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "posixtest.h"
#define WAIT_FOR_AIOCB 6
static sig_atomic_t received_all;
static void sigrt1_handler()
{
received_all = 1;
}
static int do_test(int num_aiocbs, size_t buf_size)
{
char tmpfname[256];
int fd;
struct aiocb *aiocbs[num_aiocbs];
struct aiocb *plist[2];
char *bufs;
struct sigaction action;
struct sigevent event;
struct timespec ts = {0, 1000000}; /* 1 ms */
int ret, ret2;
int err = PTS_UNRESOLVED;
int i;
snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_aio_suspend_9_1_%d",
getpid());
unlink(tmpfname);
fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("Error at open(): %s\n", strerror(errno));
goto err0;
}
unlink(tmpfname);
int file_size = num_aiocbs * buf_size;
bufs = malloc(file_size);
if (bufs == NULL) {
printf("Error at malloc(): %s\n", strerror(errno));
goto err1;
}
ret = write(fd, bufs, file_size);
if (ret != file_size) {
if (ret < 0)
printf("Error at write(): %s\n", strerror(errno));
else
printf("Error at write(): %i of %i written\n",
ret, file_size);
goto err2;
}
/* Queue up a bunch of aio reads */
for (i = 0; i < num_aiocbs; i++) {
aiocbs[i] = malloc(sizeof(struct aiocb));
memset(aiocbs[i], 0, sizeof(struct aiocb));
aiocbs[i]->aio_fildes = fd;
aiocbs[i]->aio_offset = i * buf_size;
aiocbs[i]->aio_buf = &bufs[i * buf_size];
aiocbs[i]->aio_nbytes = buf_size;
aiocbs[i]->aio_lio_opcode = LIO_READ;
}
/* reset the completion flag */
received_all = 0;
/* Use SIGRTMIN+1 for list completion */
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGRTMIN + 1;
event.sigev_value.sival_ptr = NULL;
action.sa_sigaction = sigrt1_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO | SA_RESTART;
sigaction(SIGRTMIN + 1, &action, NULL);
/* Setup suspend list */
plist[0] = NULL;
plist[1] = aiocbs[WAIT_FOR_AIOCB];
/* Submit request list */
ret = lio_listio(LIO_NOWAIT, aiocbs, num_aiocbs, &event);
if (ret) {
printf(" Error at lio_listio() %d: %s\n",
errno, strerror(errno));
goto err3;
}
/* Suspend on selected request */
ret = aio_suspend((const struct aiocb **)plist, 2, &ts);
/* Check selected request has not completed yet */
ret2 = aio_error(aiocbs[WAIT_FOR_AIOCB]);
if (ret2 != EINPROGRESS) {
/*
* The operation was too fast, wait for completion
* and redo it with larger buffers.
*/
err = -1;
goto err4;
}
/* timed out aio_suspend should return -1 and set errno to EAGAIN */
if (ret != -1) {
printf("aio_suspend() should return -1\n");
err = PTS_FAIL;
goto err4;
}
if (errno != EAGAIN) {
printf("aio_suspend() should set errno to EAGAIN: %d (%s)\n",
errno, strerror(errno));
err = PTS_FAIL;
goto err4;
}
/* Wait for list processing completion */
while (!received_all)
usleep(10000);
/* Check return values and errors */
err = PTS_PASS;
for (i = 0; i < num_aiocbs; i++) {
err = aio_error(aiocbs[i]);
ret = aio_return(aiocbs[i]);
if ((err != 0) && ((size_t)ret != buf_size)) {
printf("req %d: error = %d - return = %d\n",
i, err, ret);
err = PTS_FAIL;
}
}
err4:
while (!received_all)
usleep(10000);
err3:
for (i = 0; i < num_aiocbs; i++)
free(aiocbs[i]);
err2:
free(bufs);
err1:
close(fd);
err0:
return err;
}
int main(void)
{
int aio_cbs = 10;
int buf_size = 1024 * 64;
int ret;
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
/* Repeat the test with increasing buffer size */
do {
ret = do_test(aio_cbs, buf_size);
buf_size += buf_size / 4;
} while (ret == -1);
if (ret != 0)
return ret;
printf("(buf_size = %i)\nTest PASSED\n", buf_size);
return PTS_PASS;
}