shmif_user.c revision 1.4 1 /* $NetBSD: shmif_user.c,v 1.4 2019/01/27 02:08:49 pgoyette 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
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: shmif_user.c,v 1.4 2019/01/27 02:08:49 pgoyette Exp $");
30
31 #ifndef _KERNEL
32 #include <sys/types.h>
33 #include <sys/mman.h>
34
35 #include <errno.h>
36 #include <unistd.h>
37
38 #include <rump/rumpuser_component.h>
39
40 #include "shmif_user.h"
41
42 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
43
44 /*
45 * On BSD we use kqueue, on Linux we use inotify. The underlying
46 * interface requirements aren't quite the same, but we have a very
47 * good chance of doing the fd->path mapping on Linux thanks to dcache,
48 * so just keep the existing interfaces for now.
49 */
50 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
51 || defined(__OpenBSD__)
52 #include <sys/event.h>
53
54 #include <stdlib.h>
55
56 int
57 rumpcomp_shmif_watchsetup(int *kqp, int fd)
58 {
59 struct kevent kev;
60 int rv, kq;
61
62 kq = *kqp;
63 if (kq == -1) {
64 kq = kqueue();
65 if (kq == -1) {
66 rv = errno;
67 goto out;
68 }
69 }
70
71 EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
72 NOTE_WRITE, 0, 0);
73 if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
74 rv = errno;
75 } else {
76 rv = 0;
77 *kqp = kq;
78 }
79
80 out:
81 return rumpuser_component_errtrans(rv);
82 }
83
84 int
85 rumpcomp_shmif_watchwait(int kq)
86 {
87 void *cookie;
88 struct kevent kev;
89 int rv;
90
91 cookie = rumpuser_component_unschedule();
92 do {
93 rv = kevent(kq, NULL, 0, &kev, 1, NULL);
94 } while (rv == -1 && errno == EINTR);
95 if (rv == -1) {
96 rv = errno;
97 } else {
98 rv = 0;
99 }
100 rumpuser_component_schedule(cookie);
101
102 return rumpuser_component_errtrans(rv);
103 }
104
105 #elif defined(__linux__)
106 #include <sys/inotify.h>
107
108 #include <limits.h>
109 #include <stdio.h>
110
111 int
112 rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
113 {
114 char procbuf[PATH_MAX], linkbuf[PATH_MAX];
115 ssize_t nn;
116 int inotify, rv;
117
118 inotify = *inotifyp;
119 if (inotify == -1) {
120 inotify = inotify_init();
121 if (inotify == -1) {
122 rv = errno;
123 goto out;
124 }
125 }
126
127 /* ok, need to map fd into path for inotify */
128 snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
129 nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
130 if (nn >= (ssize_t)sizeof(linkbuf)-1) {
131 nn = -1;
132 errno = E2BIG; /* pick something */
133 }
134 if (nn == -1) {
135 rv = errno;
136 close(inotify);
137 goto out;
138 }
139
140 linkbuf[nn] = '\0';
141 if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
142 rv = errno;
143 close(inotify);
144 goto out;
145 }
146 rv = 0;
147 *inotifyp = inotify;
148
149 out:
150 return rumpuser_component_errtrans(rv);
151 }
152
153 int
154 rumpcomp_shmif_watchwait(int kq)
155 {
156 struct inotify_event iev;
157 void *cookie;
158 ssize_t nn;
159 int rv;
160
161 cookie = rumpuser_component_unschedule();
162 do {
163 nn = read(kq, &iev, sizeof(iev));
164 } while (nn == -1 && errno == EINTR);
165 if (nn == -1) {
166 rv = errno;
167 } else {
168 rv = 0;
169 }
170
171 rumpuser_component_schedule(cookie);
172
173 return rumpuser_component_errtrans(rv);
174 }
175
176 #else
177 #include <stdio.h>
178
179 /* a polling default implementation */
180 int
181 rumpcomp_shmif_watchsetup(int *nono, int fd)
182 {
183 static int warned = 0;
184
185 if (!warned) {
186 fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
187 "polling-only on this platform\n");
188 warned = 1;
189 }
190
191 return 0;
192 }
193
194 int
195 rumpcomp_shmif_watchwait(int kq)
196 {
197 void *cookie;
198
199 cookie = rumpuser_component_unschedule();
200 usleep(10000);
201 rumpuser_component_schedule(cookie);
202
203 return 0;
204 }
205 #endif
206
207 int
208 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
209 {
210 void *mem;
211 int rv;
212
213 if (ftruncate(fd, len) == -1) {
214 rv = errno;
215 goto out;
216 }
217
218 #if defined(__sun__) && !defined(MAP_FILE)
219 #define MAP_FILE 0
220 #endif
221
222 mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
223 if (mem == MAP_FAILED) {
224 rv = errno;
225 } else {
226 rv = 0;
227 *memp = mem;
228 }
229
230 out:
231 return rumpuser_component_errtrans(rv);
232 }
233 #endif
234