xref: /netbsd-src/sys/rump/net/lib/libshmif/shmif_user.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*      $NetBSD: shmif_user.c,v 1.2 2018/04/04 09:19:33 martin 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 #include <unistd.h>
33 
34 #include <rump/rumpuser_component.h>
35 
36 #include "shmif_user.h"
37 
38 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
39 
40 /*
41  * On BSD we use kqueue, on Linux we use inotify.  The underlying
42  * interface requirements aren't quite the same, but we have a very
43  * good chance of doing the fd->path mapping on Linux thanks to dcache,
44  * so just keep the existing interfaces for now.
45  */
46 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
47     || defined(__OpenBSD__)
48 #include <sys/event.h>
49 
50 #include <stdlib.h>
51 
52 int
53 rumpcomp_shmif_watchsetup(int *kqp, int fd)
54 {
55 	struct kevent kev;
56 	int rv, kq;
57 
58 	kq = *kqp;
59 	if (kq == -1) {
60 		kq = kqueue();
61 		if (kq == -1) {
62 			rv = errno;
63 			goto out;
64 		}
65 	}
66 
67 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
68 	    NOTE_WRITE, 0, 0);
69 	if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
70 		rv = errno;
71 	} else {
72 		rv = 0;
73 		*kqp = kq;
74 	}
75 
76  out:
77 	return rumpuser_component_errtrans(rv);
78 }
79 
80 int
81 rumpcomp_shmif_watchwait(int kq)
82 {
83 	void *cookie;
84 	struct kevent kev;
85 	int rv;
86 
87 	cookie = rumpuser_component_unschedule();
88 	do {
89 		rv = kevent(kq, NULL, 0, &kev, 1, NULL);
90 	} while (rv == -1 && errno == EINTR);
91 	if (rv == -1) {
92 		rv = errno;
93 	} else {
94 		rv = 0;
95 	}
96 	rumpuser_component_schedule(cookie);
97 
98 	return rumpuser_component_errtrans(rv);
99 }
100 
101 #elif defined(__linux__)
102 #include <sys/inotify.h>
103 
104 #include <limits.h>
105 #include <stdio.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 
175 /* a polling default implementation */
176 int
177 rumpcomp_shmif_watchsetup(int *nono, int fd)
178 {
179 	static int warned = 0;
180 
181 	if (!warned) {
182 		fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
183 		    "polling-only on this platform\n");
184 		warned = 1;
185 	}
186 
187 	return 0;
188 }
189 
190 int
191 rumpcomp_shmif_watchwait(int kq)
192 {
193 	void *cookie;
194 
195 	cookie = rumpuser_component_unschedule();
196 	usleep(10000);
197 	rumpuser_component_schedule(cookie);
198 
199 	return 0;
200 }
201 #endif
202 
203 int
204 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
205 {
206 	void *mem;
207 	int rv;
208 
209 	if (ftruncate(fd, len) == -1) {
210 		rv = errno;
211 		goto out;
212 	}
213 
214 #if defined(__sun__) && !defined(MAP_FILE)
215 #define MAP_FILE 0
216 #endif
217 
218 	mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
219 	if (mem == MAP_FAILED) {
220 		rv = errno;
221 	} else {
222 		rv = 0;
223 		*memp = mem;
224 	}
225 
226  out:
227 	return rumpuser_component_errtrans(rv);
228 }
229 #endif
230