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