1 /*
2  *  eventfd-sem by Davide Libenzi (Simple test for eventfd sempahore)
3  *  Copyright (C) 2009  Davide Libenzi
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Davide Libenzi <davidel@xmailserver.org>
20  *  Reference: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=bcd0b235bf3808dec5115c381cd55568f63b85f0
21  *  Reference: http://www.xmailserver.org/eventfd-sem.c
22  *  eventfd: testing improved support for semaphore-like behavior in linux-2.6.30
23  *
24  */
25 
26 #include <sys/types.h>
27 #include <sys/syscall.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <inttypes.h>
37 
38 #include "test.h"
39 #include "lapi/syscalls.h"
40 
41 char *TCID = "eventfd2_03";
42 int TST_TOTAL = 1;
43 
44 #ifndef EFD_SEMLIKE
45 #define EFD_SEMLIKE (1 << 0)
46 #endif
47 
48 /* Dummy function as syscall from linux_syscall_numbers.h uses cleanup(). */
cleanup(void)49 void cleanup(void)
50 {
51 }
52 
eventfd2(int count,int flags)53 static int eventfd2(int count, int flags)
54 {
55 	return ltp_syscall(__NR_eventfd2, count, flags);
56 }
57 
xsem_wait(int fd)58 static void xsem_wait(int fd)
59 {
60 	u_int64_t cntr;
61 
62 	if (read(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) {
63 		perror("reading eventfd");
64 		exit(1);
65 	}
66 	fprintf(stdout, "[%u] wait completed on %d: count=%" PRIu64 "\n",
67 		getpid(), fd, cntr);
68 }
69 
xsem_post(int fd,int count)70 static void xsem_post(int fd, int count)
71 {
72 	u_int64_t cntr = count;
73 
74 	if (write(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) {
75 		perror("writing eventfd");
76 		exit(1);
77 	}
78 }
79 
sem_player(int fd1,int fd2)80 static void sem_player(int fd1, int fd2)
81 {
82 	fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1);
83 	xsem_post(fd1, 1);
84 
85 	fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2);
86 	xsem_wait(fd2);
87 
88 	fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1);
89 	xsem_post(fd1, 1);
90 
91 	fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2);
92 	xsem_wait(fd2);
93 
94 	fprintf(stdout, "[%u] posting 5 on %d\n", getpid(), fd1);
95 	xsem_post(fd1, 5);
96 
97 	fprintf(stdout, "[%u] waiting 5 times on %d\n", getpid(), fd2);
98 	xsem_wait(fd2);
99 	xsem_wait(fd2);
100 	xsem_wait(fd2);
101 	xsem_wait(fd2);
102 	xsem_wait(fd2);
103 }
104 
usage(char const * prg)105 static void usage(char const *prg)
106 {
107 	fprintf(stderr, "use: %s [-h]\n", prg);
108 }
109 
main(int argc,char ** argv)110 int main(int argc, char **argv)
111 {
112 	int c, fd1, fd2, status;
113 	pid_t cpid_poster, cpid_waiter;
114 
115 	while ((c = getopt(argc, argv, "h")) != -1) {
116 		switch (c) {
117 		default:
118 			usage(argv[0]);
119 			return 1;
120 		}
121 	}
122 	if ((tst_kvercmp(2, 6, 27)) < 0) {
123 		tst_brkm(TCONF,
124 			 NULL,
125 			 "This test can only run on kernels that are 2.6.27 and higher");
126 	}
127 	if ((fd1 = eventfd2(0, EFD_SEMLIKE)) == -1 ||
128 	    (fd2 = eventfd2(0, EFD_SEMLIKE)) == -1) {
129 		perror("eventfd2");
130 		return 1;
131 	}
132 	if ((cpid_poster = fork()) == 0) {
133 		sem_player(fd1, fd2);
134 		exit(0);
135 	}
136 	if ((cpid_waiter = fork()) == 0) {
137 		sem_player(fd2, fd1);
138 		exit(0);
139 	}
140 	waitpid(cpid_poster, &status, 0);
141 	waitpid(cpid_waiter, &status, 0);
142 
143 	tst_exit();
144 }
145