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