shmif_user.c revision 1.2 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