Home | History | Annotate | Line # | Download | only in libshmif
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