Home | History | Annotate | Download | only in aio_suspend
      1 /*
      2  * Copyright (c) 2004, Bull SA. All rights reserved.
      3  *  Created by:  Laurent.Vivier (at) bull.net
      4  * Copyright (c) 2013 Cyril Hrubis <chrubis (at) suse.cz>
      5  *
      6  * This file is licensed under the GPL license.  For the full content
      7  * of this license, see the COPYING file at the top level of this
      8  * source tree.
      9  */
     10 
     11 /*
     12  * assertion:
     13  *
     14  *	aio_suspend() shall fail if:
     15  *	[EAGAIN] No AIO indicated in the list completed before timeout
     16  *
     17  * method:
     18  *
     19  *	- write to a file
     20  *	- submit a list of read requests
     21  *	- check that the selected request has not completed
     22  *	- suspend on selected request
     23  *	- check that the suspend timed out and returned EAGAIN
     24  *
     25  */
     26 
     27 #define _XOPEN_SOURCE 600
     28 #include <sys/stat.h>
     29 #include <aio.h>
     30 #include <errno.h>
     31 #include <fcntl.h>
     32 #include <signal.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <unistd.h>
     37 
     38 #include "posixtest.h"
     39 
     40 #define WAIT_FOR_AIOCB	6
     41 
     42 static sig_atomic_t received_all;
     43 
     44 static void sigrt1_handler()
     45 {
     46 	received_all = 1;
     47 }
     48 
     49 static int do_test(int num_aiocbs, size_t buf_size)
     50 {
     51 	char tmpfname[256];
     52 	int fd;
     53 	struct aiocb *aiocbs[num_aiocbs];
     54 	struct aiocb *plist[2];
     55 	char *bufs;
     56 	struct sigaction action;
     57 	struct sigevent event;
     58 	struct timespec ts = {0, 1000000};	/* 1 ms */
     59 	int ret, ret2;
     60 	int err = PTS_UNRESOLVED;
     61 	int i;
     62 
     63 	snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_aio_suspend_9_1_%d",
     64 		 getpid());
     65 	unlink(tmpfname);
     66 
     67 	fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
     68 
     69 	if (fd == -1) {
     70 		printf("Error at open(): %s\n", strerror(errno));
     71 		goto err0;
     72 	}
     73 
     74 	unlink(tmpfname);
     75 
     76 	int file_size = num_aiocbs * buf_size;
     77 
     78 	bufs = malloc(file_size);
     79 
     80 	if (bufs == NULL) {
     81 		printf("Error at malloc(): %s\n", strerror(errno));
     82 		goto err1;
     83 	}
     84 
     85 	ret = write(fd, bufs, file_size);
     86 	if (ret != file_size) {
     87 
     88 		if (ret < 0)
     89 			printf("Error at write(): %s\n", strerror(errno));
     90 		else
     91 			printf("Error at write(): %i of %i written\n",
     92 			       ret, file_size);
     93 
     94 		goto err2;
     95 	}
     96 
     97 	/* Queue up a bunch of aio reads */
     98 	for (i = 0; i < num_aiocbs; i++) {
     99 		aiocbs[i] = malloc(sizeof(struct aiocb));
    100 		memset(aiocbs[i], 0, sizeof(struct aiocb));
    101 
    102 		aiocbs[i]->aio_fildes = fd;
    103 		aiocbs[i]->aio_offset = i * buf_size;
    104 		aiocbs[i]->aio_buf = &bufs[i * buf_size];
    105 		aiocbs[i]->aio_nbytes = buf_size;
    106 		aiocbs[i]->aio_lio_opcode = LIO_READ;
    107 	}
    108 
    109 	/* reset the completion flag */
    110 	received_all = 0;
    111 
    112 	/* Use SIGRTMIN+1 for list completion */
    113 	event.sigev_notify = SIGEV_SIGNAL;
    114 	event.sigev_signo = SIGRTMIN + 1;
    115 	event.sigev_value.sival_ptr = NULL;
    116 
    117 	action.sa_sigaction = sigrt1_handler;
    118 	sigemptyset(&action.sa_mask);
    119 	action.sa_flags = SA_SIGINFO | SA_RESTART;
    120 	sigaction(SIGRTMIN + 1, &action, NULL);
    121 
    122 	/* Setup suspend list */
    123 	plist[0] = NULL;
    124 	plist[1] = aiocbs[WAIT_FOR_AIOCB];
    125 
    126 	/* Submit request list */
    127 	ret = lio_listio(LIO_NOWAIT, aiocbs, num_aiocbs, &event);
    128 
    129 	if (ret) {
    130 		printf(" Error at lio_listio() %d: %s\n",
    131 		       errno, strerror(errno));
    132 		goto err3;
    133 	}
    134 
    135 	/* Suspend on selected request */
    136 	ret = aio_suspend((const struct aiocb **)plist, 2, &ts);
    137 
    138 	/* Check selected request has not completed yet */
    139 	ret2 = aio_error(aiocbs[WAIT_FOR_AIOCB]);
    140 	if (ret2 != EINPROGRESS) {
    141 		/*
    142 		 * The operation was too fast, wait for completion
    143 		 * and redo it with larger buffers.
    144 		 */
    145 		err = -1;
    146 		goto err4;
    147 	}
    148 
    149 	/* timed out aio_suspend should return -1 and set errno to EAGAIN */
    150 	if (ret != -1) {
    151 		printf("aio_suspend() should return -1\n");
    152 		err = PTS_FAIL;
    153 		goto err4;
    154 	}
    155 	if (errno != EAGAIN) {
    156 		printf("aio_suspend() should set errno to EAGAIN: %d (%s)\n",
    157 		       errno, strerror(errno));
    158 		err = PTS_FAIL;
    159 		goto err4;
    160 	}
    161 
    162 	/* Wait for list processing completion */
    163 	while (!received_all)
    164 		usleep(10000);
    165 
    166 	/* Check return values and errors */
    167 	err = PTS_PASS;
    168 
    169 	for (i = 0; i < num_aiocbs; i++) {
    170 		err = aio_error(aiocbs[i]);
    171 		ret = aio_return(aiocbs[i]);
    172 
    173 		if ((err != 0) && ((size_t)ret != buf_size)) {
    174 			printf("req %d: error = %d - return = %d\n",
    175 			       i, err, ret);
    176 			err = PTS_FAIL;
    177 		}
    178 	}
    179 
    180 err4:
    181 	while (!received_all)
    182 		usleep(10000);
    183 err3:
    184 	for (i = 0; i < num_aiocbs; i++)
    185 		free(aiocbs[i]);
    186 err2:
    187 	free(bufs);
    188 err1:
    189 	close(fd);
    190 err0:
    191 	return err;
    192 }
    193 
    194 int main(void)
    195 {
    196 	int aio_cbs = 10;
    197 	int buf_size = 1024 * 64;
    198 	int ret;
    199 
    200 	if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
    201 		return PTS_UNSUPPORTED;
    202 
    203 	/* Repeat the test with increasing buffer size */
    204 	do {
    205 		ret = do_test(aio_cbs, buf_size);
    206 		buf_size += buf_size / 4;
    207 	} while (ret == -1);
    208 
    209 	if (ret != 0)
    210 		return ret;
    211 
    212 	printf("(buf_size = %i)\nTest PASSED\n", buf_size);
    213 	return PTS_PASS;
    214 }
    215