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