Module Name: src Committed By: justin Date: Fri Jul 11 20:26:31 UTC 2014
Modified Files: src/lib/librumpuser: Makefile src/sys/rump: README.compileopts Added Files: src/lib/librumpuser: rumpfiber.c rumpfiber.h rumpfiber_bio.c rumpfiber_sp.c Log Message: Add a fiber based implementation of librumpuser in addition to the default pthreads based version. Discussed with pooka@ To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/lib/librumpuser/Makefile cvs rdiff -u -r0 -r1.1 src/lib/librumpuser/rumpfiber.c \ src/lib/librumpuser/rumpfiber.h src/lib/librumpuser/rumpfiber_bio.c \ src/lib/librumpuser/rumpfiber_sp.c cvs rdiff -u -r1.5 -r1.6 src/sys/rump/README.compileopts 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.19 src/lib/librumpuser/Makefile:1.20 --- src/lib/librumpuser/Makefile:1.19 Wed Jul 9 23:41:40 2014 +++ src/lib/librumpuser/Makefile Fri Jul 11 20:26:31 2014 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.19 2014/07/09 23:41:40 justin Exp $ +# $NetBSD: Makefile,v 1.20 2014/07/11 20:26:31 justin Exp $ # .include <bsd.own.mk> @@ -8,8 +8,13 @@ WARNS?= 5 # rumpuser.h is in sys/rump for inclusion by kernel components .PATH: ${.CURDIR}/../../sys/rump/include/rump +RUMPUSER_THREADS?=pthread + LIB= rumpuser + +.if ${RUMPUSER_THREADS} == "pthread" LIBDPLIBS+= pthread ${.CURDIR}/../libpthread +.endif .for lib in ${RUMPUSER_EXTERNAL_DPLIBS} LIBDO.${lib}= _external LIBDPLIBS+= ${lib} lib @@ -17,15 +22,32 @@ LIBDPLIBS+= ${lib} lib CPPFLAGS+= -DLIBRUMPUSER #CPPFLAGS+= -D_DIAGNOSTIC -SRCS= rumpuser.c -SRCS+= rumpuser_pth.c -SRCS+= rumpuser_component.c rumpuser_bio.c + +.if ${RUMPUSER_THREADS} == "pthread" +SRCS= rumpuser.c rumpuser_pth.c rumpuser_bio.c +SRCS+= rumpuser_sp.c +.elif ${RUMPUSER_THREADS} == "none" +SRCS= rumpuser.c rumpuser_pth_dummy.c rumpuser_bio.c +SRCS+= rumpuser_sp.c +.elif ${RUMPUSER_THREADS} == "fiber" +.if defined(RUMP_CURLWP) +.if ${RUMP_CURLWP} != "hypercall" +.error Unsupported curlwp scheme for thread model: ${RUMP_CURLWP} +.endif +.endif +SRCS= rumpfiber.c rumpfiber_bio.c +SRCS+= rumpfiber_sp.c +.else +.error Unsupported rumpuser threading type: ${RUMPUSER_THREADS} +.endif + +SRCS+= rumpuser_component.c SRCS+= rumpuser_file.c rumpuser_mem.c SRCS+= rumpuser_errtrans.c rumpuser_sigtrans.c # optional -SRCS+= rumpuser_dl.c rumpuser_sp.c rumpuser_daemonize.c +SRCS+= rumpuser_dl.c rumpuser_daemonize.c INCSDIR= /usr/include/rump INCS= rumpuser.h rumpuser_component.h rumpuser_port.h @@ -34,5 +56,4 @@ MAN= rumpuser.3 CPPFLAGS+= -D_REENTRANT - .include <bsd.lib.mk> Index: src/sys/rump/README.compileopts diff -u src/sys/rump/README.compileopts:1.5 src/sys/rump/README.compileopts:1.6 --- src/sys/rump/README.compileopts:1.5 Fri Jun 20 12:36:31 2014 +++ src/sys/rump/README.compileopts Fri Jul 11 20:26:31 2014 @@ -1,4 +1,4 @@ - $NetBSD: README.compileopts,v 1.5 2014/06/20 12:36:31 pooka Exp $ + $NetBSD: README.compileopts,v 1.6 2014/07/11 20:26:31 justin Exp $ This file describes compile-time options for rump kernels. Additionally, NetBSD build options will have an effect. See src/share/mk/bsd.README @@ -79,6 +79,22 @@ effect: Control how curlwp is obtained i ================================================================================ +Rumpuser options: + + RUMPUSER_THREADS + +values: pthread/none/fiber or <undefined> +defval: <undefined> +effect: Define the way threading is implemented in the rumpuser hypercall + implmentation. + <undefined> - use default implementation (currently "pthread") + pthread - use pthreads to implement threading + none - do not support kernel threads at all + fiber - user a fiber interface, cooperatively scheduled contexts + + +================================================================================ + Per-component options: RUMP_SYM_NORENAME Added files: Index: src/lib/librumpuser/rumpfiber.c diff -u /dev/null src/lib/librumpuser/rumpfiber.c:1.1 --- /dev/null Fri Jul 11 20:26:31 2014 +++ src/lib/librumpuser/rumpfiber.c Fri Jul 11 20:26:31 2014 @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2007-2013 Antti Kantee. All Rights Reserved. + * Copyright (c) 2014 Justin Cormack. 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. + */ + +/* Based partly on code from Xen Minios with the following license */ + +/* + **************************************************************************** + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + **************************************************************************** + * + * File: sched.c + * Author: Grzegorz Milos + * Changes: Robert Kaiser + * + * Date: Aug 2005 + * + * Environment: Xen Minimal OS + * Description: simple scheduler for Mini-Os + * + * The scheduler is non-preemptive (cooperative), and schedules according + * to Round Robin algorithm. + * + **************************************************************************** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "rumpuser_port.h" + +#if !defined(lint) +__RCSID("$NetBSD: rumpfiber.c,v 1.1 2014/07/11 20:26:31 justin Exp $"); +#endif /* !lint */ + +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.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" +#include "rumpfiber.h" + +static void init_sched(void); +static void join_thread(struct thread *); +static void switch_threads(struct thread *prev, struct thread *next); +static struct thread *get_current(void); +static int64_t now(void); +static void msleep(uint64_t millisecs); +static void abssleep(uint64_t millisecs); + +TAILQ_HEAD(thread_list, thread); + +static struct thread_list exited_threads = TAILQ_HEAD_INITIALIZER(exited_threads); +static struct thread_list thread_list = TAILQ_HEAD_INITIALIZER(thread_list); +static struct thread *current_thread = NULL; + +static void (*scheduler_hook)(void *, void *); + +static struct thread * +get_current(void) +{ + + return current_thread; +} + +static int64_t +now(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); +} + +void +schedule(void) +{ + struct thread *prev, *next, *thread, *tmp; + int64_t tm, wakeup; + struct timespec sl; + + prev = get_current(); + + do { + tm = now(); + wakeup = tm + 1000; /* wake up in 1s max */ + next = NULL; + TAILQ_FOREACH_SAFE(thread, &thread_list, thread_list, tmp) { + if (!is_runnable(thread) && thread->wakeup_time >= 0) { + if (thread->wakeup_time <= tm) { + thread->flags |= THREAD_TIMEDOUT; + wake(thread); + } else if (thread->wakeup_time < wakeup) + wakeup = thread->wakeup_time; + } + if (is_runnable(thread)) { + next = thread; + /* Put this thread on the end of the list */ + TAILQ_REMOVE(&thread_list, thread, thread_list); + TAILQ_INSERT_TAIL(&thread_list, thread, thread_list); + break; + } + } + if (next) + break; + sl.tv_sec = (wakeup - tm) / 1000; + sl.tv_nsec = ((wakeup - tm) - 1000 * sl.tv_sec) * 1000000; +#ifdef HAVE_CLOCK_NANOSLEEP + clock_nanosleep(CLOCK_MONOTONIC, 0, &sl, NULL); +#else + nanosleep(&sl, NULL); +#endif + } while (1); + + if (prev != next) + switch_threads(prev, next); + + TAILQ_FOREACH_SAFE(thread, &exited_threads, thread_list, tmp) { + if (thread != prev) { + TAILQ_REMOVE(&exited_threads, thread, thread_list); + if ((thread->flags & THREAD_EXTSTACK) == 0) + munmap(thread->ctx.uc_stack.ss_sp, STACKSIZE); + free(thread->name); + free(thread); + } + } +} + +static void +create_ctx(ucontext_t *ctx, void *stack, size_t stack_size) +{ + + getcontext(ctx); + ctx->uc_stack.ss_sp = stack; + ctx->uc_stack.ss_size = stack_size; + ctx->uc_stack.ss_flags = 0; + ctx->uc_link = NULL; /* TODO may link to main thread */ +} + +/* may have to do bounce function to call, if args to makecontext are ints */ +/* TODO see notes in rumpuser_thread_create, have flags here */ +struct thread * +create_thread(const char *name, void *cookie, void (*f)(void *), void *data, + void *stack, size_t stack_size) +{ + struct thread *thread = calloc(1, sizeof(struct thread)); + + if (!stack) { + assert(stack_size == 0); + stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, -1, 0); + if (stack == MAP_FAILED) { + return NULL; + } + stack_size = STACKSIZE; + } else { + thread->flags = THREAD_EXTSTACK; + } + create_ctx(&thread->ctx, stack, stack_size); + makecontext(&thread->ctx, (void (*)(void))f, 1, data); + + thread->name = strdup(name); + thread->cookie = cookie; + + /* Not runnable, not exited, not sleeping */ + thread->wakeup_time = -1; + thread->lwp = NULL; + set_runnable(thread); + TAILQ_INSERT_TAIL(&thread_list, thread, thread_list); + + return thread; +} + +static void +switch_threads(struct thread *prev, struct thread *next) +{ + int ret; + + current_thread = next; + if (scheduler_hook) + scheduler_hook(prev->cookie, next->cookie); + ret = swapcontext(&prev->ctx, &next->ctx); + if (ret < 0) { + printk("swapcontext failed\n"); + abort(); + } +} + +struct join_waiter { + struct thread *jw_thread; + struct thread *jw_wanted; + TAILQ_ENTRY(join_waiter) jw_entries; +}; +static TAILQ_HEAD(, join_waiter) joinwq = TAILQ_HEAD_INITIALIZER(joinwq); + +void +exit_thread(void) +{ + struct thread *thread = get_current(); + struct join_waiter *jw_iter; + + /* if joinable, gate until we are allowed to exit */ + while (thread->flags & THREAD_MUSTJOIN) { + thread->flags |= THREAD_JOINED; + + /* see if the joiner is already there */ + TAILQ_FOREACH(jw_iter, &joinwq, jw_entries) { + if (jw_iter->jw_wanted == thread) { + wake(jw_iter->jw_thread); + break; + } + } + block(thread); + schedule(); + } + + /* Remove from the thread list */ + TAILQ_REMOVE(&thread_list, thread, thread_list); + clear_runnable(thread); + /* Put onto exited list */ + TAILQ_INSERT_HEAD(&exited_threads, thread, thread_list); + + /* Schedule will free the resources */ + while (1) { + schedule(); + printk("schedule() returned! Trying again\n"); + } +} + +static void +join_thread(struct thread *joinable) +{ + struct join_waiter jw; + struct thread *thread = get_current(); + + assert(joinable->flags & THREAD_MUSTJOIN); + + /* wait for exiting thread to hit thread_exit() */ + while (! (joinable->flags & THREAD_JOINED)) { + + jw.jw_thread = thread; + jw.jw_wanted = joinable; + TAILQ_INSERT_TAIL(&joinwq, &jw, jw_entries); + block(thread); + schedule(); + TAILQ_REMOVE(&joinwq, &jw, jw_entries); + } + + /* signal exiting thread that we have seen it and it may now exit */ + assert(joinable->flags & THREAD_JOINED); + joinable->flags &= ~THREAD_MUSTJOIN; + + wake(joinable); +} + +static void msleep(uint64_t millisecs) +{ + struct thread *thread = get_current(); + + thread->wakeup_time = now() + millisecs; + clear_runnable(thread); + schedule(); +} + +static void abssleep(uint64_t millisecs) +{ + struct thread *thread = get_current(); + + thread->wakeup_time = millisecs; + clear_runnable(thread); + schedule(); +} + +/* like abssleep, except against realtime clock instead of monotonic clock */ +int abssleep_real(uint64_t millisecs) +{ + struct thread *thread = get_current(); + struct timespec ts; + uint64_t real_now; + int rv; + + clock_gettime(CLOCK_REALTIME, &ts); + real_now = 1000*ts.tv_sec + ts.tv_nsec/(1000*1000); + thread->wakeup_time = now() + (millisecs - real_now); + + clear_runnable(thread); + schedule(); + + rv = !!(thread->flags & THREAD_TIMEDOUT); + thread->flags &= ~THREAD_TIMEDOUT; + return rv; +} + +void wake(struct thread *thread) +{ + + thread->wakeup_time = -1; + set_runnable(thread); +} + +void block(struct thread *thread) +{ + + thread->wakeup_time = -1; + clear_runnable(thread); +} + +int is_runnable(struct thread *thread) +{ + + return thread->flags & RUNNABLE_FLAG; +} + +void set_runnable(struct thread *thread) +{ + + thread->flags |= RUNNABLE_FLAG; +} + +void clear_runnable(struct thread *thread) +{ + + thread->flags &= ~RUNNABLE_FLAG; +} + +static void +init_sched(void) +{ + struct thread *thread = calloc(1, sizeof(struct thread)); + + getcontext(&thread->ctx); + thread->name = strdup("init"); + thread->flags = 0; + thread->wakeup_time = -1; + thread->lwp = NULL; + set_runnable(thread); + TAILQ_INSERT_TAIL(&thread_list, thread, thread_list); + current_thread = thread; +} + +void +set_sched_hook(void (*f)(void *, void *)) +{ + + scheduler_hook = f; +} + +struct thread * +init_mainthread(void *cookie) +{ + + current_thread->cookie = cookie; + return current_thread; +} + +/* rump functions below */ + +struct rumpuser_hyperup rumpuser__hyp; + +int +rumpuser_init(int version, const struct rumpuser_hyperup *hyp) +{ + + if (version != RUMPUSER_VERSION) { + printk("rumpuser version mismatch\n"); + return 1; + } + +#ifdef RUMPUSER_USE_DEVRANDOM + uint32_t rv; + int fd; + + if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { + srandom(time(NULL)); + } else { + if (read(fd, &rv, sizeof(rv)) != sizeof(rv)) + srandom(time(NULL)); + else + srandom(rv); + close(fd); + } +#endif + + rumpuser__hyp = *hyp; + + init_sched(); + + return 0; +} + +int +rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec) +{ + enum rumpclock rclk = enum_rumpclock; + struct timespec ts; + clockid_t clk; + int rv; + + switch (rclk) { + case RUMPUSER_CLOCK_RELWALL: + clk = CLOCK_REALTIME; + break; + case RUMPUSER_CLOCK_ABSMONO: + clk = CLOCK_MONOTONIC; + break; + default: + abort(); + } + + if (clock_gettime(clk, &ts) == -1) { + rv = errno; + } else { + *sec = ts.tv_sec; + *nsec = ts.tv_nsec; + rv = 0; + } + + ET(rv); +} + +int +rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec) +{ + enum rumpclock rclk = enum_rumpclock; + uint32_t msec; + int nlocks; + + rumpkern_unsched(&nlocks, NULL); + switch (rclk) { + case RUMPUSER_CLOCK_RELWALL: + msec = sec * 1000 + nsec / (1000*1000UL); + msleep(msec); + break; + case RUMPUSER_CLOCK_ABSMONO: + msec = sec * 1000 + nsec / (1000*1000UL); + abssleep(msec); + break; + } + rumpkern_sched(nlocks, NULL); + + return 0; +} + +int +rumpuser_getparam(const char *name, void *buf, size_t blen) +{ + int rv; + const char *ncpu = "1"; + + if (strcmp(name, RUMPUSER_PARAM_NCPU) == 0) { + strncpy(buf, ncpu, blen); + rv = 0; + } else if (strcmp(name, RUMPUSER_PARAM_HOSTNAME) == 0) { + char tmp[MAXHOSTNAMELEN]; + + if (gethostname(tmp, sizeof(tmp)) == -1) { + snprintf(buf, blen, "rump-%05d", (int)getpid()); + } else { + snprintf(buf, blen, "rump-%05d.%s", + (int)getpid(), tmp); + } + rv = 0; + } else if (*name == '_') { + rv = EINVAL; + } else { + if (getenv_r(name, buf, blen) == -1) + rv = errno; + else + rv = 0; + } + + ET(rv); +} + +void +rumpuser_putchar(int c) +{ + + putchar(c); +} + +__dead void +rumpuser_exit(int rv) +{ + + if (rv == RUMPUSER_PANIC) + abort(); + else + exit(rv); +} + +void +rumpuser_seterrno(int error) +{ + + errno = error; +} + +/* + * This is meant for safe debugging prints from the kernel. + */ +void +rumpuser_dprintf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} + +int +rumpuser_kill(int64_t pid, int rumpsig) +{ + int sig; + + sig = rumpuser__sig_rump2host(rumpsig); + if (sig > 0) + raise(sig); + return 0; +} + +int +rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retp) +{ + size_t origlen = buflen; + uint32_t *p = buf; + uint32_t tmp; + int chunk; + + do { + chunk = buflen < 4 ? buflen : 4; /* portable MIN ... */ + tmp = RUMPUSER_RANDOM(); + memcpy(p, &tmp, chunk); + p++; + buflen -= chunk; + } while (chunk); + + *retp = origlen; + ET(0); +} + +/* thread functions */ + +TAILQ_HEAD(waithead, waiter); +struct waiter { + struct thread *who; + TAILQ_ENTRY(waiter) entries; + int onlist; +}; + +static int +wait(struct waithead *wh, uint64_t msec) +{ + struct waiter w; + + w.who = get_current(); + TAILQ_INSERT_TAIL(wh, &w, entries); + w.onlist = 1; + block(w.who); + if (msec) + w.who->wakeup_time = now() + msec; + schedule(); + + /* woken up by timeout? */ + if (w.onlist) + TAILQ_REMOVE(wh, &w, entries); + + return w.onlist ? ETIMEDOUT : 0; +} + +static void +wakeup_one(struct waithead *wh) +{ + struct waiter *w; + + if ((w = TAILQ_FIRST(wh)) != NULL) { + TAILQ_REMOVE(wh, w, entries); + w->onlist = 0; + wake(w->who); + } +} + +static void +wakeup_all(struct waithead *wh) +{ + struct waiter *w; + + while ((w = TAILQ_FIRST(wh)) != NULL) { + TAILQ_REMOVE(wh, w, entries); + w->onlist = 0; + wake(w->who); + } +} + +int +rumpuser_thread_create(void *(*f)(void *), void *arg, const char *thrname, + int joinable, int pri, int cpuidx, void **tptr) +{ + struct thread *thr; + + thr = create_thread(thrname, NULL, (void (*)(void *))f, arg, NULL, 0); + /* + * XXX: should be supplied as a flag to create_thread() so as to + * _ensure_ it's set before the thread runs (and could exit). + * now we're trusting unclear semantics of create_thread() + */ + if (thr && joinable) + thr->flags |= THREAD_MUSTJOIN; + + if (!thr) + return EINVAL; + + *tptr = thr; + return 0; +} + +void +rumpuser_thread_exit(void) +{ + + exit_thread(); +} + +int +rumpuser_thread_join(void *p) +{ + + join_thread(p); + return 0; +} + +struct rumpuser_mtx { + struct waithead waiters; + int v; + int flags; + struct lwp *o; +}; + +void +rumpuser_mutex_init(struct rumpuser_mtx **mtxp, int flags) +{ + struct rumpuser_mtx *mtx; + + mtx = malloc(sizeof(*mtx)); + memset(mtx, 0, sizeof(*mtx)); + mtx->flags = flags; + TAILQ_INIT(&mtx->waiters); + *mtxp = mtx; +} + +void +rumpuser_mutex_enter(struct rumpuser_mtx *mtx) +{ + int nlocks; + + if (rumpuser_mutex_tryenter(mtx) != 0) { + rumpkern_unsched(&nlocks, NULL); + while (rumpuser_mutex_tryenter(mtx) != 0) + wait(&mtx->waiters, 0); + rumpkern_sched(nlocks, NULL); + } +} + +void +rumpuser_mutex_enter_nowrap(struct rumpuser_mtx *mtx) +{ + int rv; + + rv = rumpuser_mutex_tryenter(mtx); + /* one VCPU supported, no preemption => must succeed */ + if (rv != 0) { + printk("no voi ei\n"); + } +} + +int +rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx) +{ + struct lwp *l = get_current()->lwp; + + if (mtx->v && mtx->o != l) + return EBUSY; + + mtx->v++; + mtx->o = l; + + return 0; +} + +void +rumpuser_mutex_exit(struct rumpuser_mtx *mtx) +{ + + assert(mtx->v > 0); + if (--mtx->v == 0) { + mtx->o = NULL; + wakeup_one(&mtx->waiters); + } +} + +void +rumpuser_mutex_destroy(struct rumpuser_mtx *mtx) +{ + + assert(TAILQ_EMPTY(&mtx->waiters) && mtx->o == NULL); + free(mtx); +} + +void +rumpuser_mutex_owner(struct rumpuser_mtx *mtx, struct lwp **lp) +{ + + *lp = mtx->o; +} + +struct rumpuser_rw { + struct waithead rwait; + struct waithead wwait; + int v; + struct lwp *o; +}; + +void +rumpuser_rw_init(struct rumpuser_rw **rwp) +{ + struct rumpuser_rw *rw; + + rw = malloc(sizeof(*rw)); + memset(rw, 0, sizeof(*rw)); + TAILQ_INIT(&rw->rwait); + TAILQ_INIT(&rw->wwait); + + *rwp = rw; +} + +void +rumpuser_rw_enter(int enum_rumprwlock, struct rumpuser_rw *rw) +{ + enum rumprwlock lk = enum_rumprwlock; + struct waithead *w = NULL; + int nlocks; + + switch (lk) { + case RUMPUSER_RW_WRITER: + w = &rw->wwait; + break; + case RUMPUSER_RW_READER: + w = &rw->rwait; + break; + } + + if (rumpuser_rw_tryenter(enum_rumprwlock, rw) != 0) { + rumpkern_unsched(&nlocks, NULL); + while (rumpuser_rw_tryenter(enum_rumprwlock, rw) != 0) + wait(w, 0); + rumpkern_sched(nlocks, NULL); + } +} + +int +rumpuser_rw_tryenter(int enum_rumprwlock, struct rumpuser_rw *rw) +{ + enum rumprwlock lk = enum_rumprwlock; + int rv; + + switch (lk) { + case RUMPUSER_RW_WRITER: + if (rw->o == NULL) { + rw->o = rumpuser_curlwp(); + rv = 0; + } else { + rv = EBUSY; + } + break; + case RUMPUSER_RW_READER: + if (rw->o == NULL && TAILQ_EMPTY(&rw->wwait)) { + rw->v++; + rv = 0; + } else { + rv = EBUSY; + } + break; + default: + rv = EINVAL; + } + + return rv; +} + +void +rumpuser_rw_exit(struct rumpuser_rw *rw) +{ + + if (rw->o) { + rw->o = NULL; + } else { + rw->v--; + } + + /* standard procedure, don't let readers starve out writers */ + if (!TAILQ_EMPTY(&rw->wwait)) { + if (rw->o == NULL) + wakeup_one(&rw->wwait); + } else if (!TAILQ_EMPTY(&rw->rwait) && rw->o == NULL) { + wakeup_all(&rw->rwait); + } +} + +void +rumpuser_rw_destroy(struct rumpuser_rw *rw) +{ + + free(rw); +} + +void +rumpuser_rw_held(int enum_rumprwlock, struct rumpuser_rw *rw, int *rvp) +{ + enum rumprwlock lk = enum_rumprwlock; + + switch (lk) { + case RUMPUSER_RW_WRITER: + *rvp = rw->o == rumpuser_curlwp(); + break; + case RUMPUSER_RW_READER: + *rvp = rw->v > 0; + break; + } +} + +void +rumpuser_rw_downgrade(struct rumpuser_rw *rw) +{ + + assert(rw->o == rumpuser_curlwp()); + rw->v = -1; +} + +int +rumpuser_rw_tryupgrade(struct rumpuser_rw *rw) +{ + + if (rw->v == -1) { + rw->v = 1; + rw->o = rumpuser_curlwp(); + return 0; + } + + return EBUSY; +} + +struct rumpuser_cv { + struct waithead waiters; + int nwaiters; +}; + +void +rumpuser_cv_init(struct rumpuser_cv **cvp) +{ + struct rumpuser_cv *cv; + + cv = malloc(sizeof(*cv)); + memset(cv, 0, sizeof(*cv)); + TAILQ_INIT(&cv->waiters); + *cvp = cv; +} + +void +rumpuser_cv_destroy(struct rumpuser_cv *cv) +{ + + assert(cv->nwaiters == 0); + free(cv); +} + +static void +cv_unsched(struct rumpuser_mtx *mtx, int *nlocks) +{ + + rumpkern_unsched(nlocks, mtx); + rumpuser_mutex_exit(mtx); +} + +static void +cv_resched(struct rumpuser_mtx *mtx, int nlocks) +{ + + /* see rumpuser(3) */ + if ((mtx->flags & (RUMPUSER_MTX_KMUTEX | RUMPUSER_MTX_SPIN)) == + (RUMPUSER_MTX_KMUTEX | RUMPUSER_MTX_SPIN)) { + rumpkern_sched(nlocks, mtx); + rumpuser_mutex_enter_nowrap(mtx); + } else { + rumpuser_mutex_enter_nowrap(mtx); + rumpkern_sched(nlocks, mtx); + } +} + +void +rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx) +{ + int nlocks; + + cv->nwaiters++; + cv_unsched(mtx, &nlocks); + wait(&cv->waiters, 0); + cv_resched(mtx, nlocks); + cv->nwaiters--; +} + +void +rumpuser_cv_wait_nowrap(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx) +{ + + cv->nwaiters++; + rumpuser_mutex_exit(mtx); + wait(&cv->waiters, 0); + rumpuser_mutex_enter_nowrap(mtx); + cv->nwaiters--; +} + +int +rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx, + int64_t sec, int64_t nsec) +{ + int nlocks; + int rv; + + cv->nwaiters++; + cv_unsched(mtx, &nlocks); + rv = wait(&cv->waiters, sec * 1000 + nsec / (1000*1000)); + cv_resched(mtx, nlocks); + cv->nwaiters--; + + return rv; +} + +void +rumpuser_cv_signal(struct rumpuser_cv *cv) +{ + + wakeup_one(&cv->waiters); +} + +void +rumpuser_cv_broadcast(struct rumpuser_cv *cv) +{ + + wakeup_all(&cv->waiters); +} + +void +rumpuser_cv_has_waiters(struct rumpuser_cv *cv, int *rvp) +{ + + *rvp = cv->nwaiters != 0; +} + +/* + * curlwp + */ + +void +rumpuser_curlwpop(int enum_rumplwpop, struct lwp *l) +{ + struct thread *thread; + enum rumplwpop op = enum_rumplwpop; + + switch (op) { + case RUMPUSER_LWP_CREATE: + case RUMPUSER_LWP_DESTROY: + break; + case RUMPUSER_LWP_SET: + thread = get_current(); + thread->lwp = l; + break; + case RUMPUSER_LWP_CLEAR: + thread = get_current(); + assert(thread->lwp == l); + thread->lwp = NULL; + break; + } +} + +struct lwp * +rumpuser_curlwp(void) +{ + + return get_current()->lwp; +} Index: src/lib/librumpuser/rumpfiber.h diff -u /dev/null src/lib/librumpuser/rumpfiber.h:1.1 --- /dev/null Fri Jul 11 20:26:31 2014 +++ src/lib/librumpuser/rumpfiber.h Fri Jul 11 20:26:31 2014 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014 Justin Cormack. 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/queue.h> + +#include <stdint.h> +#include <string.h> +#include <time.h> +#include <ucontext.h> +#include <unistd.h> + +static void printk(const char *s); + +static void +printk(const char *msg) +{ + int ret __attribute__((unused)); + + ret = write(2, msg, strlen(msg)); +} + +struct thread { + char *name; + void *lwp; + void *cookie; + int64_t wakeup_time; + TAILQ_ENTRY(thread) thread_list; + ucontext_t ctx; + uint32_t flags; + int threrrno; +}; + +#define RUNNABLE_FLAG 0x00000001 +#define THREAD_MUSTJOIN 0x00000002 +#define THREAD_JOINED 0x00000004 +#define THREAD_EXTSTACK 0x00000008 +#define THREAD_TIMEDOUT 0x00000010 + +#define STACKSIZE 65536 + +/* used by experimental _lwp code */ +void schedule(void); +void wake(struct thread *thread); +void block(struct thread *thread); +struct thread *init_mainthread(void *); +void exit_thread(void) __attribute__((noreturn)); +void set_sched_hook(void (*f)(void *, void *)); +int abssleep_real(uint64_t millisecs); +struct thread* create_thread(const char *name, void *cookie, + void (*f)(void *), void *data, + void *stack, size_t stack_size); +int is_runnable(struct thread *); +void set_runnable(struct thread *); +void clear_runnable(struct thread *); + Index: src/lib/librumpuser/rumpfiber_bio.c diff -u /dev/null src/lib/librumpuser/rumpfiber_bio.c:1.1 --- /dev/null Fri Jul 11 20:26:31 2014 +++ src/lib/librumpuser/rumpfiber_bio.c Fri Jul 11 20:26:31 2014 @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2014 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 "rumpuser_port.h" + +#if !defined(lint) +__RCSID("$NetBSD: rumpfiber_bio.c,v 1.1 2014/07/11 20:26:31 justin Exp $"); +#endif /* !lint */ + +#include <sys/types.h> + +#include <stdint.h> +#include <unistd.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +void +rumpuser_bio(int fd, int op, void *data, size_t dlen, int64_t doff, + rump_biodone_fn biodone, void *bioarg) +{ + ssize_t rv; + int error = 0; + + if (op & RUMPUSER_BIO_READ) { + if ((rv = pread(fd, data, dlen, doff)) == -1) + error = errno; + } else { + if ((rv = pwrite(fd, data, dlen, doff)) == -1) + error = errno; + if (error == 0 && (op & RUMPUSER_BIO_SYNC)) { +#ifdef __NetBSD__ + fsync_range(fd, FDATASYNC, doff, dlen); +#else + fsync(fd); +#endif + } + } + if (rv == -1) + rv = 0; + biodone(bioarg, (size_t)rv, error); +} Index: src/lib/librumpuser/rumpfiber_sp.c diff -u /dev/null src/lib/librumpuser/rumpfiber_sp.c:1.1 --- /dev/null Fri Jul 11 20:26:31 2014 +++ src/lib/librumpuser/rumpfiber_sp.c Fri Jul 11 20:26:31 2014 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014 Justin Cormack. 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. + */ + +/* stubs for sp functions as not supported for fibers yet */ + +#include "rumpuser_port.h" + +#if !defined(lint) +__RCSID("$NetBSD: rumpfiber_sp.c,v 1.1 2014/07/11 20:26:31 justin Exp $"); +#endif /* !lint */ + +#include <stdlib.h> + +#include <rump/rumpuser.h> + +#include "rumpfiber.h" + +/*ARGSUSED*/ +int +rumpuser_sp_init(const char *url, + const char *ostype, const char *osrelease, const char *machine) +{ + + return 0; +} + +/*ARGSUSED*/ +void +rumpuser_sp_fini(void *arg) +{ + +} + +/*ARGSUSED*/ +int +rumpuser_sp_raise(void *arg, int signo) +{ + + printk("rumphyper: unimplemented rumpuser_sp_raise\n"); + exit(1); +} + +/*ARGSUSED*/ +int +rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len) +{ + + printk("rumphyper: unimplemented rumpuser_sp_copyin\n"); + exit(1); +} + +/*ARGSUSED*/ +int +rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len) +{ + + printk("rumphyper: unimplemented rumpuser_sp_copyinstr\n"); + exit(1); +} + +/*ARGSUSED*/ +int +rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen) +{ + + printk("rumphyper: unimplemented rumpuser_sp_copyout\n"); + exit(1); +} + +/*ARGSUSED*/ +int +rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen) +{ + + printk("rumphyper: unimplemented rumpuser_sp_copyoutstr\n"); + exit(1); +} + +/*ARGSUSED*/ +int +rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr) +{ + + printk("rumphyper: unimplemented rumpuser_sp_anonmmap\n"); + exit(1); +}