Module Name: src Committed By: pooka Date: Fri Feb 26 18:54:21 UTC 2010
Modified Files: src/lib/librumpuser: Makefile src/sys/rump/librump: Makefile Added Files: src/lib/librumpuser: rumpuser.3 rumpuser.c rumpuser_dl.c rumpuser_int.h rumpuser_net.c rumpuser_pth.c rumpuser_pth_dummy.c shlib_version Removed Files: src/sys/rump/librump/rumpuser: Makefile rumpuser.3 rumpuser.c rumpuser_dl.c rumpuser_int.h rumpuser_net.c rumpuser_pth.c rumpuser_pth_dummy.c Log Message: librumpuser is not _KERNEL code and does not belong in sys. Move the source files from src/sys/rump/librump/rumpuser to src/lib/librumpuser (from where it is already built). Even so, keep rumpuser.h in sys/rump/include for kernel source tree self-containment. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/lib/librumpuser/Makefile cvs rdiff -u -r0 -r1.1 src/lib/librumpuser/rumpuser.3 \ src/lib/librumpuser/rumpuser.c src/lib/librumpuser/rumpuser_dl.c \ src/lib/librumpuser/rumpuser_int.h src/lib/librumpuser/rumpuser_net.c \ src/lib/librumpuser/rumpuser_pth.c \ src/lib/librumpuser/rumpuser_pth_dummy.c \ src/lib/librumpuser/shlib_version cvs rdiff -u -r1.7 -r1.8 src/sys/rump/librump/Makefile cvs rdiff -u -r1.16 -r0 src/sys/rump/librump/rumpuser/Makefile cvs rdiff -u -r1.1 -r0 src/sys/rump/librump/rumpuser/rumpuser.3 cvs rdiff -u -r1.49 -r0 src/sys/rump/librump/rumpuser/rumpuser.c cvs rdiff -u -r1.12 -r0 src/sys/rump/librump/rumpuser/rumpuser_dl.c cvs rdiff -u -r1.4 -r0 src/sys/rump/librump/rumpuser/rumpuser_int.h cvs rdiff -u -r1.7 -r0 src/sys/rump/librump/rumpuser/rumpuser_net.c cvs rdiff -u -r1.40 -r0 src/sys/rump/librump/rumpuser/rumpuser_pth.c cvs rdiff -u -r1.8 -r0 src/sys/rump/librump/rumpuser/rumpuser_pth_dummy.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/librumpuser/Makefile diff -u src/lib/librumpuser/Makefile:1.1 src/lib/librumpuser/Makefile:1.2 --- src/lib/librumpuser/Makefile:1.1 Tue Jul 29 13:17:41 2008 +++ src/lib/librumpuser/Makefile Fri Feb 26 18:54:20 2010 @@ -1,9 +1,24 @@ -# $NetBSD: Makefile,v 1.1 2008/07/29 13:17:41 pooka Exp $ +# $NetBSD: Makefile,v 1.2 2010/02/26 18:54:20 pooka Exp $ # -.PATH: ${.CURDIR}/../../sys/rump/librump/rumpuser +WARNS= 4 +# rumpuser.h is in sys/rump for inclusion by kernel components +.PATH: ${.CURDIR}/../../sys/rump/include/rump + +LIB= rumpuser LIBDPLIBS+= pthread ${.CURDIR}/../libpthread + +SRCS= rumpuser.c rumpuser_net.c +SRCS+= rumpuser_pth.c +SRCS+= rumpuser_dl.c + +INCSDIR= /usr/include/rump +INCS= rumpuser.h + MAN= rumpuser.3 -.include "${.CURDIR}/../../sys/rump/librump/rumpuser/Makefile" +CPPFLAGS+= -D_REENTRANT + + +.include <bsd.lib.mk> Index: src/sys/rump/librump/Makefile diff -u src/sys/rump/librump/Makefile:1.7 src/sys/rump/librump/Makefile:1.8 --- src/sys/rump/librump/Makefile:1.7 Tue Nov 17 15:36:28 2009 +++ src/sys/rump/librump/Makefile Fri Feb 26 18:54:20 2010 @@ -1,11 +1,7 @@ -# $NetBSD: Makefile,v 1.7 2009/11/17 15:36:28 pooka Exp $ +# $NetBSD: Makefile,v 1.8 2010/02/26 18:54:20 pooka Exp $ # SUBDIR= rumpkern -.if !defined(NORUMPUSER) -SUBDIR+= rumpuser -.endif - SUBDIR+= rumpcrypto rumpdev rumpnet rumpvfs .include <bsd.subdir.mk> Added files: Index: src/lib/librumpuser/rumpuser.3 diff -u /dev/null src/lib/librumpuser/rumpuser.3:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser.3 Fri Feb 26 18:54:20 2010 @@ -0,0 +1,50 @@ +.\" $NetBSD: rumpuser.3,v 1.1 2010/02/26 18:54:20 pooka Exp $ +.\" +.\" Copyright (c) 2008 Antti Kantee. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 28, 2008 +.Dt RUMPUSER 3 +.Os +.Sh NAME +.Nm rumpuser +.Nd rump user namespace helper routines +.Sh LIBRARY +rump User Library (librumpuser, \-lrumpuser) +.Sh SYNOPSIS +.In rump/rumpuser.h +.Sh DESCRIPTION +.Nm +is a user namespace helper library for runnable userspace meta programs. +From rump emulation code compiled with +.Dv -D_KERNEL +is it not possible to directly call routines such as system calls +for reading and writing files or devices. +This is where +.Nm +comes into play by providing a bridge between the two namespaces. +Another example of its services is a way to call pthread routines, +used for emulating kernel threads and synchronization mechanisms +in rump. +.Sh SEE ALSO +.Xr rump 3 Index: src/lib/librumpuser/rumpuser.c diff -u /dev/null src/lib/librumpuser/rumpuser.c:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser.c Fri Feb 26 18:54:20 2010 @@ -0,0 +1,573 @@ +/* $NetBSD: rumpuser.c,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: rumpuser.c,v 1.1 2010/02/26 18:54:20 pooka Exp $"); +#endif /* !lint */ + +/* thank the maker for this */ +#ifdef __linux__ +#define _XOPEN_SOURCE 500 +#define _BSD_SOURCE +#define _FILE_OFFSET_BITS 64 +#include <features.h> +#endif + +#include <sys/param.h> +#include <sys/event.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/uio.h> + +#ifdef __NetBSD__ +#include <sys/disklabel.h> +#endif + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +int +rumpuser_getfileinfo(const char *path, uint64_t *sizep, int *ftp, int *error) +{ + struct stat sb; + uint64_t size; + int needsdev = 0, rv = 0, ft; + + if (stat(path, &sb) == -1) { + *error = errno; + return -1; + } + + switch (sb.st_mode & S_IFMT) { + case S_IFDIR: + ft = RUMPUSER_FT_DIR; + break; + case S_IFREG: + ft = RUMPUSER_FT_REG; + break; + case S_IFBLK: + ft = RUMPUSER_FT_BLK; + needsdev = 1; + break; + case S_IFCHR: + ft = RUMPUSER_FT_CHR; + needsdev = 1; + break; + default: + ft = RUMPUSER_FT_OTHER; + break; + } + + if (!needsdev) { + size = sb.st_size; + } else if (sizep) { + /* + * Welcome to the jungle. Of course querying the kernel + * for a device partition size is supposed to be far from + * trivial. On NetBSD we use ioctl. On $other platform + * we have a problem. We try "the lseek trick" and just + * fail if that fails. Platform specific code can later + * be written here if appropriate. + * + * On NetBSD we hope and pray that for block devices nobody + * else is holding them open, because otherwise the kernel + * will not permit us to open it. Thankfully, this is + * usually called only in bootstrap and then we can + * forget about it. + */ +#ifndef __NetBSD__ + off_t off; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) { + *error = errno; + rv = -1; + goto out; + } + + off = lseek(fd, 0, SEEK_END); + close(fd); + if (off != 0) { + size = off; + goto out; + } + fprintf(stderr, "error: device size query not implemented on " + "this platform\n"); + *error = EOPNOTSUPP; + rv = -1; + goto out; +#else + struct disklabel lab; + struct partition *parta; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) { + *error = errno; + rv = -1; + goto out; + } + + if (ioctl(fd, DIOCGDINFO, &lab) == -1) { + *error = errno; + rv = -1; + goto out; + } + close(fd); + + parta = &lab.d_partitions[DISKPART(sb.st_rdev)]; + size = (uint64_t)lab.d_secsize * parta->p_size; +#endif /* __NetBSD__ */ + } + + out: + if (rv == 0 && sizep) + *sizep = size; + if (rv == 0 && ftp) + *ftp = ft; + + return rv; +} + +int +rumpuser_nanosleep(uint64_t *sec, uint64_t *nsec, int *error) +{ + struct timespec rqt, rmt; + int rv; + + /*LINTED*/ + rqt.tv_sec = *sec; + /*LINTED*/ + rqt.tv_nsec = *nsec; + + KLOCK_WRAP(rv = nanosleep(&rqt, &rmt)); + if (rv == -1) + *error = errno; + + *sec = rmt.tv_sec; + *nsec = rmt.tv_nsec; + + return rv; +} + +void * +rumpuser__malloc(size_t howmuch, int canfail, const char *func, int line) +{ + void *rv; + + rv = malloc(howmuch); + if (rv == NULL && canfail == 0) { + warn("malloc failed %s (%d)", func, line); + abort(); + } + + return rv; +} + +void * +rumpuser__realloc(void *ptr, size_t howmuch, int canfail, + const char *func, int line) +{ + void *rv; + + rv = realloc(ptr, howmuch); + if (rv == NULL && canfail == 0) { + warn("realloc failed %s (%d)", func, line); + abort(); + } + + return rv; +} + +void +rumpuser_free(void *ptr) +{ + + free(ptr); +} + +void * +rumpuser_anonmmap(size_t size, int alignbit, int exec, int *error) +{ + void *rv; + int prot; + + prot = PROT_READ|PROT_WRITE; + if (exec) + prot |= PROT_EXEC; + /* XXX: MAP_ALIGNED() is not portable */ + rv = mmap(NULL, size, prot, MAP_ANON | MAP_ALIGNED(alignbit), -1, 0); + if (rv == MAP_FAILED) { + *error = errno; + return NULL; + } + return rv; +} + +void +rumpuser_unmap(void *addr, size_t len) +{ + int rv; + + rv = munmap(addr, len); + assert(rv == 0); +} + +void * +rumpuser_filemmap(int fd, off_t offset, size_t len, int flags, int *error) +{ + void *rv; + int mmflags, prot; + + if (flags & RUMPUSER_FILEMMAP_TRUNCATE) + ftruncate(fd, offset + len); + + mmflags = MAP_FILE; + if (flags & RUMPUSER_FILEMMAP_SHARED) + mmflags |= MAP_SHARED; + else + mmflags |= MAP_PRIVATE; + + prot = 0; + if (flags & RUMPUSER_FILEMMAP_READ) + prot |= PROT_READ; + if (flags & RUMPUSER_FILEMMAP_WRITE) + prot |= PROT_WRITE; + + rv = mmap(NULL, len, PROT_READ|PROT_WRITE, mmflags, fd, offset); + if (rv == MAP_FAILED) { + *error = errno; + return NULL; + } + + *error = 0; + return rv; +} + +int +rumpuser_memsync(void *addr, size_t len, int *error) +{ + + DOCALL_KLOCK(int, (msync(addr, len, MS_SYNC))); +} + +int +rumpuser_open(const char *path, int flags, int *error) +{ + + DOCALL(int, (open(path, flags, 0644))); +} + +int +rumpuser_ioctl(int fd, u_long cmd, void *data, int *error) +{ + + DOCALL_KLOCK(int, (ioctl(fd, cmd, data))); +} + +int +rumpuser_close(int fd, int *error) +{ + + DOCALL(int, close(fd)); +} + +int +rumpuser_fsync(int fd, int *error) +{ + + DOCALL_KLOCK(int, fsync(fd)); +} + +ssize_t +rumpuser_read(int fd, void *data, size_t size, int *error) +{ + ssize_t rv; + + KLOCK_WRAP(rv = read(fd, data, size)); + if (rv == -1) + *error = errno; + + return rv; +} + +ssize_t +rumpuser_pread(int fd, void *data, size_t size, off_t offset, int *error) +{ + ssize_t rv; + + KLOCK_WRAP(rv = pread(fd, data, size, offset)); + if (rv == -1) + *error = errno; + + return rv; +} + +void +rumpuser_read_bio(int fd, void *data, size_t size, off_t offset, + rump_biodone_fn biodone, void *biodonecookie) +{ + ssize_t rv; + int error = 0; + + rv = rumpuser_pread(fd, data, size, offset, &error); + /* check against <0 instead of ==-1 to get typing below right */ + if (rv < 0) + rv = 0; + + /* LINTED: see above */ + biodone(biodonecookie, rv, error); +} + +ssize_t +rumpuser_write(int fd, const void *data, size_t size, int *error) +{ + ssize_t rv; + + KLOCK_WRAP(rv = write(fd, data, size)); + if (rv == -1) + *error = errno; + + return rv; +} + +ssize_t +rumpuser_pwrite(int fd, const void *data, size_t size, off_t offset, int *error) +{ + ssize_t rv; + + KLOCK_WRAP(rv = pwrite(fd, data, size, offset)); + if (rv == -1) + *error = errno; + + return rv; +} + +void +rumpuser_write_bio(int fd, const void *data, size_t size, off_t offset, + rump_biodone_fn biodone, void *biodonecookie) +{ + ssize_t rv; + int error = 0; + + rv = rumpuser_pwrite(fd, data, size, offset, &error); + /* check against <0 instead of ==-1 to get typing below right */ + if (rv < 0) + rv = 0; + + /* LINTED: see above */ + biodone(biodonecookie, rv, error); +} + +ssize_t +rumpuser_readv(int fd, const struct rumpuser_iovec *riov, int iovcnt, + int *error) +{ + struct iovec *iovp; + ssize_t rv; + int i; + + iovp = malloc(iovcnt * sizeof(struct iovec)); + if (iovp == NULL) { + *error = ENOMEM; + return -1; + } + for (i = 0; i < iovcnt; i++) { + iovp[i].iov_base = riov[i].iov_base; + /*LINTED*/ + iovp[i].iov_len = riov[i].iov_len; + } + + KLOCK_WRAP(rv = readv(fd, iovp, iovcnt)); + if (rv == -1) + *error = errno; + free(iovp); + + return rv; +} + +ssize_t +rumpuser_writev(int fd, const struct rumpuser_iovec *riov, int iovcnt, + int *error) +{ + struct iovec *iovp; + ssize_t rv; + int i; + + iovp = malloc(iovcnt * sizeof(struct iovec)); + if (iovp == NULL) { + *error = ENOMEM; + return -1; + } + for (i = 0; i < iovcnt; i++) { + iovp[i].iov_base = riov[i].iov_base; + /*LINTED*/ + iovp[i].iov_len = riov[i].iov_len; + } + + KLOCK_WRAP(rv = writev(fd, iovp, iovcnt)); + if (rv == -1) + *error = errno; + free(iovp); + + return rv; +} + +int +rumpuser_gettime(uint64_t *sec, uint64_t *nsec, int *error) +{ + struct timeval tv; + int rv; + + rv = gettimeofday(&tv, NULL); + if (rv == -1) { + *error = errno; + return rv; + } + + *sec = tv.tv_sec; + *nsec = tv.tv_usec * 1000; + + return 0; +} + +int +rumpuser_getenv(const char *name, char *buf, size_t blen, int *error) +{ + + DOCALL(int, getenv_r(name, buf, blen)); +} + +int +rumpuser_gethostname(char *name, size_t namelen, int *error) +{ + + DOCALL(int, (gethostname(name, namelen))); +} + +int +rumpuser_poll(struct pollfd *fds, int nfds, int timeout, int *error) +{ + + DOCALL_KLOCK(int, (poll(fds, (nfds_t)nfds, timeout))); +} + +int +rumpuser_putchar(int c, int *error) +{ + + DOCALL(int, (putchar(c))); +} + +void +rumpuser_exit(int rv) +{ + + if (rv == RUMPUSER_PANIC) + abort(); + else + exit(rv); +} + +void +rumpuser_seterrno(int error) +{ + + errno = error; +} + +int +rumpuser_writewatchfile_setup(int kq, int fd, intptr_t opaque, int *error) +{ + struct kevent kev; + + if (kq == -1) { + kq = kqueue(); + if (kq == -1) { + *error = errno; + return -1; + } + } + + EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, + NOTE_WRITE, 0, opaque); + if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) { + *error = errno; + return -1; + } + + return kq; +} + +int +rumpuser_writewatchfile_wait(int kq, intptr_t *opaque, int *error) +{ + struct kevent kev; + int rv; + + KLOCK_WRAP(rv = kevent(kq, NULL, 0, &kev, 1, NULL)); + if (rv == -1) { + *error = errno; + return -1; + } + + if (opaque) + *opaque = kev.udata; + return rv; +} + +/* + * This is meant for safe debugging prints from the kernel. + */ +int +rumpuser_dprintf(const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vprintf(format, ap); + va_end(ap); + + return rv; +} Index: src/lib/librumpuser/rumpuser_dl.c diff -u /dev/null src/lib/librumpuser/rumpuser_dl.c:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser_dl.c Fri Feb 26 18:54:20 2010 @@ -0,0 +1,413 @@ +/* $NetBSD: rumpuser_dl.c,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2009 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Load all module link sets and feed symbol table to the kernel. + * Called during rump bootstrap. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: rumpuser_dl.c,v 1.1 2010/02/26 18:54:20 pooka Exp $"); + +#include <sys/types.h> +#include <sys/time.h> + +#include <assert.h> +#include <dlfcn.h> +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <link.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rumpuser.h> + +#if defined(__ELF__) && (defined(__NetBSD__) || defined(__FreeBSD__) \ + || (defined(__sun__) && defined(__svr4__))) +static size_t symtabsize = 0, strtabsize = 0; +static size_t symtaboff = 0, strtaboff = 0; +static uint8_t *symtab = NULL; +static char *strtab = NULL; +static unsigned char eident; + +static void * +reservespace(void *store, size_t *storesize, + size_t storeoff, size_t required) +{ + size_t chunk, newsize; + + assert(storeoff <= *storesize); + chunk = *storesize - storeoff; + + if (chunk >= required) + return store; + + newsize = *storesize + ((size_t)required - chunk); + store = realloc(store, newsize); + if (store == NULL) { + return NULL; + } + *((uint8_t *)store + storeoff) = '\0'; + *storesize = newsize; + + return store; +} + +/* + * Macros to make handling elf32/64 in the code a little saner. + */ + +#define EHDR_GETMEMBER(base, thevar, result) \ +do { \ + if (eident == ELFCLASS32) { \ + Elf32_Ehdr *ehdr = base; \ + /*LINTED*/ \ + result = ehdr->thevar; \ + } else { \ + Elf64_Ehdr *ehdr = base; \ + /*LINTED*/ \ + result = ehdr->thevar; \ + } \ +} while (/*CONSTCOND*/0) + +#define SHDRn_GETMEMBER(base, n, thevar, result) \ +do { \ + if (eident == ELFCLASS32) { \ + Elf32_Shdr *shdr = base; \ + /*LINTED*/ \ + result = shdr[n].thevar; \ + } else { \ + Elf64_Shdr *shdr = base; \ + /*LINTED*/ \ + result = shdr[n].thevar; \ + } \ +} while (/*CONSTCOND*/0) + +#define DYNn_GETMEMBER(base, n, thevar, result) \ +do { \ + if (eident == ELFCLASS32) { \ + Elf32_Dyn *dyn = base; \ + /*LINTED*/ \ + result = dyn[n].thevar; \ + } else { \ + Elf64_Dyn *dyn = base; \ + /*LINTED*/ \ + result = dyn[n].thevar; \ + } \ +} while (/*CONSTCOND*/0) + +#define SYMn_GETMEMBER(base, n, thevar, result) \ +do { \ + if (eident == ELFCLASS32) { \ + Elf32_Sym *sym = base; \ + /*LINTED*/ \ + result = sym[n].thevar; \ + } else { \ + Elf64_Sym *sym = base; \ + /*LINTED*/ \ + result = sym[n].thevar; \ + } \ +} while (/*CONSTCOND*/0) + +#define SYMn_SETMEMBER(base, n, thevar, value) \ +do { \ + if (eident == ELFCLASS32) { \ + Elf32_Sym *sym = base; \ + /*LINTED*/ \ + sym[n].thevar = value; \ + } else { \ + Elf64_Sym *sym = base; \ + /*LINTED*/ \ + sym[n].thevar = value; \ + } \ +} while (/*CONSTCOND*/0) + +#define SYM_GETSIZE() ((eident==ELFCLASS32)?sizeof(Elf32_Sym):sizeof(Elf64_Sym)) + +static int +getsymbols(struct link_map *map) +{ + void *libbase = map->l_addr; + int i = 0, fd; + char *str_base; + void *syms_base = NULL; /* XXXgcc */ + size_t cursymsize, curstrsize; + void *shdr_base; + size_t shsize; + int shnum; + uint64_t shoff; + void *ed_base; + uint64_t ed_tag; + int sverrno; + + if (memcmp(libbase, ELFMAG, SELFMAG) != 0) + return ENOEXEC; + eident = *(unsigned char *)(map->l_addr + EI_CLASS); + if (eident != ELFCLASS32 && eident != ELFCLASS64) + return ENOEXEC; + + /* read the section headers from disk to determine size of dynsym */ + fd = open(map->l_name, O_RDONLY); + if (fd == -1) { + sverrno = errno; + fprintf(stderr, "open %s failed\n", map->l_name); + return sverrno; + } + + EHDR_GETMEMBER(libbase, e_shnum, shnum); + EHDR_GETMEMBER(libbase, e_shentsize, shsize); + EHDR_GETMEMBER(libbase, e_shoff, shoff); + shdr_base = malloc(shnum * shsize); + if (pread(fd, shdr_base, shnum * shsize, (off_t)shoff) + != (ssize_t)(shnum*shsize)){ + sverrno = errno; + fprintf(stderr, "read section headers for %s failed\n", + map->l_name); + free(shdr_base); + close(fd); + return sverrno; + } + cursymsize = (size_t)-1; + for (i = 1; i <= shnum; i++) { + int shtype; + + SHDRn_GETMEMBER(shdr_base, i, sh_type, shtype); + if (shtype != SHT_DYNSYM) + continue; + SHDRn_GETMEMBER(shdr_base, i, sh_size, cursymsize); + break; + } + free(shdr_base); + close(fd); + if (cursymsize == (size_t)-1) { + fprintf(stderr, "could not find dynsym size from %s\n", + map->l_name); + return ENOEXEC; + } + + /* find symtab, strtab and strtab size */ + str_base = NULL; + curstrsize = (size_t)-1; + ed_base = map->l_ld; + i = 0; + DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag); + while (ed_tag != DT_NULL) { + uintptr_t edptr; + size_t edval; + + switch (ed_tag) { + case DT_SYMTAB: + DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr); + syms_base = map->l_addr + edptr; + break; + case DT_STRTAB: + DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr); + str_base = map->l_addr + edptr; + break; + case DT_STRSZ: + DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval); + curstrsize = edval; + break; + default: + break; + } + i++; + DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag); + } while (ed_tag != DT_NULL); + + if (str_base == NULL || syms_base == NULL || curstrsize == (size_t)-1) { + fprintf(stderr, "could not find strtab, symtab or strtab size " + "in %s\n", map->l_name); + return ENOEXEC; + } + + /* + * Make sure we have enough space for the contents of the symbol + * and string tables we are currently processing. The total used + * space will be smaller due to undefined symbols we are not + * interested in. + */ + symtab = reservespace(symtab, &symtabsize, symtaboff, cursymsize); + strtab = reservespace(strtab, &strtabsize, strtaboff, curstrsize); + if (symtab == NULL || strtab == NULL) { + fprintf(stderr, "failed to reserve memory"); + return ENOMEM; + } + + /* iterate over all symbols in current symtab */ + for (i = 0; i * SYM_GETSIZE() < cursymsize; i++) { + char *cursymname; + int shndx, name; + uintptr_t value; + void *csym; + + SYMn_GETMEMBER(syms_base, i, st_shndx, shndx); + SYMn_GETMEMBER(syms_base, i, st_value, value); + if (shndx == SHN_UNDEF || value == 0) + continue; + + /* get symbol name */ + SYMn_GETMEMBER(syms_base, i, st_name, name); + cursymname = name + str_base; + memcpy(symtab + symtaboff, + (uint8_t *)syms_base + i*SYM_GETSIZE(), SYM_GETSIZE()); + + /* + * set name to point at new strtab, offset symbol value + * with lib base address. + */ + csym = symtab + symtaboff; + SYMn_SETMEMBER(csym, 0, st_name, strtaboff); + SYMn_GETMEMBER(csym, 0, st_value, value); + SYMn_SETMEMBER(csym, 0, st_value,(intptr_t)(value+map->l_addr)); + symtaboff += SYM_GETSIZE(); + + strcpy(strtab + strtaboff, cursymname); + strtaboff += strlen(cursymname)+1; + } + + return 0; +} + +static int +process(const char *soname, rump_modinit_fn domodinit) +{ + void *handle; + struct modinfo **mi, **mi_end; + int loaded = 0; + + if (strstr(soname, "librump") == NULL) + return 0; + + handle = dlopen(soname, RTLD_LAZY); + if (handle == NULL) + return 0; + + mi = dlsym(handle, "__start_link_set_modules"); + if (!mi) + goto out; + mi_end = dlsym(handle, "__stop_link_set_modules"); + if (!mi_end) + goto out; + + for (; mi < mi_end; mi++) + if (domodinit(*mi, NULL) == 0) + loaded = 1; + assert(mi == mi_end); + + out: + dlclose(handle); + return loaded; +} + +/* + * Get the linkmap from the dynlinker. Try to load kernel modules + * from all objects in the linkmap. + */ +void +rumpuser_dl_bootstrap(rump_modinit_fn domodinit, + rump_symload_fn symload) +{ + struct link_map *map, *origmap; + int couldload; + int error; + + if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &origmap) == -1) { + fprintf(stderr, "warning: rumpuser module bootstrap " + "failed: %s\n", dlerror()); + return; + } + /* + * Process last->first because that's the most probable + * order for dependencies + */ + for (; origmap->l_next; origmap = origmap->l_next) + continue; + + /* + * Build symbol table to hand to the rump kernel. Do this by + * iterating over all rump libraries and collecting symbol + * addresses and relocation info. + */ + error = 0; + for (map = origmap; map && !error; map = map->l_prev) { + if (map->l_addr == NULL) + continue; + if (strstr(map->l_name, "librump") != NULL) + error = getsymbols(map); + } + + if (error == 0) { + void *trimmedsym, *trimmedstr; + + /* + * Allocate optimum-sized memory for storing tables + * and feed to kernel. If memory allocation fails, + * just give the ones with extra context (although + * I'm pretty sure we'll die moments later due to + * memory running out). + */ + if ((trimmedsym = malloc(symtaboff)) != NULL) { + memcpy(trimmedsym, symtab, symtaboff); + } else { + trimmedsym = symtab; + symtab = NULL; + } + if ((trimmedstr = malloc(strtaboff)) != NULL) { + memcpy(trimmedstr, strtab, strtaboff); + } else { + trimmedstr = strtab; + strtab = NULL; + } + symload(trimmedsym, symtaboff, trimmedstr, strtaboff); + } + free(symtab); + free(strtab); + + /* + * Next, load modules from dynlibs. + */ + do { + couldload = 0; + map = origmap; + for (; map; map = map->l_prev) + if (process(map->l_name, domodinit)) + couldload = 1; + } while (couldload); +} +#else +void +rumpuser_dl_bootstrap(rump_modinit_fn domodinit, + rump_symload_fn symload) +{ + + fprintf(stderr, "Warning, dlinfo() unsupported on host?\n"); +} +#endif Index: src/lib/librumpuser/rumpuser_int.h diff -u /dev/null src/lib/librumpuser/rumpuser_int.h:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser_int.h Fri Feb 26 18:54:20 2010 @@ -0,0 +1,61 @@ +/* $NetBSD: rumpuser_int.h,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2008 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <rump/rumpuser.h> + +extern kernel_lockfn rumpuser__klock; +extern kernel_unlockfn rumpuser__kunlock; +extern int rumpuser__wantthreads; + +#define KLOCK_WRAP(a) \ +do { \ + int nlocks; \ + rumpuser__kunlock(0, &nlocks); \ + a; \ + rumpuser__klock(nlocks); \ +} while (/*CONSTCOND*/0) + +#define DOCALL(rvtype, call) \ + rvtype rv; \ + rv = call; \ + if (rv == -1) \ + *error = errno; \ + else \ + *error = 0; \ + return rv; + +#define DOCALL_KLOCK(rvtype, call) \ + rvtype rv; \ + int nlocks; \ + rumpuser__kunlock(0, &nlocks); \ + rv = call; \ + rumpuser__klock(nlocks); \ + if (rv == -1) \ + *error = errno; \ + else \ + *error = 0; \ + return rv; Index: src/lib/librumpuser/rumpuser_net.c diff -u /dev/null src/lib/librumpuser/rumpuser_net.c:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser_net.c Fri Feb 26 18:54:20 2010 @@ -0,0 +1,125 @@ +/* $NetBSD: rumpuser_net.c,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2008 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: rumpuser_net.c,v 1.1 2010/02/26 18:54:20 pooka Exp $"); +#endif /* !lint */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +int +rumpuser_net_socket(int domain, int type, int proto, int *error) +{ + + DOCALL_KLOCK(int, (socket(domain, type, proto))); +} + +int +rumpuser_net_sendmsg(int s, const struct msghdr *msg, int flags, int *error) +{ + + DOCALL_KLOCK(ssize_t, (sendmsg(s, msg, flags))); +} + +int +rumpuser_net_recvmsg(int s, struct msghdr *msg, int flags, int *error) +{ + + DOCALL_KLOCK(ssize_t, (recvmsg(s, msg, flags))); +} + +int +rumpuser_net_connect(int s, const struct sockaddr *name, int len, int *error) +{ + + DOCALL_KLOCK(int, (connect(s, name, (socklen_t)len))); +} + +int +rumpuser_net_bind(int s, const struct sockaddr *name, int len, int *error) +{ + + DOCALL_KLOCK(int, (bind(s, name, (socklen_t)len))); +} + +int +rumpuser_net_accept(int s, struct sockaddr *name, int *lenp, int *error) +{ + + DOCALL_KLOCK(int, (accept(s, name, (socklen_t *)lenp))); +} + +int +rumpuser_net_listen(int s, int backlog, int *error) +{ + + DOCALL_KLOCK(int, (listen(s, backlog))); +} + +int +rumpuser_net_getname(int s, struct sockaddr *so, int *lenp, + enum rumpuser_getnametype which, int *error) +{ + socklen_t slen = *lenp; + int rv; + + if (which == RUMPUSER_SOCKNAME) + rv = getsockname(s, so, &slen); + else + rv = getpeername(s, so, &slen); + + *lenp = slen; + if (rv == -1) + *error = errno; + else + *error = 0; + + return rv; +} + +int +rumpuser_net_setsockopt(int s, int level, int name, + const void *data, int dlen, int *error) +{ + socklen_t slen = dlen; + int rv; + + rv = setsockopt(s, level, name, data, slen); + if (rv == -1) + *error = errno; + else + *error = 0; + return rv; +} Index: src/lib/librumpuser/rumpuser_pth.c diff -u /dev/null src/lib/librumpuser/rumpuser_pth.c:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser_pth.c Fri Feb 26 18:54:20 2010 @@ -0,0 +1,526 @@ +/* $NetBSD: rumpuser_pth.c,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: rumpuser_pth.c,v 1.1 2010/02/26 18:54:20 pooka Exp $"); +#endif /* !lint */ + +#ifdef __linux__ +#define _XOPEN_SOURCE 500 +#define _BSD_SOURCE +#define _FILE_OFFSET_BITS 64 +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +static pthread_key_t curlwpkey; + +#define NOFAIL(a) do {if (!(a)) abort();} while (/*CONSTCOND*/0) +#define NOFAIL_ERRNO(a) \ +do { \ + int fail_rv = (a); \ + if (fail_rv) { \ + printf("panic: rumpuser fatal failure %d (%s)\n", \ + fail_rv, strerror(fail_rv)); \ + abort(); \ + } \ +} while (/*CONSTCOND*/0) + +#define RUMTX_INCRECURSION(mtx) ((mtx)->recursion++) +#define RUMTX_DECRECURSION(mtx) ((mtx)->recursion--) +struct rumpuser_mtx { + pthread_mutex_t pthmtx; + pthread_t owner; + unsigned recursion; +}; + +#define RURW_AMWRITER(rw) (pthread_equal(rw->writer, pthread_self()) \ + && rw->readers == -1) +#define RURW_HASREAD(rw) (rw->readers > 0) + +#define RURW_SETWRITE(rw) \ +do { \ + assert(rw->readers == 0); \ + rw->writer = pthread_self(); \ + rw->readers = -1; \ +} while (/*CONSTCOND*/0) +#define RURW_CLRWRITE(rw) \ +do { \ + assert(rw->readers == -1 && RURW_AMWRITER(rw)); \ + rw->readers = 0; \ +} while (/*CONSTCOND*/0) +#define RURW_INCREAD(rw) \ +do { \ + pthread_spin_lock(&rw->spin); \ + assert(rw->readers >= 0); \ + ++(rw)->readers; \ + pthread_spin_unlock(&rw->spin); \ +} while (/*CONSTCOND*/0) +#define RURW_DECREAD(rw) \ +do { \ + pthread_spin_lock(&rw->spin); \ + assert(rw->readers > 0); \ + --(rw)->readers; \ + pthread_spin_unlock(&rw->spin); \ +} while (/*CONSTCOND*/0) + +struct rumpuser_rw { + pthread_rwlock_t pthrw; + pthread_spinlock_t spin; + int readers; + pthread_t writer; +}; + +struct rumpuser_cv { + pthread_cond_t pthcv; + int nwaiters; +}; + +struct rumpuser_mtx rumpuser_aio_mtx; +struct rumpuser_cv rumpuser_aio_cv; +int rumpuser_aio_head, rumpuser_aio_tail; +struct rumpuser_aio rumpuser_aios[N_AIOS]; + +kernel_lockfn rumpuser__klock; +kernel_unlockfn rumpuser__kunlock; +int rumpuser__wantthreads; + +void +/*ARGSUSED*/ +rumpuser_biothread(void *arg) +{ + struct rumpuser_aio *rua; + rump_biodone_fn biodone = arg; + ssize_t rv; + int error, dummy; + + /* unschedule from CPU. we reschedule before running the interrupt */ + rumpuser__kunlock(0, &dummy); + assert(dummy == 0); + + NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx.pthmtx)); + for (;;) { + while (rumpuser_aio_head == rumpuser_aio_tail) { + NOFAIL_ERRNO(pthread_cond_wait(&rumpuser_aio_cv.pthcv, + &rumpuser_aio_mtx.pthmtx)); + } + + rua = &rumpuser_aios[rumpuser_aio_tail]; + assert(rua->rua_bp != NULL); + pthread_mutex_unlock(&rumpuser_aio_mtx.pthmtx); + + if (rua->rua_op & RUA_OP_READ) { + error = 0; + rv = pread(rua->rua_fd, rua->rua_data, + rua->rua_dlen, rua->rua_off); + if (rv < 0) { + rv = 0; + error = errno; + } + } else { + error = 0; + rv = pwrite(rua->rua_fd, rua->rua_data, + rua->rua_dlen, rua->rua_off); + if (rv < 0) { + rv = 0; + error = errno; + } else if (rua->rua_op & RUA_OP_SYNC) { +#ifdef __NetBSD__ + fsync_range(rua->rua_fd, FDATASYNC, + rua->rua_off, rua->rua_dlen); +#else + fsync(rua->rua_fd); +#endif + } + } + rumpuser__klock(0); + biodone(rua->rua_bp, (size_t)rv, error); + rumpuser__kunlock(0, &dummy); + + rua->rua_bp = NULL; + + NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx.pthmtx)); + rumpuser_aio_tail = (rumpuser_aio_tail+1) % N_AIOS; + pthread_cond_signal(&rumpuser_aio_cv.pthcv); + } + + /*NOTREACHED*/ + fprintf(stderr, "error: rumpuser_biothread reached unreachable\n"); + abort(); +} + +void +rumpuser_thrinit(kernel_lockfn lockfn, kernel_unlockfn unlockfn, int threads) +{ + + pthread_mutex_init(&rumpuser_aio_mtx.pthmtx, NULL); + pthread_cond_init(&rumpuser_aio_cv.pthcv, NULL); + + pthread_key_create(&curlwpkey, NULL); + + rumpuser__klock = lockfn; + rumpuser__kunlock = unlockfn; + rumpuser__wantthreads = threads; +} + +#if 0 +void +rumpuser__thrdestroy(void) +{ + + pthread_key_delete(curlwpkey); +} +#endif + +int +rumpuser_thread_create(void *(*f)(void *), void *arg, const char *thrname) +{ + pthread_t ptid; + int rv; + + rv = pthread_create(&ptid, NULL, f, arg); +#ifdef __NetBSD__ + if (rv == 0 && thrname) + pthread_setname_np(ptid, thrname, NULL); +#endif + + return rv; +} + +__dead void +rumpuser_thread_exit(void) +{ + + pthread_exit(NULL); +} + +void +rumpuser_mutex_init(struct rumpuser_mtx **mtx) +{ + pthread_mutexattr_t att; + + NOFAIL(*mtx = malloc(sizeof(struct rumpuser_mtx))); + + pthread_mutexattr_init(&att); + pthread_mutexattr_settype(&att, PTHREAD_MUTEX_ERRORCHECK); + NOFAIL_ERRNO(pthread_mutex_init(&((*mtx)->pthmtx), &att)); + pthread_mutexattr_destroy(&att); + + (*mtx)->owner = NULL; + (*mtx)->recursion = 0; +} + +void +rumpuser_mutex_recursive_init(struct rumpuser_mtx **mtx) +{ + pthread_mutexattr_t mattr; + + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + + NOFAIL(*mtx = malloc(sizeof(struct rumpuser_mtx))); + NOFAIL_ERRNO(pthread_mutex_init(&((*mtx)->pthmtx), &mattr)); + (*mtx)->owner = NULL; + (*mtx)->recursion = 0; + + pthread_mutexattr_destroy(&mattr); +} + +static void +mtxenter(struct rumpuser_mtx *mtx) +{ + + if (mtx->recursion++ == 0) { + assert(mtx->owner == NULL); + mtx->owner = pthread_self(); + } else { + assert(pthread_equal(mtx->owner, pthread_self())); + } +} + +static void +mtxexit(struct rumpuser_mtx *mtx) +{ + + assert(mtx->owner != NULL); + if (--mtx->recursion == 0) + mtx->owner = NULL; +} + +void +rumpuser_mutex_enter(struct rumpuser_mtx *mtx) +{ + + if (pthread_mutex_trylock(&mtx->pthmtx) != 0) + KLOCK_WRAP(NOFAIL_ERRNO(pthread_mutex_lock(&mtx->pthmtx))); + mtxenter(mtx); +} + +void +rumpuser_mutex_enter_nowrap(struct rumpuser_mtx *mtx) +{ + + NOFAIL_ERRNO(pthread_mutex_lock(&mtx->pthmtx)); + mtxenter(mtx); +} + +int +rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx) +{ + int rv; + + rv = pthread_mutex_trylock(&mtx->pthmtx); + if (rv == 0) { + mtxenter(mtx); + } + + return rv == 0; +} + +void +rumpuser_mutex_exit(struct rumpuser_mtx *mtx) +{ + + mtxexit(mtx); + NOFAIL_ERRNO(pthread_mutex_unlock(&mtx->pthmtx)); +} + +void +rumpuser_mutex_destroy(struct rumpuser_mtx *mtx) +{ + + NOFAIL_ERRNO(pthread_mutex_destroy(&mtx->pthmtx)); + free(mtx); +} + +int +rumpuser_mutex_held(struct rumpuser_mtx *mtx) +{ + + return mtx->recursion && pthread_equal(mtx->owner, pthread_self()); +} + +void +rumpuser_rw_init(struct rumpuser_rw **rw) +{ + + NOFAIL(*rw = malloc(sizeof(struct rumpuser_rw))); + NOFAIL_ERRNO(pthread_rwlock_init(&((*rw)->pthrw), NULL)); + NOFAIL_ERRNO(pthread_spin_init(&((*rw)->spin), PTHREAD_PROCESS_SHARED)); + (*rw)->readers = 0; + (*rw)->writer = NULL; +} + +void +rumpuser_rw_enter(struct rumpuser_rw *rw, int iswrite) +{ + + if (iswrite) { + if (pthread_rwlock_trywrlock(&rw->pthrw) != 0) + KLOCK_WRAP(NOFAIL_ERRNO( + pthread_rwlock_wrlock(&rw->pthrw))); + RURW_SETWRITE(rw); + } else { + if (pthread_rwlock_tryrdlock(&rw->pthrw) != 0) + KLOCK_WRAP(NOFAIL_ERRNO( + pthread_rwlock_rdlock(&rw->pthrw))); + RURW_INCREAD(rw); + } +} + +int +rumpuser_rw_tryenter(struct rumpuser_rw *rw, int iswrite) +{ + int rv; + + if (iswrite) { + rv = pthread_rwlock_trywrlock(&rw->pthrw); + if (rv == 0) + RURW_SETWRITE(rw); + } else { + rv = pthread_rwlock_tryrdlock(&rw->pthrw); + if (rv == 0) + RURW_INCREAD(rw); + } + + return rv == 0; +} + +void +rumpuser_rw_exit(struct rumpuser_rw *rw) +{ + + if (RURW_HASREAD(rw)) + RURW_DECREAD(rw); + else + RURW_CLRWRITE(rw); + NOFAIL_ERRNO(pthread_rwlock_unlock(&rw->pthrw)); +} + +void +rumpuser_rw_destroy(struct rumpuser_rw *rw) +{ + + NOFAIL_ERRNO(pthread_rwlock_destroy(&rw->pthrw)); + NOFAIL_ERRNO(pthread_spin_destroy(&rw->spin)); + free(rw); +} + +int +rumpuser_rw_held(struct rumpuser_rw *rw) +{ + + return rw->readers != 0; +} + +int +rumpuser_rw_rdheld(struct rumpuser_rw *rw) +{ + + return RURW_HASREAD(rw); +} + +int +rumpuser_rw_wrheld(struct rumpuser_rw *rw) +{ + + return RURW_AMWRITER(rw); +} + +void +rumpuser_cv_init(struct rumpuser_cv **cv) +{ + + NOFAIL(*cv = malloc(sizeof(struct rumpuser_cv))); + NOFAIL_ERRNO(pthread_cond_init(&((*cv)->pthcv), NULL)); + (*cv)->nwaiters = 0; +} + +void +rumpuser_cv_destroy(struct rumpuser_cv *cv) +{ + + NOFAIL_ERRNO(pthread_cond_destroy(&cv->pthcv)); + free(cv); +} + +void +rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx) +{ + + cv->nwaiters++; + assert(mtx->recursion == 1); + mtxexit(mtx); + KLOCK_WRAP(NOFAIL_ERRNO(pthread_cond_wait(&cv->pthcv, &mtx->pthmtx))); + mtxenter(mtx); + cv->nwaiters--; +} + +void +rumpuser_cv_wait_nowrap(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx) +{ + + cv->nwaiters++; + assert(mtx->recursion == 1); + mtxexit(mtx); + NOFAIL_ERRNO(pthread_cond_wait(&cv->pthcv, &mtx->pthmtx)); + mtxenter(mtx); + cv->nwaiters--; +} + +int +rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx, + int64_t sec, int64_t nsec) +{ + struct timespec ts; + int rv; + + /* LINTED */ + ts.tv_sec = sec; ts.tv_nsec = nsec; + + cv->nwaiters++; + mtxexit(mtx); + KLOCK_WRAP(rv = pthread_cond_timedwait(&cv->pthcv, &mtx->pthmtx, &ts)); + mtxenter(mtx); + cv->nwaiters--; + if (rv != 0 && rv != ETIMEDOUT) + abort(); + + return rv == ETIMEDOUT; +} + +void +rumpuser_cv_signal(struct rumpuser_cv *cv) +{ + + NOFAIL_ERRNO(pthread_cond_signal(&cv->pthcv)); +} + +void +rumpuser_cv_broadcast(struct rumpuser_cv *cv) +{ + + NOFAIL_ERRNO(pthread_cond_broadcast(&cv->pthcv)); +} + +int +rumpuser_cv_has_waiters(struct rumpuser_cv *cv) +{ + + return cv->nwaiters; +} + +/* + * curlwp + */ + +void +rumpuser_set_curlwp(struct lwp *l) +{ + + assert(pthread_getspecific(curlwpkey) == NULL || l == NULL); + pthread_setspecific(curlwpkey, l); +} + +struct lwp * +rumpuser_get_curlwp(void) +{ + + return pthread_getspecific(curlwpkey); +} Index: src/lib/librumpuser/rumpuser_pth_dummy.c diff -u /dev/null src/lib/librumpuser/rumpuser_pth_dummy.c:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/rumpuser_pth_dummy.c Fri Feb 26 18:54:20 2010 @@ -0,0 +1,296 @@ +/* $NetBSD: rumpuser_pth_dummy.c,v 1.1 2010/02/26 18:54:20 pooka Exp $ */ + +/* + * Copyright (c) 2009 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: rumpuser_pth_dummy.c,v 1.1 2010/02/26 18:54:20 pooka Exp $"); +#endif /* !lint */ + +#include <sys/time.h> + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +struct rumpuser_cv {}; + +struct rumpuser_mtx { + int v; +}; + +struct rumpuser_rw { + int v; +}; + +struct rumpuser_mtx rumpuser_aio_mtx; +struct rumpuser_cv rumpuser_aio_cv; +int rumpuser_aio_head, rumpuser_aio_tail; +struct rumpuser_aio rumpuser_aios[N_AIOS]; + +void donada(int); +/*ARGSUSED*/ +void donada(int arg) {} +void dounnada(int, int *); +/*ARGSUSED*/ +void dounnada(int arg, int *ap) {} +kernel_lockfn rumpuser__klock = donada; +kernel_unlockfn rumpuser__kunlock = dounnada; + +/*ARGSUSED*/ +void +rumpuser_thrinit(kernel_lockfn lockfn, kernel_unlockfn unlockfn, int threads) +{ + +} + +/*ARGSUSED*/ +void +rumpuser_biothread(void *arg) +{ + + fprintf(stderr, "rumpuser: threads not available\n"); + abort(); +} + +/*ARGSUSED*/ +int +rumpuser_thread_create(void *(*f)(void *), void *arg, const char *thrname) +{ + + fprintf(stderr, "rumpuser: threads not available\n"); + abort(); + return 0; +} + +void +rumpuser_thread_exit(void) +{ + +} + +void +rumpuser_mutex_init(struct rumpuser_mtx **mtx) +{ + + *mtx = calloc(1, sizeof(struct rumpuser_mtx)); +} + +void +rumpuser_mutex_recursive_init(struct rumpuser_mtx **mtx) +{ + + rumpuser_mutex_init(mtx); +} + +void +rumpuser_mutex_enter(struct rumpuser_mtx *mtx) +{ + + mtx->v++; +} + +int +rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx) +{ + + mtx->v++; + return 1; +} + +void +rumpuser_mutex_exit(struct rumpuser_mtx *mtx) +{ + + mtx->v--; +} + +void +rumpuser_mutex_destroy(struct rumpuser_mtx *mtx) +{ + + free(mtx); +} + +int +rumpuser_mutex_held(struct rumpuser_mtx *mtx) +{ + + return mtx->v; +} + +void +rumpuser_rw_init(struct rumpuser_rw **rw) +{ + + *rw = calloc(1, sizeof(struct rumpuser_rw)); +} + +void +rumpuser_rw_enter(struct rumpuser_rw *rw, int write) +{ + + if (write) { + rw->v++; + assert(rw->v == 1); + } else { + assert(rw->v <= 0); + rw->v--; + } +} + +int +rumpuser_rw_tryenter(struct rumpuser_rw *rw, int write) +{ + + rumpuser_rw_enter(rw, write); + return 1; +} + +void +rumpuser_rw_exit(struct rumpuser_rw *rw) +{ + + if (rw->v > 0) { + assert(rw->v == 1); + rw->v--; + } else { + rw->v++; + } +} + +void +rumpuser_rw_destroy(struct rumpuser_rw *rw) +{ + + free(rw); +} + +int +rumpuser_rw_held(struct rumpuser_rw *rw) +{ + + return rw->v != 0; +} + +int +rumpuser_rw_rdheld(struct rumpuser_rw *rw) +{ + + return rw->v < 0; +} + +int +rumpuser_rw_wrheld(struct rumpuser_rw *rw) +{ + + return rw->v > 0; +} + +/*ARGSUSED*/ +void +rumpuser_cv_init(struct rumpuser_cv **cv) +{ + +} + +/*ARGSUSED*/ +void +rumpuser_cv_destroy(struct rumpuser_cv *cv) +{ + +} + +/*ARGSUSED*/ +void +rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx) +{ + +} + +/*ARGSUSED*/ +int +rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx, + int64_t sec, int64_t nsec) +{ + struct timespec ts; + + /*LINTED*/ + ts.tv_sec = sec; + /*LINTED*/ + ts.tv_nsec = nsec; + + nanosleep(&ts, NULL); + return 0; +} + +/*ARGSUSED*/ +void +rumpuser_cv_signal(struct rumpuser_cv *cv) +{ + +} + +/*ARGSUSED*/ +void +rumpuser_cv_broadcast(struct rumpuser_cv *cv) +{ + +} + +/*ARGSUSED*/ +int +rumpuser_cv_has_waiters(struct rumpuser_cv *cv) +{ + + return 0; +} + +/* + * curlwp + */ + +static struct lwp *curlwp; +void +rumpuser_set_curlwp(struct lwp *l) +{ + + curlwp = l; +} + +struct lwp * +rumpuser_get_curlwp(void) +{ + + return curlwp; +} Index: src/lib/librumpuser/shlib_version diff -u /dev/null src/lib/librumpuser/shlib_version:1.1 --- /dev/null Fri Feb 26 18:54:21 2010 +++ src/lib/librumpuser/shlib_version Fri Feb 26 18:54:20 2010 @@ -0,0 +1,4 @@ +# $NetBSD: shlib_version,v 1.1 2010/02/26 18:54:20 pooka Exp $ +# +major=0 +minor=0