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