eventfd01.c revision 56207cec7732e09c216c751c0b5f88a242bacae6
1/*
2 *   Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org>
3 *
4 *   Based on testcases/kernel/syscalls/waitpid/waitpid01.c
5 *   Original copyright message:
6 *
7 *   Copyright (c) International Business Machines  Corp., 2001
8 *
9 *   This program is free software;  you can redistribute it and/or modify
10 *   it under the terms of the GNU General Public License as published by
11 *   the Free Software Foundation; either version 2 of the License, or
12 *   (at your option) any later version.
13 *
14 *   This program is distributed in the hope that it will be useful,
15 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17 *   the GNU General Public License for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program;  if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24/*
25 * NAME
26 *	eventfd01.c
27 *
28 * DESCRIPTION
29 *      Test cases for eventfd syscall.
30 *
31 * USAGE:  <for command-line>
32 *      eventfd01 [-c n] [-i n] [-I x] [-P x] [-t]
33 *      where,  -c n : Run n copies concurrently.
34 *              -i n : Execute test n times.
35 *              -I x : Execute test for x seconds.
36 *              -P x : Pause for x seconds between iterations.
37 *              -t   : Turn on syscall timing.
38 *
39 * History
40 *	07/2008 Vijay Kumar
41 *		Initial Version.
42 *
43 * Restrictions
44 *	None
45 */
46
47#include "config.h"
48
49#include <sys/select.h>
50#include <sys/signal.h>
51#include <sys/types.h>
52#include <sys/wait.h>
53#include <unistd.h>
54#include <fcntl.h>
55#include <errno.h>
56#include <string.h>
57#include <stdint.h>
58#include <poll.h>
59
60#include <test.h>
61#include <usctest.h>
62#include <linux_syscall_numbers.h>
63
64#ifdef HAVE_LIBAIO_H
65#include <libaio.h>
66#endif
67
68static void setup(void);
69static void cleanup(void);
70
71TCID_DEFINE(eventfd01);
72int TST_TOTAL = 15;
73extern int Tst_count;
74
75static int myeventfd(unsigned int initval, int flags)
76{
77	/* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */
78#if defined (__NR_eventfd)
79	return syscall(__NR_eventfd, initval);
80#else
81	errno = ENOSYS;
82	return -1;
83#endif
84}
85
86/*
87 * clear_counter() - clears the counter by performing a dummy read
88 * @fd: the eventfd
89 *
90 * RETURNS:
91 * 0 on success, and -1 on failure
92 */
93static int clear_counter(int fd)
94{
95	uint64_t dummy;
96	int ret;
97
98	ret = read(fd, &dummy, sizeof(dummy));
99	if (ret == -1) {
100		if (errno != EAGAIN) {
101			tst_resm(TINFO, "error clearing counter: %s",
102				 strerror(errno));
103			return -1;
104		}
105	}
106
107	return 0;
108}
109
110/*
111 * set_counter() - sets the count to specified value
112 * @fd: the eventfd
113 * @val: the value to be set
114 *
115 * Clears the counter and sets the counter to @val.
116 *
117 * RETURNS:
118 * 0 on success, -1 on failure
119 */
120static int set_counter(int fd, uint64_t val)
121{
122	int ret;
123
124	ret = clear_counter(fd);
125	if (ret == -1) {
126		return -1;
127	}
128
129	ret = write(fd, &val, sizeof(val));
130	if (ret == -1) {
131		tst_resm(TINFO, "error setting counter value: %s",
132			 strerror(errno));
133		return -1;
134	}
135
136	return 0;
137}
138
139/*
140 * Test whether the current value of the counter matches @required.
141 */
142static void read_test(int fd, uint64_t required)
143{
144	int ret;
145	uint64_t val;
146
147	ret = read(fd, &val, sizeof(val));
148	if (ret == -1) {
149		tst_resm(TBROK, "error reading eventfd: %s", strerror(errno));
150		return;
151	}
152
153	if (val == required)
154		tst_resm(TPASS, "counter value matches required");
155	else
156		tst_resm(TFAIL, "counter value mismatch: "
157			 "required: %llu, got: %llu", required, val);
158}
159
160/*
161 * Test whether read returns with error EAGAIN when counter is at 0.
162 */
163static void read_eagain_test(int fd)
164{
165	int ret;
166	uint64_t val;
167
168	ret = clear_counter(fd);
169	if (ret == -1) {
170		tst_resm(TBROK, "error clearing counter");
171		return;
172	}
173
174	ret = read(fd, &val, sizeof(val));
175	if (ret == -1) {
176		if (errno == EAGAIN)
177			tst_resm(TPASS, "read failed with EAGAIN as expected");
178		else
179			tst_resm(TFAIL, "read failed with unexpected "
180				 "error: %s", strerror(errno));
181	} else {
182		tst_resm(TFAIL, "read returned with %d");
183	}
184}
185
186/*
187 * Test whether writing to counter works.
188 */
189static void write_test(int fd)
190{
191	int ret;
192	uint64_t val;
193
194	val = 12;
195
196	ret = set_counter(fd, val);
197	if (ret == -1) {
198		tst_resm(TBROK, "error setting counter value to %lld", val);
199		return;
200	}
201
202	read_test(fd, val);
203}
204
205/*
206 * Test whether write returns with error EAGAIN when counter is at
207 * (UINT64_MAX - 1).
208 */
209static void write_eagain_test(int fd)
210{
211	int ret;
212	uint64_t val;
213
214	ret = set_counter(fd, UINT64_MAX - 1);
215	if (ret == -1) {
216		tst_resm(TBROK, "error setting counter value to UINT64_MAX-1");
217		return;
218	}
219
220	val = 1;
221	ret = write(fd, &val, sizeof(val));
222	if (ret == -1) {
223		if (errno == EAGAIN)
224			tst_resm(TPASS, "write failed with EAGAIN as "
225				 "expected");
226		else
227			tst_resm(TFAIL, "write returned with unexpected "
228				 "error: %s", strerror(errno));
229	} else {
230		tst_resm(TFAIL, "write returned with %d", ret);
231	}
232}
233
234/*
235 * Test whether read returns with error EINVAL, if buffer size is less
236 * than 8 bytes.
237 */
238static void read_einval_test(int fd)
239{
240	uint32_t invalid;
241	int ret;
242
243	ret = read(fd, &invalid, sizeof(invalid));
244	if (ret == -1) {
245		if (errno == EINVAL) {
246			tst_resm(TPASS, "read failed with EINVAL as expected");
247		} else {
248			tst_resm(TFAIL, "read returned with unexpected "
249				 "error: %s", strerror(errno));
250		}
251	} else {
252		tst_resm(TFAIL, "read returned with %d", ret);
253	}
254}
255
256/*
257 * Test whether write returns with error EINVAL, if buffer size is
258 * less than 8 bytes.
259 */
260static void write_einval_test(int fd)
261{
262	uint32_t invalid;
263	int ret;
264
265	ret = write(fd, &invalid, sizeof(invalid));
266	if (ret == -1) {
267		if (errno == EINVAL) {
268			tst_resm(TPASS, "write failed with EINVAL as "
269				 "expected");
270		} else {
271			tst_resm(TFAIL, "write returned with unexpected "
272				 "error: %s", strerror(errno));
273		}
274	} else {
275		tst_resm(TFAIL, "write returned with %d", ret);
276	}
277}
278
279/*
280 * Test wheter write returns with error EINVAL, when the written value
281 * is 0xFFFFFFFFFFFFFFFF.
282 */
283static void write_einval2_test(int fd)
284{
285	int ret;
286	uint64_t val;
287
288	ret = clear_counter(fd);
289	if (ret == -1) {
290		tst_resm(TBROK, "error clearing counter");
291		return;
292	}
293
294	val = 0xffffffffffffffffLL;
295	ret = write(fd, &val, sizeof(val));
296	if (ret == -1) {
297		if (errno == EINVAL)
298			tst_resm(TPASS, "write failed with EINVAL as "
299				 "expected");
300		else
301			tst_resm(TFAIL, "write returned with unexpected "
302				 "error: %s", strerror(errno));
303	} else {
304		tst_resm(TFAIL, "write returned with %d", ret);
305	}
306}
307
308/*
309 * Test whether readfd is set by select when counter value is
310 * non-zero.
311 */
312static void readfd_set_test(int fd)
313{
314	int ret;
315	fd_set readfds;
316	struct timeval timeout = { 0, 0 };
317	uint64_t non_zero = 10;
318
319	FD_ZERO(&readfds);
320	FD_SET(fd, &readfds);
321
322	ret = set_counter(fd, non_zero);
323	if (ret == -1) {
324		tst_resm(TBROK, "error setting counter value to %lld",
325			 non_zero);
326		return;
327	}
328
329	ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
330	if (ret == -1) {
331		/* EINTR cannot occur, since we don't block. */
332		tst_resm(TBROK, "select: error getting fd status: %s",
333			 strerror(errno));
334		return;
335	}
336
337	if (FD_ISSET(fd, &readfds))
338		tst_resm(TPASS, "fd is set in readfds");
339	else
340		tst_resm(TFAIL, "fd is not set in readfds");
341}
342
343/*
344 * Test whether readfd is not set by select when counter value is
345 * zero.
346 */
347static void readfd_not_set_test(int fd)
348{
349	int ret;
350	fd_set readfds;
351	struct timeval timeout = { 0, 0 };
352
353	FD_ZERO(&readfds);
354	FD_SET(fd, &readfds);
355
356	ret = clear_counter(fd);
357	if (ret == -1) {
358		tst_resm(TBROK, "error clearing counter");
359		return;
360	}
361
362	ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
363	if (ret == -1) {
364		/* EINTR cannot occur, since we don't block. */
365		tst_resm(TBROK, "select: error getting fd status: %s",
366			 strerror(errno));
367		return;
368	}
369
370	if (!FD_ISSET(fd, &readfds))
371		tst_resm(TPASS, "fd is not set in readfds");
372	else
373		tst_resm(TFAIL, "fd is set in readfds");
374}
375
376/*
377 * Test whether writefd is set by select when counter value is not the
378 * maximum counter value.
379 */
380static void writefd_set_test(int fd)
381{
382	int ret;
383	fd_set writefds;
384	struct timeval timeout = { 0, 0 };
385	uint64_t non_max = 10;
386
387	FD_ZERO(&writefds);
388	FD_SET(fd, &writefds);
389
390	ret = set_counter(fd, non_max);
391	if (ret == -1) {
392		tst_resm(TBROK, "error setting counter value to %lld", non_max);
393		return;
394	}
395
396	ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
397	if (ret == -1) {
398		/* EINTR cannot occur, since we don't block. */
399		tst_resm(TBROK, "select: error getting fd status: %s",
400			 strerror(errno));
401		return;
402	}
403
404	if (FD_ISSET(fd, &writefds))
405		tst_resm(TPASS, "fd is set in writefds");
406	else
407		tst_resm(TFAIL, "fd is not set in writefds");
408}
409
410/*
411 * Test whether writefd is not set by select when counter value is at
412 * (UINT64_MAX - 1).
413 */
414static void writefd_not_set_test(int fd)
415{
416	int ret;
417	fd_set writefds;
418	struct timeval timeout = { 0, 0 };
419
420	FD_ZERO(&writefds);
421	FD_SET(fd, &writefds);
422
423	ret = set_counter(fd, UINT64_MAX - 1);
424	if (ret == -1) {
425		tst_resm(TBROK, "error setting counter value to UINT64_MAX-1");
426		return;
427	}
428
429	ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
430	if (ret == -1) {
431		/* EINTR cannot occur, since we don't block. */
432		tst_resm(TBROK, "select: error getting fd status: %s",
433			 strerror(errno));
434		return;
435	}
436
437	if (!FD_ISSET(fd, &writefds))
438		tst_resm(TPASS, "fd is not set in writefds");
439	else
440		tst_resm(TFAIL, "fd is set in writefds");
441}
442
443/*
444 * Test whether counter update in child is reflected in the parent.
445 */
446static void child_inherit_test(int fd)
447{
448	uint64_t val;
449	pid_t cpid;
450	int ret;
451	int status;
452	uint64_t to_parent = 0xdeadbeef;
453	uint64_t dummy;
454
455	cpid = fork();
456	if (cpid == -1)
457		tst_resm(TBROK, "error while forking child: %s",
458			 strerror(errno));
459	if (cpid != 0) {
460		/* Parent */
461		ret = wait(&status);
462		if (ret == -1) {
463			tst_resm(TBROK, "error getting child exit status");
464			return;
465		}
466
467		if (WEXITSTATUS(status) == 1) {
468			tst_resm(TBROK, "counter value write not "
469				 "succesful in child");
470			return;
471		}
472
473		ret = read(fd, &val, sizeof(val));
474		if (ret == -1) {
475			tst_resm(TBROK, "error reading eventfd: %s",
476				 strerror(errno));
477			return;
478		}
479
480		if (val == to_parent)
481			tst_resm(TPASS, "counter value write from "
482				 "child successful");
483		else
484			tst_resm(TFAIL, "counter value write in child "
485				 "failed");
486	} else {
487		/* Child */
488		ret = read(fd, &dummy, sizeof(dummy));
489		if (ret == -1 && errno != EAGAIN) {
490			tst_resm(TWARN, "error clearing counter: %s",
491				 strerror(errno));
492			exit(1);
493		}
494
495		ret = write(fd, &to_parent, sizeof(to_parent));
496		if (ret == -1) {
497			tst_resm(TWARN, "error writing eventfd: %s",
498				 strerror(errno));
499			exit(1);
500		}
501
502		exit(0);
503	}
504}
505
506#ifdef HAVE_IO_SET_EVENTFD
507/*
508 * Test whether counter overflow is detected and handled correctly.
509 *
510 * It is not possible to directly overflow the counter using the
511 * write() syscall. Overflows occur when the counter is incremented
512 * from kernel space, in an irq context, when it is not possible to
513 * block the calling thread of execution.
514 *
515 * The AIO subsystem internally uses eventfd mechanism for
516 * notification of completion of read or write requests. In this test
517 * we trigger a counter overflow, by setting the counter value to the
518 * max possible value initially. When the AIO subsystem notifies
519 * through the eventfd counter, the counter overflows.
520 *
521 * NOTE: If the the counter starts from an initial value of 0, it will
522 * take decades for an overflow to occur. But since we set the initial
523 * value to the max possible counter value, we are able to cause it to
524 * overflow with a single increment.
525 *
526 * When the counter overflows, the following are tested
527 *   1. Check whether POLLERR event occurs in poll() for the eventfd.
528 *   2. Check whether readfd_set/writefd_set is set in select() for the
529        eventfd.
530 *   3. The counter value is UINT64_MAX.
531 */
532static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx)
533{
534	int ret;
535	struct iocb iocb;
536	struct iocb *iocbap[1];
537	static char buf[4 * 1024];
538
539	*ctx = 0;
540	ret = io_setup(16, ctx);
541	if (ret < 0) {
542		tst_resm(TINFO, "io_setup error: %s", strerror(-ret));
543		return -1;
544	}
545
546	*fd = open("testfile", O_RDWR | O_CREAT, 0644);
547	if (*fd == -1) {
548		tst_resm(TINFO, "error creating tmp file: %s", strerror(errno));
549		goto err_io_destroy;
550	}
551
552	ret = set_counter(evfd, UINT64_MAX - 1);
553	if (ret == -1) {
554		tst_resm(TINFO, "error setting counter to UINT64_MAX-1");
555		goto err_close_file;
556	}
557
558	io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0);
559	io_set_eventfd(&iocb, evfd);
560
561	iocbap[0] = &iocb;
562	ret = io_submit(*ctx, 1, iocbap);
563	if (ret < 0) {
564		tst_resm(TINFO, "error submitting iocb: %s", strerror(-ret));
565		goto err_close_file;
566	}
567
568	return 0;
569
570      err_close_file:
571	close(*fd);
572
573      err_io_destroy:
574	io_destroy(*ctx);
575
576	return -1;
577}
578
579static void cleanup_overflow(int fd, io_context_t ctx)
580{
581	close(fd);
582	io_destroy(ctx);
583}
584
585static void overflow_select_test(int evfd)
586{
587	struct timeval timeout = { 10, 0 };
588	fd_set readfds;
589	int fd;
590	io_context_t ctx;
591	int ret;
592
593	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
594	if (ret == -1) {
595		tst_resm(TBROK, "error triggering eventfd overflow");
596		return;
597	}
598
599	FD_ZERO(&readfds);
600	FD_SET(evfd, &readfds);
601	ret = select(evfd + 1, &readfds, NULL, NULL, &timeout);
602	if (ret == -1) {
603		tst_resm(TBROK, "error getting evfd status with select: %s",
604			 strerror(errno));
605		goto err_cleanup;
606	}
607
608	if (FD_ISSET(evfd, &readfds))
609		tst_resm(TPASS, "read fd set as expected");
610	else
611		tst_resm(TFAIL, "read fd not set");
612
613      err_cleanup:
614	cleanup_overflow(fd, ctx);
615}
616
617static void overflow_poll_test(int evfd)
618{
619	struct pollfd pollfd;
620	int fd;
621	io_context_t ctx;
622	int ret;
623
624	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
625	if (fd == -1) {
626		tst_resm(TBROK, "error triggering eventfd overflow");
627		return;
628	}
629
630	pollfd.fd = evfd;
631	pollfd.events = POLLIN;
632	pollfd.revents = 0;
633	ret = poll(&pollfd, 1, 10000);
634	if (ret == -1) {
635		tst_resm(TBROK, "error getting evfd status with poll: %s",
636			 strerror(errno));
637		goto err_cleanup;
638	}
639	if (pollfd.revents & POLLERR)
640		tst_resm(TPASS, "POLLERR occurred as expected");
641	else
642		tst_resm(TFAIL, "POLLERR did not occur");
643
644      err_cleanup:
645	cleanup_overflow(fd, ctx);
646}
647
648static void overflow_read_test(int evfd)
649{
650	uint64_t count;
651	io_context_t ctx;
652	int fd;
653	int ret;
654
655	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
656	if (ret == -1) {
657		tst_resm(TBROK, "error triggering eventfd overflow");
658		return;
659	}
660
661	ret = read(evfd, &count, sizeof(count));
662	if (ret == -1) {
663		tst_resm(TBROK, "error reading eventfd: %s", strerror(errno));
664		goto err_cleanup;
665	}
666
667	if (count == UINT64_MAX)
668		tst_resm(TPASS, "overflow occurred as expected");
669	else
670		tst_resm(TFAIL, "overflow did not occur");
671
672      err_cleanup:
673	cleanup_overflow(fd, ctx);
674}
675#else
676static void overflow_select_test(int evfd)
677{
678	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
679}
680
681static void overflow_poll_test(int evfd)
682{
683	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
684}
685
686static void overflow_read_test(int evfd)
687{
688	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
689}
690#endif
691
692int main(int argc, char **argv)
693{
694	int lc;			/* loop counter */
695	char *msg;		/* message returned from parse_opts */
696	int fd;
697
698	/* parse standard options */
699	msg = parse_opts(argc, argv, (option_t *) NULL, NULL);
700	if (msg != NULL) {
701		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
702		tst_exit();
703		/* NOTREACHED */
704	}
705
706	setup();
707
708	/* check for looping state if -i option is given */
709	for (lc = 0; TEST_LOOPING(lc); lc++) {
710		int ret;
711		uint64_t einit = 10;
712
713		/* reset Tst_count in case we are looping */
714		Tst_count = 0;
715
716		fd = myeventfd(einit, 0);
717		if (fd == -1)
718			tst_brkm(TBROK, cleanup, "error creating eventfd: %s",
719				 strerror(errno));
720
721		ret = fcntl(fd, F_SETFL, O_NONBLOCK);
722		if (ret == -1)
723			tst_brkm(TBROK, cleanup,
724				 "error setting non-block mode: %s", strerror);
725
726		read_test(fd, einit);
727		read_eagain_test(fd);
728		write_test(fd);
729		write_eagain_test(fd);
730		read_einval_test(fd);
731		write_einval_test(fd);
732		write_einval2_test(fd);
733		readfd_set_test(fd);
734		readfd_not_set_test(fd);
735		writefd_set_test(fd);
736		writefd_not_set_test(fd);
737		child_inherit_test(fd);
738		overflow_select_test(fd);
739		overflow_poll_test(fd);
740		overflow_read_test(fd);
741
742		close(fd);
743	}
744
745	cleanup();
746	/* NOT REACHED */
747
748	return 0;
749}
750
751/*
752 * setup() - performs all ONE TIME setup for this test
753 */
754static void setup(void)
755{
756	/* capture signals */
757	tst_sig(FORK, DEF_HANDLER, cleanup);
758
759	if (tst_kvercmp(2, 6, 22) < 0)
760		tst_brkm(TCONF, cleanup, "2.6.22 or greater kernel required");
761
762	/* Pause if that option was specified
763	 * TEST_PAUSE contains the code to fork the test with the -c option.
764	 */
765	TEST_PAUSE;
766}
767
768/*
769 * cleanup() - performs all ONE TIME cleanup for this test
770 */
771static void cleanup(void)
772{
773	/*
774	 * print timing stats if that option was specified.
775	 * print errno log if that option was specified.
776	 */
777	TEST_CLEANUP;
778
779	/* exit with return code appropriate for results */
780	tst_exit();
781 /*NOTREACHED*/}
782