1 /*
2  * Copyright (c) 2004, Bull SA. All rights reserved.
3  * Created by:  Laurent.Vivier@bull.net
4  * This file is licensed under the GPL license.  For the full content
5  * of this license, see the COPYING file at the top level of this
6  * source tree.
7  */
8 
9 /*
10  * assertion:
11  *
12  *	Asynchronous notification shall occur for AIO that are successfully
13  *	cancelled.
14  *
15  * method:
16  *
17  *	we queue a lot of aio_write() with a valid sigevent to a file descriptor
18  *	next we try to cancel all operations on this file descriptor
19  *	we guess some have been finished, other are in progress,
20  *	other are waiting
21  *	we guess we can cancel all operations waiting
22  *	then we analyze aio_error() in the event handler
23  *	if aio_error() is ECANCELED, the test is passed
24  *	otherwise, we don't know (perhaps we haven't cancel any operation ?)
25  *	if number of sig event is not equal to number of aio_write()
26  *	the test fails (in fact it hangs).
27  *
28  */
29 
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <aio.h>
40 #include <time.h>
41 
42 #include "posixtest.h"
43 
44 #define TNAME "aio_cancel/3-1.c"
45 
46 #define BUF_NB		128
47 #define BUF_SIZE	(1024 * 1024)
48 
49 static volatile int countdown = BUF_NB;
50 static volatile int canceled;
51 
sig_handler(int signum LTP_ATTRIBUTE_UNUSED,siginfo_t * info,void * context LTP_ATTRIBUTE_UNUSED)52 void sig_handler(int signum LTP_ATTRIBUTE_UNUSED, siginfo_t *info,
53     void *context LTP_ATTRIBUTE_UNUSED)
54 {
55 	struct aiocb *a = info->si_value.sival_ptr;
56 
57 	if (aio_error(a) == ECANCELED)
58 		canceled++;
59 
60 	aio_return(a);		/* free entry */
61 
62 	countdown--;
63 }
64 
main(void)65 int main(void)
66 {
67 	char tmpfname[256];
68 	int fd;
69 	struct aiocb *aiocb_list[BUF_NB];
70 	struct aiocb *aiocb;
71 	struct sigaction action;
72 	struct timespec processing_completion_ts = {0, 10000000};
73 	int i;
74 
75 	if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) {
76 		printf(TNAME " %ld\n", sysconf(_SC_ASYNCHRONOUS_IO));
77 		return PTS_UNSUPPORTED;
78 	}
79 
80 	snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_aio_cancel_3_1_%d",
81 		 getpid());
82 	unlink(tmpfname);
83 	fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
84 	if (fd == -1) {
85 		printf(TNAME " Error at open(): %s\n", strerror(errno));
86 		return PTS_UNRESOLVED;
87 	}
88 
89 	unlink(tmpfname);
90 
91 	/* install signal handler */
92 
93 	action.sa_sigaction = sig_handler;
94 	sigemptyset(&action.sa_mask);
95 	action.sa_flags = SA_SIGINFO | SA_RESTART;
96 	if (sigaction(SIGRTMIN + 1, &action, NULL)) {
97 		printf(TNAME " Error at sigaction(): %s\n", strerror(errno));
98 		return PTS_FAIL;
99 	}
100 
101 	/* create AIO req */
102 
103 	for (i = 0; i < BUF_NB; i++) {
104 		aiocb = malloc(sizeof(struct aiocb));
105 		if (aiocb == NULL) {
106 			printf(TNAME " Error at malloc(): %s\n",
107 			       strerror(errno));
108 			return PTS_FAIL;
109 		}
110 
111 		aiocb->aio_fildes = fd;
112 		aiocb->aio_buf = malloc(BUF_SIZE);
113 		if (aiocb->aio_buf == NULL) {
114 			printf(TNAME " Error at malloc(): %s\n",
115 			       strerror(errno));
116 			return PTS_FAIL;
117 		}
118 
119 		aiocb->aio_nbytes = BUF_SIZE;
120 		aiocb->aio_offset = 0;
121 
122 		aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
123 		aiocb->aio_sigevent.sigev_signo = SIGRTMIN + 1;
124 		aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb;
125 		aiocb->aio_reqprio = 0;
126 
127 		aiocb_list[i] = aiocb;
128 	}
129 
130 	for (i = 0; i < BUF_NB; i++) {
131 		if (aio_write(aiocb_list[i]) == -1) {
132 			printf(TNAME " loop %d: Error at aio_write(): %s\n",
133 			       i, strerror(errno));
134 			return PTS_FAIL;
135 		}
136 	}
137 
138 	/* try to cancel all
139 	 * we hope to have enough time to cancel at least one
140 	 */
141 
142 	if (aio_cancel(fd, NULL) == -1) {
143 		printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
144 		return PTS_FAIL;
145 	}
146 
147 	close(fd);
148 
149 	while (countdown)
150 		nanosleep(&processing_completion_ts, NULL);
151 
152 	if (!canceled)
153 		return PTS_UNRESOLVED;
154 
155 	printf("Test PASSED\n");
156 	return PTS_PASS;
157 }
158