xref: /netbsd-src/sys/rump/net/lib/libshmif/shmif_user.c (revision 3feacbccbd4c8b6fd5f19c8e34474c4c3f8923d7)
1 /*      $NetBSD: shmif_user.c,v 1.1 2014/03/13 01:42:59 pooka Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #ifndef _KERNEL
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 
31 #include <errno.h>
32 
33 #include <rump/rumpuser_component.h>
34 
35 #include "shmif_user.h"
36 
37 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
38 
39 /*
40  * On BSD we use kqueue, on Linux we use inotify.  The underlying
41  * interface requirements aren't quite the same, but we have a very
42  * good chance of doing the fd->path mapping on Linux thanks to dcache,
43  * so just keep the existing interfaces for now.
44  */
45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
46     || defined(__OpenBSD__)
47 #include <sys/event.h>
48 
49 #include <stdlib.h>
50 
51 int
52 rumpcomp_shmif_watchsetup(int *kqp, int fd)
53 {
54 	struct kevent kev;
55 	int rv, kq;
56 
57 	kq = *kqp;
58 	if (kq == -1) {
59 		kq = kqueue();
60 		if (kq == -1) {
61 			rv = errno;
62 			goto out;
63 		}
64 	}
65 
66 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
67 	    NOTE_WRITE, 0, 0);
68 	if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
69 		rv = errno;
70 	} else {
71 		rv = 0;
72 		*kqp = kq;
73 	}
74 
75  out:
76 	return rumpuser_component_errtrans(rv);
77 }
78 
79 int
80 rumpcomp_shmif_watchwait(int kq)
81 {
82 	void *cookie;
83 	struct kevent kev;
84 	int rv;
85 
86 	cookie = rumpuser_component_unschedule();
87 	do {
88 		rv = kevent(kq, NULL, 0, &kev, 1, NULL);
89 	} while (rv == -1 && errno == EINTR);
90 	if (rv == -1) {
91 		rv = errno;
92 	} else {
93 		rv = 0;
94 	}
95 	rumpuser_component_schedule(cookie);
96 
97 	return rumpuser_component_errtrans(rv);
98 }
99 
100 #elif defined(__linux__)
101 #include <sys/inotify.h>
102 
103 #include <limits.h>
104 #include <stdio.h>
105 #include <unistd.h>
106 
107 int
108 rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
109 {
110 	char procbuf[PATH_MAX], linkbuf[PATH_MAX];
111 	ssize_t nn;
112 	int inotify, rv;
113 
114 	inotify = *inotifyp;
115 	if (inotify == -1) {
116 		inotify = inotify_init();
117 		if (inotify == -1) {
118 			rv = errno;
119 			goto out;
120 		}
121 	}
122 
123 	/* ok, need to map fd into path for inotify */
124 	snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
125 	nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
126 	if (nn >= (ssize_t)sizeof(linkbuf)-1) {
127 		nn = -1;
128 		errno = E2BIG; /* pick something */
129 	}
130 	if (nn == -1) {
131 		rv = errno;
132 		close(inotify);
133 		goto out;
134 	}
135 
136 	linkbuf[nn] = '\0';
137 	if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
138 		rv = errno;
139 		close(inotify);
140 		goto out;
141 	}
142 	rv = 0;
143 	*inotifyp = inotify;
144 
145  out:
146 	return rumpuser_component_errtrans(rv);
147 }
148 
149 int
150 rumpcomp_shmif_watchwait(int kq)
151 {
152 	struct inotify_event iev;
153 	void *cookie;
154 	ssize_t nn;
155 	int rv;
156 
157 	cookie = rumpuser_component_unschedule();
158 	do {
159 		nn = read(kq, &iev, sizeof(iev));
160 	} while (nn == -1 && errno == EINTR);
161 	if (nn == -1) {
162 		rv = errno;
163 	} else {
164 		rv = 0;
165 	}
166 
167 	rumpuser_component_schedule(cookie);
168 
169 	return rumpuser_component_errtrans(rv);
170 }
171 
172 #else
173 #include <stdio.h>
174 #include <unistd.h>
175 
176 /* a polling default implementation */
177 int
178 rumpcomp_shmif_watchsetup(int *nono, int fd)
179 {
180 	static int warned = 0;
181 
182 	if (!warned) {
183 		fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
184 		    "polling-only on this platform\n");
185 		warned = 1;
186 	}
187 
188 	return 0;
189 }
190 
191 int
192 rumpcomp_shmif_watchwait(int kq)
193 {
194 	void *cookie;
195 
196 	cookie = rumpuser_component_unschedule();
197 	usleep(10000);
198 	rumpuser_component_schedule(cookie);
199 
200 	return 0;
201 }
202 #endif
203 
204 int
205 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
206 {
207 	void *mem;
208 	int rv;
209 
210 	if (ftruncate(fd, len) == -1) {
211 		rv = errno;
212 		goto out;
213 	}
214 
215 #if defined(__sun__) && !defined(MAP_FILE)
216 #define MAP_FILE 0
217 #endif
218 
219 	mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
220 	if (mem == MAP_FAILED) {
221 		rv = errno;
222 	} else {
223 		rv = 0;
224 		*memp = mem;
225 	}
226 
227  out:
228 	return rumpuser_component_errtrans(rv);
229 }
230 #endif
231