Home | History | Annotate | Line # | Download | only in librumpuser
      1  1.13   ozaki /*	$NetBSD: rumpfiber.c,v 1.13 2017/12/27 09:01:53 ozaki-r Exp $	*/
      2   1.4   pooka 
      3   1.1  justin /*
      4   1.1  justin  * Copyright (c) 2007-2013 Antti Kantee.  All Rights Reserved.
      5   1.1  justin  * Copyright (c) 2014 Justin Cormack.  All Rights Reserved.
      6   1.1  justin  *
      7   1.1  justin  * Redistribution and use in source and binary forms, with or without
      8   1.1  justin  * modification, are permitted provided that the following conditions
      9   1.1  justin  * are met:
     10   1.1  justin  * 1. Redistributions of source code must retain the above copyright
     11   1.1  justin  *    notice, this list of conditions and the following disclaimer.
     12   1.1  justin  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  justin  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  justin  *    documentation and/or other materials provided with the distribution.
     15   1.1  justin  *
     16   1.1  justin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     17   1.1  justin  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18   1.1  justin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19   1.1  justin  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20   1.1  justin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21   1.1  justin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22   1.1  justin  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1  justin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1  justin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1  justin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1  justin  * SUCH DAMAGE.
     27   1.1  justin  */
     28   1.1  justin 
     29   1.1  justin /* Based partly on code from Xen Minios with the following license */
     30   1.1  justin 
     31   1.1  justin /*
     32   1.1  justin  ****************************************************************************
     33   1.1  justin  * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
     34   1.1  justin  ****************************************************************************
     35   1.1  justin  *
     36   1.1  justin  *        File: sched.c
     37   1.1  justin  *      Author: Grzegorz Milos
     38   1.1  justin  *     Changes: Robert Kaiser
     39   1.1  justin  *
     40   1.1  justin  *        Date: Aug 2005
     41   1.1  justin  *
     42   1.1  justin  * Environment: Xen Minimal OS
     43   1.1  justin  * Description: simple scheduler for Mini-Os
     44   1.1  justin  *
     45   1.1  justin  * The scheduler is non-preemptive (cooperative), and schedules according
     46   1.1  justin  * to Round Robin algorithm.
     47   1.1  justin  *
     48   1.1  justin  ****************************************************************************
     49   1.1  justin  * Permission is hereby granted, free of charge, to any person obtaining a copy
     50   1.1  justin  * of this software and associated documentation files (the "Software"), to
     51   1.1  justin  * deal in the Software without restriction, including without limitation the
     52   1.1  justin  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     53   1.1  justin  * sell copies of the Software, and to permit persons to whom the Software is
     54   1.1  justin  * furnished to do so, subject to the following conditions:
     55   1.1  justin  *
     56   1.1  justin  * The above copyright notice and this permission notice shall be included in
     57   1.1  justin  * all copies or substantial portions of the Software.
     58   1.1  justin  *
     59   1.1  justin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     60   1.1  justin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     61   1.1  justin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     62   1.1  justin  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     63   1.1  justin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     64   1.1  justin  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     65   1.1  justin  * DEALINGS IN THE SOFTWARE.
     66   1.1  justin  */
     67   1.1  justin 
     68   1.1  justin #include "rumpuser_port.h"
     69   1.1  justin 
     70   1.1  justin #if !defined(lint)
     71  1.13   ozaki __RCSID("$NetBSD: rumpfiber.c,v 1.13 2017/12/27 09:01:53 ozaki-r Exp $");
     72   1.1  justin #endif /* !lint */
     73   1.1  justin 
     74   1.1  justin #include <sys/mman.h>
     75   1.1  justin #include <sys/time.h>
     76   1.1  justin 
     77   1.1  justin #include <assert.h>
     78   1.1  justin #include <errno.h>
     79   1.1  justin #include <fcntl.h>
     80   1.1  justin #include <signal.h>
     81   1.1  justin #include <stdarg.h>
     82   1.1  justin #include <stdint.h>
     83   1.1  justin #include <stdio.h>
     84   1.1  justin #include <stdlib.h>
     85   1.1  justin #include <string.h>
     86   1.1  justin #include <time.h>
     87   1.1  justin #include <unistd.h>
     88   1.1  justin 
     89   1.1  justin #include <rump/rumpuser.h>
     90   1.1  justin 
     91   1.1  justin #include "rumpuser_int.h"
     92   1.1  justin #include "rumpfiber.h"
     93   1.1  justin 
     94   1.1  justin static void init_sched(void);
     95   1.1  justin static void join_thread(struct thread *);
     96   1.1  justin static void switch_threads(struct thread *prev, struct thread *next);
     97   1.1  justin static struct thread *get_current(void);
     98   1.1  justin static int64_t now(void);
     99   1.1  justin static void msleep(uint64_t millisecs);
    100   1.1  justin static void abssleep(uint64_t millisecs);
    101   1.1  justin 
    102   1.1  justin TAILQ_HEAD(thread_list, thread);
    103   1.1  justin 
    104   1.1  justin static struct thread_list exited_threads = TAILQ_HEAD_INITIALIZER(exited_threads);
    105   1.1  justin static struct thread_list thread_list = TAILQ_HEAD_INITIALIZER(thread_list);
    106   1.1  justin static struct thread *current_thread = NULL;
    107   1.1  justin 
    108   1.1  justin static void (*scheduler_hook)(void *, void *);
    109   1.1  justin 
    110   1.9  justin static void printk(const char *s);
    111   1.9  justin 
    112   1.9  justin static void
    113   1.9  justin printk(const char *msg)
    114   1.9  justin {
    115   1.9  justin 	int ret __attribute__((unused));
    116   1.9  justin 
    117   1.9  justin 	ret = write(2, msg, strlen(msg));
    118   1.9  justin }
    119   1.9  justin 
    120   1.1  justin static struct thread *
    121   1.1  justin get_current(void)
    122   1.1  justin {
    123   1.1  justin 
    124   1.1  justin 	return current_thread;
    125   1.1  justin }
    126   1.1  justin 
    127   1.1  justin static int64_t
    128   1.1  justin now(void)
    129   1.1  justin {
    130   1.1  justin 	struct timespec ts;
    131   1.5   pooka 	int rv;
    132   1.1  justin 
    133   1.5   pooka 	rv = clock_gettime(CLOCK_MONOTONIC, &ts);
    134   1.5   pooka 	assert(rv == 0);
    135   1.1  justin 	return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
    136   1.1  justin }
    137   1.1  justin 
    138   1.1  justin void
    139   1.1  justin schedule(void)
    140   1.1  justin {
    141   1.1  justin 	struct thread *prev, *next, *thread, *tmp;
    142   1.1  justin 	int64_t tm, wakeup;
    143   1.1  justin 	struct timespec sl;
    144   1.1  justin 
    145   1.1  justin 	prev = get_current();
    146   1.1  justin 
    147   1.1  justin 	do {
    148   1.1  justin 		tm = now();
    149   1.1  justin 		wakeup = tm + 1000; /* wake up in 1s max */
    150   1.1  justin 		next = NULL;
    151   1.1  justin 		TAILQ_FOREACH_SAFE(thread, &thread_list, thread_list, tmp) {
    152   1.1  justin 			if (!is_runnable(thread) && thread->wakeup_time >= 0) {
    153   1.1  justin 				if (thread->wakeup_time <= tm) {
    154   1.1  justin 					thread->flags |= THREAD_TIMEDOUT;
    155   1.1  justin 					wake(thread);
    156   1.1  justin 				} else if (thread->wakeup_time < wakeup)
    157   1.1  justin 					wakeup = thread->wakeup_time;
    158   1.1  justin 			}
    159   1.1  justin 			if (is_runnable(thread)) {
    160   1.1  justin 				next = thread;
    161   1.1  justin 				/* Put this thread on the end of the list */
    162   1.1  justin 				TAILQ_REMOVE(&thread_list, thread, thread_list);
    163   1.1  justin 				TAILQ_INSERT_TAIL(&thread_list, thread, thread_list);
    164   1.1  justin 				break;
    165   1.1  justin 			}
    166   1.1  justin 		}
    167   1.1  justin 		if (next)
    168   1.1  justin 			break;
    169   1.1  justin 		sl.tv_sec = (wakeup - tm) / 1000;
    170   1.1  justin 		sl.tv_nsec = ((wakeup - tm) - 1000 * sl.tv_sec) * 1000000;
    171   1.1  justin #ifdef HAVE_CLOCK_NANOSLEEP
    172   1.1  justin 		clock_nanosleep(CLOCK_MONOTONIC, 0, &sl, NULL);
    173   1.1  justin #else
    174   1.1  justin 		nanosleep(&sl, NULL);
    175   1.1  justin #endif
    176   1.1  justin 	} while (1);
    177   1.1  justin 
    178   1.1  justin 	if (prev != next)
    179   1.1  justin 		switch_threads(prev, next);
    180   1.1  justin 
    181   1.1  justin 	TAILQ_FOREACH_SAFE(thread, &exited_threads, thread_list, tmp) {
    182   1.1  justin 		if (thread != prev) {
    183   1.1  justin 			TAILQ_REMOVE(&exited_threads, thread, thread_list);
    184   1.1  justin 			if ((thread->flags & THREAD_EXTSTACK) == 0)
    185   1.1  justin 				munmap(thread->ctx.uc_stack.ss_sp, STACKSIZE);
    186   1.1  justin 			free(thread->name);
    187   1.1  justin 			free(thread);
    188   1.1  justin 		}
    189   1.1  justin 	}
    190   1.1  justin }
    191   1.1  justin 
    192   1.1  justin static void
    193   1.7  justin create_ctx(ucontext_t *ctx, void *stack, size_t stack_size,
    194   1.7  justin 	void (*f)(void *), void *data)
    195   1.1  justin {
    196   1.1  justin 
    197   1.1  justin 	getcontext(ctx);
    198   1.1  justin 	ctx->uc_stack.ss_sp = stack;
    199   1.1  justin 	ctx->uc_stack.ss_size = stack_size;
    200   1.1  justin 	ctx->uc_stack.ss_flags = 0;
    201   1.1  justin 	ctx->uc_link = NULL; /* TODO may link to main thread */
    202   1.7  justin 	/* may have to do bounce function to call, if args to makecontext are ints */
    203   1.7  justin 	makecontext(ctx, (void (*)(void))f, 1, data);
    204   1.1  justin }
    205   1.1  justin 
    206   1.1  justin /* TODO see notes in rumpuser_thread_create, have flags here */
    207   1.1  justin struct thread *
    208   1.1  justin create_thread(const char *name, void *cookie, void (*f)(void *), void *data,
    209   1.1  justin 	void *stack, size_t stack_size)
    210   1.1  justin {
    211   1.1  justin 	struct thread *thread = calloc(1, sizeof(struct thread));
    212   1.1  justin 
    213   1.6  justin 	if (!thread) {
    214   1.6  justin 		return NULL;
    215   1.6  justin 	}
    216   1.6  justin 
    217   1.1  justin 	if (!stack) {
    218   1.1  justin 		assert(stack_size == 0);
    219   1.1  justin 		stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE,
    220   1.1  justin 		    MAP_SHARED | MAP_ANON, -1, 0);
    221   1.1  justin 		if (stack == MAP_FAILED) {
    222   1.6  justin 			free(thread);
    223   1.1  justin 			return NULL;
    224   1.1  justin 		}
    225   1.1  justin 		stack_size = STACKSIZE;
    226   1.1  justin 	} else {
    227   1.1  justin 		thread->flags = THREAD_EXTSTACK;
    228   1.1  justin 	}
    229   1.7  justin 	create_ctx(&thread->ctx, stack, stack_size, f, data);
    230   1.1  justin 
    231   1.1  justin 	thread->name = strdup(name);
    232   1.1  justin 	thread->cookie = cookie;
    233   1.1  justin 
    234   1.1  justin 	/* Not runnable, not exited, not sleeping */
    235   1.1  justin 	thread->wakeup_time = -1;
    236   1.1  justin 	thread->lwp = NULL;
    237   1.1  justin 	set_runnable(thread);
    238   1.1  justin 	TAILQ_INSERT_TAIL(&thread_list, thread, thread_list);
    239   1.1  justin 
    240   1.1  justin 	return thread;
    241   1.1  justin }
    242   1.1  justin 
    243   1.1  justin static void
    244   1.1  justin switch_threads(struct thread *prev, struct thread *next)
    245   1.1  justin {
    246   1.1  justin 	int ret;
    247   1.1  justin 
    248   1.1  justin 	current_thread = next;
    249   1.1  justin 	if (scheduler_hook)
    250   1.1  justin 		scheduler_hook(prev->cookie, next->cookie);
    251   1.1  justin 	ret = swapcontext(&prev->ctx, &next->ctx);
    252   1.1  justin 	if (ret < 0) {
    253   1.1  justin 		printk("swapcontext failed\n");
    254   1.1  justin 		abort();
    255   1.1  justin 	}
    256   1.1  justin }
    257   1.1  justin 
    258   1.1  justin struct join_waiter {
    259   1.1  justin     struct thread *jw_thread;
    260   1.1  justin     struct thread *jw_wanted;
    261   1.1  justin     TAILQ_ENTRY(join_waiter) jw_entries;
    262   1.1  justin };
    263   1.1  justin static TAILQ_HEAD(, join_waiter) joinwq = TAILQ_HEAD_INITIALIZER(joinwq);
    264   1.1  justin 
    265   1.1  justin void
    266   1.1  justin exit_thread(void)
    267   1.1  justin {
    268   1.1  justin 	struct thread *thread = get_current();
    269   1.1  justin 	struct join_waiter *jw_iter;
    270   1.1  justin 
    271   1.1  justin 	/* if joinable, gate until we are allowed to exit */
    272   1.1  justin 	while (thread->flags & THREAD_MUSTJOIN) {
    273   1.1  justin 		thread->flags |= THREAD_JOINED;
    274   1.1  justin 
    275   1.1  justin 		/* see if the joiner is already there */
    276   1.1  justin 		TAILQ_FOREACH(jw_iter, &joinwq, jw_entries) {
    277   1.1  justin 			if (jw_iter->jw_wanted == thread) {
    278   1.1  justin 				wake(jw_iter->jw_thread);
    279   1.1  justin 				break;
    280   1.1  justin 			}
    281   1.1  justin 		}
    282   1.1  justin 		block(thread);
    283   1.1  justin 		schedule();
    284   1.1  justin 	}
    285   1.1  justin 
    286   1.1  justin 	/* Remove from the thread list */
    287   1.1  justin 	TAILQ_REMOVE(&thread_list, thread, thread_list);
    288   1.1  justin 	clear_runnable(thread);
    289   1.1  justin 	/* Put onto exited list */
    290   1.1  justin 	TAILQ_INSERT_HEAD(&exited_threads, thread, thread_list);
    291   1.1  justin 
    292   1.1  justin 	/* Schedule will free the resources */
    293   1.1  justin 	while (1) {
    294   1.1  justin 		schedule();
    295   1.1  justin 		printk("schedule() returned!  Trying again\n");
    296   1.1  justin 	}
    297   1.1  justin }
    298   1.1  justin 
    299   1.1  justin static void
    300   1.1  justin join_thread(struct thread *joinable)
    301   1.1  justin {
    302   1.1  justin 	struct join_waiter jw;
    303   1.1  justin 	struct thread *thread = get_current();
    304   1.1  justin 
    305   1.1  justin 	assert(joinable->flags & THREAD_MUSTJOIN);
    306   1.1  justin 
    307   1.1  justin 	/* wait for exiting thread to hit thread_exit() */
    308   1.1  justin 	while (! (joinable->flags & THREAD_JOINED)) {
    309   1.1  justin 
    310   1.1  justin 		jw.jw_thread = thread;
    311   1.1  justin 		jw.jw_wanted = joinable;
    312   1.1  justin 		TAILQ_INSERT_TAIL(&joinwq, &jw, jw_entries);
    313   1.1  justin 		block(thread);
    314   1.1  justin 		schedule();
    315   1.1  justin 		TAILQ_REMOVE(&joinwq, &jw, jw_entries);
    316   1.1  justin 	}
    317   1.1  justin 
    318   1.1  justin 	/* signal exiting thread that we have seen it and it may now exit */
    319   1.1  justin 	assert(joinable->flags & THREAD_JOINED);
    320   1.1  justin 	joinable->flags &= ~THREAD_MUSTJOIN;
    321   1.1  justin 
    322   1.1  justin 	wake(joinable);
    323   1.1  justin }
    324   1.1  justin 
    325   1.1  justin static void msleep(uint64_t millisecs)
    326   1.1  justin {
    327   1.1  justin 	struct thread *thread = get_current();
    328   1.1  justin 
    329   1.1  justin 	thread->wakeup_time = now() + millisecs;
    330   1.1  justin 	clear_runnable(thread);
    331   1.1  justin 	schedule();
    332   1.1  justin }
    333   1.1  justin 
    334   1.1  justin static void abssleep(uint64_t millisecs)
    335   1.1  justin {
    336   1.1  justin 	struct thread *thread = get_current();
    337   1.1  justin 
    338   1.1  justin 	thread->wakeup_time = millisecs;
    339   1.1  justin 	clear_runnable(thread);
    340   1.1  justin 	schedule();
    341   1.1  justin }
    342   1.1  justin 
    343   1.1  justin /* like abssleep, except against realtime clock instead of monotonic clock */
    344   1.1  justin int abssleep_real(uint64_t millisecs)
    345   1.1  justin {
    346   1.1  justin 	struct thread *thread = get_current();
    347   1.1  justin 	struct timespec ts;
    348   1.1  justin 	uint64_t real_now;
    349   1.1  justin 	int rv;
    350   1.1  justin 
    351   1.1  justin 	clock_gettime(CLOCK_REALTIME, &ts);
    352   1.1  justin 	real_now = 1000*ts.tv_sec + ts.tv_nsec/(1000*1000);
    353   1.1  justin 	thread->wakeup_time = now() + (millisecs - real_now);
    354   1.1  justin 
    355   1.1  justin 	clear_runnable(thread);
    356   1.1  justin 	schedule();
    357   1.1  justin 
    358   1.1  justin 	rv = !!(thread->flags & THREAD_TIMEDOUT);
    359   1.1  justin 	thread->flags &= ~THREAD_TIMEDOUT;
    360   1.1  justin 	return rv;
    361   1.1  justin }
    362   1.1  justin 
    363   1.1  justin void wake(struct thread *thread)
    364   1.1  justin {
    365   1.1  justin 
    366   1.1  justin 	thread->wakeup_time = -1;
    367   1.1  justin 	set_runnable(thread);
    368   1.1  justin }
    369   1.1  justin 
    370   1.1  justin void block(struct thread *thread)
    371   1.1  justin {
    372   1.1  justin 
    373   1.1  justin 	thread->wakeup_time = -1;
    374   1.1  justin 	clear_runnable(thread);
    375   1.1  justin }
    376   1.1  justin 
    377   1.1  justin int is_runnable(struct thread *thread)
    378   1.1  justin {
    379   1.1  justin 
    380   1.1  justin 	return thread->flags & RUNNABLE_FLAG;
    381   1.1  justin }
    382   1.1  justin 
    383   1.1  justin void set_runnable(struct thread *thread)
    384   1.1  justin {
    385   1.1  justin 
    386   1.1  justin 	thread->flags |= RUNNABLE_FLAG;
    387   1.1  justin }
    388   1.1  justin 
    389   1.1  justin void clear_runnable(struct thread *thread)
    390   1.1  justin {
    391   1.1  justin 
    392   1.1  justin 	thread->flags &= ~RUNNABLE_FLAG;
    393   1.1  justin }
    394   1.1  justin 
    395   1.1  justin static void
    396   1.1  justin init_sched(void)
    397   1.1  justin {
    398   1.1  justin 	struct thread *thread = calloc(1, sizeof(struct thread));
    399   1.1  justin 
    400  1.10  justin 	if (!thread) {
    401  1.10  justin 		abort();
    402  1.10  justin 	}
    403  1.10  justin 
    404   1.1  justin 	thread->name = strdup("init");
    405   1.1  justin 	thread->flags = 0;
    406   1.1  justin 	thread->wakeup_time = -1;
    407   1.1  justin 	thread->lwp = NULL;
    408   1.1  justin 	set_runnable(thread);
    409   1.1  justin 	TAILQ_INSERT_TAIL(&thread_list, thread, thread_list);
    410   1.1  justin 	current_thread = thread;
    411   1.1  justin }
    412   1.1  justin 
    413   1.1  justin void
    414   1.1  justin set_sched_hook(void (*f)(void *, void *))
    415   1.1  justin {
    416   1.1  justin 
    417   1.1  justin 	scheduler_hook = f;
    418   1.1  justin }
    419   1.1  justin 
    420   1.1  justin struct thread *
    421   1.1  justin init_mainthread(void *cookie)
    422   1.1  justin {
    423   1.1  justin 
    424   1.1  justin 	current_thread->cookie = cookie;
    425   1.1  justin 	return current_thread;
    426   1.1  justin }
    427   1.1  justin 
    428   1.1  justin /* rump functions below */
    429   1.1  justin 
    430   1.1  justin struct rumpuser_hyperup rumpuser__hyp;
    431   1.1  justin 
    432   1.1  justin int
    433   1.1  justin rumpuser_init(int version, const struct rumpuser_hyperup *hyp)
    434   1.1  justin {
    435   1.3  justin 	int rv;
    436   1.1  justin 
    437   1.1  justin 	if (version != RUMPUSER_VERSION) {
    438   1.1  justin 		printk("rumpuser version mismatch\n");
    439   1.3  justin 		abort();
    440   1.1  justin 	}
    441   1.1  justin 
    442   1.3  justin 	rv = rumpuser__random_init();
    443   1.3  justin 	if (rv != 0) {
    444   1.3  justin 		ET(rv);
    445   1.1  justin 	}
    446   1.1  justin 
    447  1.11  justin 	rumpuser__hyp = *hyp;
    448   1.1  justin 
    449   1.1  justin 	init_sched();
    450   1.1  justin 
    451  1.11  justin 	return 0;
    452   1.1  justin }
    453   1.1  justin 
    454   1.1  justin int
    455   1.1  justin rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec)
    456   1.1  justin {
    457   1.1  justin 	enum rumpclock rclk = enum_rumpclock;
    458   1.1  justin 	struct timespec ts;
    459   1.1  justin 	clockid_t clk;
    460   1.1  justin 	int rv;
    461   1.1  justin 
    462   1.1  justin 	switch (rclk) {
    463   1.1  justin 	case RUMPUSER_CLOCK_RELWALL:
    464   1.1  justin 		clk = CLOCK_REALTIME;
    465   1.1  justin 		break;
    466   1.1  justin 	case RUMPUSER_CLOCK_ABSMONO:
    467   1.1  justin 		clk = CLOCK_MONOTONIC;
    468   1.1  justin 		break;
    469   1.1  justin 	default:
    470   1.1  justin 		abort();
    471   1.1  justin 	}
    472   1.1  justin 
    473   1.1  justin 	if (clock_gettime(clk, &ts) == -1) {
    474   1.1  justin 		rv = errno;
    475   1.1  justin 	} else {
    476   1.1  justin 		*sec = ts.tv_sec;
    477   1.1  justin 		*nsec = ts.tv_nsec;
    478   1.1  justin 		rv = 0;
    479   1.1  justin 	}
    480   1.1  justin 
    481   1.1  justin 	ET(rv);
    482   1.1  justin }
    483   1.1  justin 
    484   1.1  justin int
    485   1.1  justin rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec)
    486   1.1  justin {
    487   1.1  justin 	enum rumpclock rclk = enum_rumpclock;
    488  1.12  justin 	uint64_t msec;
    489   1.1  justin 	int nlocks;
    490   1.1  justin 
    491   1.1  justin 	rumpkern_unsched(&nlocks, NULL);
    492   1.1  justin 	switch (rclk) {
    493   1.1  justin 	case RUMPUSER_CLOCK_RELWALL:
    494   1.1  justin 		msec = sec * 1000 + nsec / (1000*1000UL);
    495   1.1  justin 		msleep(msec);
    496   1.1  justin 		break;
    497   1.1  justin 	case RUMPUSER_CLOCK_ABSMONO:
    498   1.1  justin 		msec = sec * 1000 + nsec / (1000*1000UL);
    499   1.1  justin 		abssleep(msec);
    500   1.1  justin 		break;
    501   1.1  justin 	}
    502   1.1  justin 	rumpkern_sched(nlocks, NULL);
    503   1.1  justin 
    504   1.1  justin 	return 0;
    505   1.1  justin }
    506   1.1  justin 
    507   1.1  justin int
    508   1.1  justin rumpuser_getparam(const char *name, void *buf, size_t blen)
    509   1.1  justin {
    510   1.1  justin 	int rv;
    511   1.1  justin 	const char *ncpu = "1";
    512   1.1  justin 
    513   1.1  justin 	if (strcmp(name, RUMPUSER_PARAM_NCPU) == 0) {
    514   1.1  justin 		strncpy(buf, ncpu, blen);
    515   1.1  justin 		rv = 0;
    516   1.1  justin 	} else if (strcmp(name, RUMPUSER_PARAM_HOSTNAME) == 0) {
    517   1.1  justin 		char tmp[MAXHOSTNAMELEN];
    518   1.1  justin 
    519   1.1  justin 		if (gethostname(tmp, sizeof(tmp)) == -1) {
    520   1.1  justin 			snprintf(buf, blen, "rump-%05d", (int)getpid());
    521   1.1  justin 		} else {
    522   1.1  justin 			snprintf(buf, blen, "rump-%05d.%s",
    523   1.1  justin 			    (int)getpid(), tmp);
    524   1.1  justin 		}
    525   1.1  justin 		rv = 0;
    526   1.1  justin 	} else if (*name == '_') {
    527   1.1  justin 		rv = EINVAL;
    528   1.1  justin 	} else {
    529   1.1  justin 		if (getenv_r(name, buf, blen) == -1)
    530   1.1  justin 			rv = errno;
    531   1.1  justin 		else
    532   1.1  justin 			rv = 0;
    533   1.1  justin 	}
    534   1.1  justin 
    535   1.1  justin 	ET(rv);
    536   1.1  justin }
    537   1.1  justin 
    538   1.1  justin void
    539   1.1  justin rumpuser_putchar(int c)
    540   1.1  justin {
    541   1.1  justin 
    542   1.1  justin 	putchar(c);
    543   1.1  justin }
    544   1.1  justin 
    545   1.1  justin __dead void
    546   1.1  justin rumpuser_exit(int rv)
    547   1.1  justin {
    548   1.1  justin 
    549   1.1  justin 	if (rv == RUMPUSER_PANIC)
    550   1.1  justin 		abort();
    551   1.1  justin 	else
    552   1.1  justin 		exit(rv);
    553   1.1  justin }
    554   1.1  justin 
    555   1.1  justin void
    556   1.1  justin rumpuser_seterrno(int error)
    557   1.1  justin {
    558   1.1  justin 
    559   1.1  justin 	errno = error;
    560   1.1  justin }
    561   1.1  justin 
    562   1.1  justin /*
    563   1.1  justin  * This is meant for safe debugging prints from the kernel.
    564   1.1  justin  */
    565   1.1  justin void
    566   1.1  justin rumpuser_dprintf(const char *format, ...)
    567   1.1  justin {
    568   1.1  justin 	va_list ap;
    569   1.1  justin 
    570   1.1  justin 	va_start(ap, format);
    571   1.1  justin 	vfprintf(stderr, format, ap);
    572   1.1  justin 	va_end(ap);
    573   1.1  justin }
    574   1.1  justin 
    575   1.1  justin int
    576   1.1  justin rumpuser_kill(int64_t pid, int rumpsig)
    577   1.1  justin {
    578   1.1  justin 	int sig;
    579   1.1  justin 
    580   1.1  justin 	sig = rumpuser__sig_rump2host(rumpsig);
    581   1.1  justin 	if (sig > 0)
    582   1.1  justin 		raise(sig);
    583   1.1  justin 	return 0;
    584   1.1  justin }
    585   1.1  justin 
    586   1.1  justin /* thread functions */
    587   1.1  justin 
    588   1.1  justin TAILQ_HEAD(waithead, waiter);
    589   1.1  justin struct waiter {
    590   1.1  justin 	struct thread *who;
    591   1.1  justin 	TAILQ_ENTRY(waiter) entries;
    592   1.1  justin 	int onlist;
    593   1.1  justin };
    594   1.1  justin 
    595   1.1  justin static int
    596   1.1  justin wait(struct waithead *wh, uint64_t msec)
    597   1.1  justin {
    598   1.1  justin 	struct waiter w;
    599   1.1  justin 
    600   1.1  justin 	w.who = get_current();
    601   1.1  justin 	TAILQ_INSERT_TAIL(wh, &w, entries);
    602   1.1  justin 	w.onlist = 1;
    603   1.1  justin 	block(w.who);
    604   1.1  justin 	if (msec)
    605   1.1  justin 		w.who->wakeup_time = now() + msec;
    606   1.1  justin 	schedule();
    607   1.1  justin 
    608   1.1  justin 	/* woken up by timeout? */
    609   1.1  justin 	if (w.onlist)
    610   1.1  justin 		TAILQ_REMOVE(wh, &w, entries);
    611   1.1  justin 
    612   1.1  justin 	return w.onlist ? ETIMEDOUT : 0;
    613   1.1  justin }
    614   1.1  justin 
    615   1.1  justin static void
    616   1.1  justin wakeup_one(struct waithead *wh)
    617   1.1  justin {
    618   1.1  justin 	struct waiter *w;
    619   1.1  justin 
    620   1.1  justin 	if ((w = TAILQ_FIRST(wh)) != NULL) {
    621   1.1  justin 		TAILQ_REMOVE(wh, w, entries);
    622   1.1  justin 		w->onlist = 0;
    623   1.1  justin 		wake(w->who);
    624   1.1  justin 	}
    625   1.1  justin }
    626   1.1  justin 
    627   1.1  justin static void
    628   1.1  justin wakeup_all(struct waithead *wh)
    629   1.1  justin {
    630   1.1  justin 	struct waiter *w;
    631   1.1  justin 
    632   1.1  justin 	while ((w = TAILQ_FIRST(wh)) != NULL) {
    633   1.1  justin 		TAILQ_REMOVE(wh, w, entries);
    634   1.1  justin 		w->onlist = 0;
    635   1.1  justin 		wake(w->who);
    636   1.1  justin 	}
    637   1.1  justin }
    638   1.1  justin 
    639   1.1  justin int
    640   1.1  justin rumpuser_thread_create(void *(*f)(void *), void *arg, const char *thrname,
    641  1.11  justin 	int joinable, int pri, int cpuidx, void **tptr)
    642   1.1  justin {
    643  1.10  justin 	struct thread *thr;
    644  1.10  justin 
    645  1.10  justin 	thr = create_thread(thrname, NULL, (void (*)(void *))f, arg, NULL, 0);
    646  1.10  justin 
    647  1.10  justin 	if (!thr)
    648  1.10  justin 		return EINVAL;
    649   1.1  justin 
    650  1.11  justin 	/*
    651  1.11  justin 	 * XXX: should be supplied as a flag to create_thread() so as to
    652  1.11  justin 	 * _ensure_ it's set before the thread runs (and could exit).
    653  1.11  justin 	 * now we're trusting unclear semantics of create_thread()
    654  1.11  justin 	 */
    655  1.11  justin 	if (thr && joinable)
    656  1.11  justin 		thr->flags |= THREAD_MUSTJOIN;
    657   1.1  justin 
    658  1.11  justin 	*tptr = thr;
    659  1.11  justin 	return 0;
    660   1.1  justin }
    661   1.1  justin 
    662   1.1  justin void
    663   1.1  justin rumpuser_thread_exit(void)
    664   1.1  justin {
    665   1.1  justin 
    666  1.11  justin 	exit_thread();
    667   1.1  justin }
    668   1.1  justin 
    669   1.1  justin int
    670   1.1  justin rumpuser_thread_join(void *p)
    671   1.1  justin {
    672   1.1  justin 
    673  1.11  justin 	join_thread(p);
    674  1.11  justin 	return 0;
    675   1.1  justin }
    676   1.1  justin 
    677   1.1  justin struct rumpuser_mtx {
    678   1.1  justin 	struct waithead waiters;
    679   1.1  justin 	int v;
    680   1.1  justin 	int flags;
    681   1.1  justin 	struct lwp *o;
    682   1.1  justin };
    683   1.1  justin 
    684   1.1  justin void
    685   1.1  justin rumpuser_mutex_init(struct rumpuser_mtx **mtxp, int flags)
    686   1.1  justin {
    687   1.1  justin 	struct rumpuser_mtx *mtx;
    688   1.1  justin 
    689   1.1  justin 	mtx = malloc(sizeof(*mtx));
    690   1.1  justin 	memset(mtx, 0, sizeof(*mtx));
    691   1.1  justin 	mtx->flags = flags;
    692   1.1  justin 	TAILQ_INIT(&mtx->waiters);
    693   1.1  justin 	*mtxp = mtx;
    694   1.1  justin }
    695   1.1  justin 
    696  1.13   ozaki int
    697  1.13   ozaki rumpuser_mutex_spin_p(struct rumpuser_mtx *mtx)
    698  1.13   ozaki {
    699  1.13   ozaki 
    700  1.13   ozaki 	return (mtx->flags & RUMPUSER_MTX_SPIN) != 0;
    701  1.13   ozaki }
    702  1.13   ozaki 
    703   1.1  justin void
    704   1.1  justin rumpuser_mutex_enter(struct rumpuser_mtx *mtx)
    705   1.1  justin {
    706   1.1  justin 	int nlocks;
    707   1.1  justin 
    708   1.1  justin 	if (rumpuser_mutex_tryenter(mtx) != 0) {
    709   1.1  justin 		rumpkern_unsched(&nlocks, NULL);
    710   1.1  justin 		while (rumpuser_mutex_tryenter(mtx) != 0)
    711   1.1  justin 			wait(&mtx->waiters, 0);
    712   1.1  justin 		rumpkern_sched(nlocks, NULL);
    713   1.1  justin 	}
    714   1.1  justin }
    715   1.1  justin 
    716   1.1  justin void
    717   1.1  justin rumpuser_mutex_enter_nowrap(struct rumpuser_mtx *mtx)
    718   1.1  justin {
    719   1.1  justin 	int rv;
    720   1.1  justin 
    721   1.1  justin 	rv = rumpuser_mutex_tryenter(mtx);
    722   1.1  justin 	/* one VCPU supported, no preemption => must succeed */
    723   1.1  justin 	if (rv != 0) {
    724   1.1  justin 		printk("no voi ei\n");
    725   1.1  justin 	}
    726   1.1  justin }
    727   1.1  justin 
    728   1.1  justin int
    729   1.1  justin rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx)
    730   1.1  justin {
    731   1.1  justin 	struct lwp *l = get_current()->lwp;
    732   1.1  justin 
    733   1.1  justin 	if (mtx->v && mtx->o != l)
    734   1.1  justin 		return EBUSY;
    735   1.1  justin 
    736   1.1  justin 	mtx->v++;
    737   1.1  justin 	mtx->o = l;
    738   1.1  justin 
    739   1.1  justin 	return 0;
    740   1.1  justin }
    741   1.1  justin 
    742   1.1  justin void
    743   1.1  justin rumpuser_mutex_exit(struct rumpuser_mtx *mtx)
    744   1.1  justin {
    745   1.1  justin 
    746   1.1  justin 	assert(mtx->v > 0);
    747   1.1  justin 	if (--mtx->v == 0) {
    748   1.1  justin 		mtx->o = NULL;
    749   1.1  justin 		wakeup_one(&mtx->waiters);
    750   1.1  justin 	}
    751   1.1  justin }
    752   1.1  justin 
    753   1.1  justin void
    754   1.1  justin rumpuser_mutex_destroy(struct rumpuser_mtx *mtx)
    755   1.1  justin {
    756   1.1  justin 
    757   1.1  justin 	assert(TAILQ_EMPTY(&mtx->waiters) && mtx->o == NULL);
    758   1.1  justin 	free(mtx);
    759   1.1  justin }
    760   1.1  justin 
    761   1.1  justin void
    762   1.1  justin rumpuser_mutex_owner(struct rumpuser_mtx *mtx, struct lwp **lp)
    763   1.1  justin {
    764   1.1  justin 
    765   1.1  justin 	*lp = mtx->o;
    766   1.1  justin }
    767   1.1  justin 
    768   1.1  justin struct rumpuser_rw {
    769   1.1  justin 	struct waithead rwait;
    770   1.1  justin 	struct waithead wwait;
    771   1.1  justin 	int v;
    772   1.1  justin 	struct lwp *o;
    773   1.1  justin };
    774   1.1  justin 
    775   1.1  justin void
    776   1.1  justin rumpuser_rw_init(struct rumpuser_rw **rwp)
    777   1.1  justin {
    778   1.1  justin 	struct rumpuser_rw *rw;
    779   1.1  justin 
    780   1.1  justin 	rw = malloc(sizeof(*rw));
    781   1.1  justin 	memset(rw, 0, sizeof(*rw));
    782   1.1  justin 	TAILQ_INIT(&rw->rwait);
    783   1.1  justin 	TAILQ_INIT(&rw->wwait);
    784   1.1  justin 
    785   1.1  justin 	*rwp = rw;
    786   1.1  justin }
    787   1.1  justin 
    788   1.1  justin void
    789   1.1  justin rumpuser_rw_enter(int enum_rumprwlock, struct rumpuser_rw *rw)
    790   1.1  justin {
    791   1.1  justin 	enum rumprwlock lk = enum_rumprwlock;
    792   1.1  justin 	struct waithead *w = NULL;
    793   1.1  justin 	int nlocks;
    794   1.1  justin 
    795   1.1  justin 	switch (lk) {
    796   1.1  justin 	case RUMPUSER_RW_WRITER:
    797   1.1  justin 		w = &rw->wwait;
    798   1.1  justin 		break;
    799   1.1  justin 	case RUMPUSER_RW_READER:
    800   1.1  justin 		w = &rw->rwait;
    801   1.1  justin 		break;
    802   1.1  justin 	}
    803   1.1  justin 
    804   1.1  justin 	if (rumpuser_rw_tryenter(enum_rumprwlock, rw) != 0) {
    805   1.1  justin 		rumpkern_unsched(&nlocks, NULL);
    806   1.1  justin 		while (rumpuser_rw_tryenter(enum_rumprwlock, rw) != 0)
    807   1.1  justin 			wait(w, 0);
    808   1.1  justin 		rumpkern_sched(nlocks, NULL);
    809   1.1  justin 	}
    810   1.1  justin }
    811   1.1  justin 
    812   1.1  justin int
    813   1.1  justin rumpuser_rw_tryenter(int enum_rumprwlock, struct rumpuser_rw *rw)
    814   1.1  justin {
    815   1.1  justin 	enum rumprwlock lk = enum_rumprwlock;
    816   1.1  justin 	int rv;
    817   1.1  justin 
    818   1.1  justin 	switch (lk) {
    819   1.1  justin 	case RUMPUSER_RW_WRITER:
    820   1.1  justin 		if (rw->o == NULL) {
    821   1.1  justin 			rw->o = rumpuser_curlwp();
    822   1.1  justin 			rv = 0;
    823   1.1  justin 		} else {
    824   1.1  justin 			rv = EBUSY;
    825   1.1  justin 		}
    826   1.1  justin 		break;
    827   1.1  justin 	case RUMPUSER_RW_READER:
    828   1.1  justin 		if (rw->o == NULL && TAILQ_EMPTY(&rw->wwait)) {
    829   1.1  justin 			rw->v++;
    830   1.1  justin 			rv = 0;
    831   1.1  justin 		} else {
    832   1.1  justin 			rv = EBUSY;
    833   1.1  justin 		}
    834   1.1  justin 		break;
    835   1.1  justin 	default:
    836   1.1  justin 		rv = EINVAL;
    837   1.1  justin 	}
    838   1.1  justin 
    839   1.1  justin 	return rv;
    840   1.1  justin }
    841   1.1  justin 
    842   1.1  justin void
    843   1.1  justin rumpuser_rw_exit(struct rumpuser_rw *rw)
    844   1.1  justin {
    845   1.1  justin 
    846   1.1  justin 	if (rw->o) {
    847   1.1  justin 		rw->o = NULL;
    848   1.1  justin 	} else {
    849   1.1  justin 		rw->v--;
    850   1.1  justin 	}
    851   1.1  justin 
    852   1.1  justin 	/* standard procedure, don't let readers starve out writers */
    853   1.1  justin 	if (!TAILQ_EMPTY(&rw->wwait)) {
    854   1.1  justin 		if (rw->o == NULL)
    855   1.1  justin 			wakeup_one(&rw->wwait);
    856   1.1  justin 	} else if (!TAILQ_EMPTY(&rw->rwait) && rw->o == NULL) {
    857   1.1  justin 		wakeup_all(&rw->rwait);
    858   1.1  justin 	}
    859   1.1  justin }
    860   1.1  justin 
    861   1.1  justin void
    862   1.1  justin rumpuser_rw_destroy(struct rumpuser_rw *rw)
    863   1.1  justin {
    864   1.1  justin 
    865   1.1  justin 	free(rw);
    866   1.1  justin }
    867   1.1  justin 
    868   1.1  justin void
    869   1.1  justin rumpuser_rw_held(int enum_rumprwlock, struct rumpuser_rw *rw, int *rvp)
    870   1.1  justin {
    871   1.1  justin 	enum rumprwlock lk = enum_rumprwlock;
    872   1.1  justin 
    873   1.1  justin 	switch (lk) {
    874   1.1  justin 	case RUMPUSER_RW_WRITER:
    875   1.1  justin 		*rvp = rw->o == rumpuser_curlwp();
    876   1.1  justin 		break;
    877   1.1  justin 	case RUMPUSER_RW_READER:
    878   1.1  justin 		*rvp = rw->v > 0;
    879   1.1  justin 		break;
    880   1.1  justin 	}
    881   1.1  justin }
    882   1.1  justin 
    883   1.1  justin void
    884   1.1  justin rumpuser_rw_downgrade(struct rumpuser_rw *rw)
    885   1.1  justin {
    886   1.1  justin 
    887   1.1  justin 	assert(rw->o == rumpuser_curlwp());
    888   1.1  justin 	rw->v = -1;
    889   1.1  justin }
    890   1.1  justin 
    891   1.1  justin int
    892   1.1  justin rumpuser_rw_tryupgrade(struct rumpuser_rw *rw)
    893   1.1  justin {
    894   1.1  justin 
    895   1.1  justin 	if (rw->v == -1) {
    896   1.1  justin 		rw->v = 1;
    897   1.1  justin 		rw->o = rumpuser_curlwp();
    898   1.1  justin 		return 0;
    899   1.1  justin 	}
    900   1.1  justin 
    901   1.1  justin 	return EBUSY;
    902   1.1  justin }
    903   1.1  justin 
    904   1.1  justin struct rumpuser_cv {
    905   1.1  justin 	struct waithead waiters;
    906   1.1  justin 	int nwaiters;
    907   1.1  justin };
    908   1.1  justin 
    909   1.1  justin void
    910   1.1  justin rumpuser_cv_init(struct rumpuser_cv **cvp)
    911   1.1  justin {
    912   1.1  justin 	struct rumpuser_cv *cv;
    913   1.1  justin 
    914   1.1  justin 	cv = malloc(sizeof(*cv));
    915   1.1  justin 	memset(cv, 0, sizeof(*cv));
    916   1.1  justin 	TAILQ_INIT(&cv->waiters);
    917   1.1  justin 	*cvp = cv;
    918   1.1  justin }
    919   1.1  justin 
    920   1.1  justin void
    921   1.1  justin rumpuser_cv_destroy(struct rumpuser_cv *cv)
    922   1.1  justin {
    923   1.1  justin 
    924   1.1  justin 	assert(cv->nwaiters == 0);
    925   1.1  justin 	free(cv);
    926   1.1  justin }
    927   1.1  justin 
    928   1.1  justin static void
    929   1.1  justin cv_unsched(struct rumpuser_mtx *mtx, int *nlocks)
    930   1.1  justin {
    931   1.1  justin 
    932   1.1  justin 	rumpkern_unsched(nlocks, mtx);
    933   1.1  justin 	rumpuser_mutex_exit(mtx);
    934   1.1  justin }
    935   1.1  justin 
    936   1.1  justin static void
    937   1.1  justin cv_resched(struct rumpuser_mtx *mtx, int nlocks)
    938   1.1  justin {
    939   1.1  justin 
    940   1.1  justin 	/* see rumpuser(3) */
    941   1.1  justin 	if ((mtx->flags & (RUMPUSER_MTX_KMUTEX | RUMPUSER_MTX_SPIN)) ==
    942   1.1  justin 	    (RUMPUSER_MTX_KMUTEX | RUMPUSER_MTX_SPIN)) {
    943   1.1  justin 		rumpkern_sched(nlocks, mtx);
    944   1.1  justin 		rumpuser_mutex_enter_nowrap(mtx);
    945   1.1  justin 	} else {
    946   1.1  justin 		rumpuser_mutex_enter_nowrap(mtx);
    947   1.1  justin 		rumpkern_sched(nlocks, mtx);
    948   1.1  justin 	}
    949   1.1  justin }
    950   1.1  justin 
    951   1.1  justin void
    952   1.1  justin rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx)
    953   1.1  justin {
    954   1.1  justin 	int nlocks;
    955   1.1  justin 
    956   1.1  justin 	cv->nwaiters++;
    957   1.1  justin 	cv_unsched(mtx, &nlocks);
    958   1.1  justin 	wait(&cv->waiters, 0);
    959   1.1  justin 	cv_resched(mtx, nlocks);
    960   1.1  justin 	cv->nwaiters--;
    961   1.1  justin }
    962   1.1  justin 
    963   1.1  justin void
    964   1.1  justin rumpuser_cv_wait_nowrap(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx)
    965   1.1  justin {
    966   1.1  justin 
    967   1.1  justin 	cv->nwaiters++;
    968   1.1  justin 	rumpuser_mutex_exit(mtx);
    969   1.1  justin 	wait(&cv->waiters, 0);
    970   1.1  justin 	rumpuser_mutex_enter_nowrap(mtx);
    971   1.1  justin 	cv->nwaiters--;
    972   1.1  justin }
    973   1.1  justin 
    974   1.1  justin int
    975   1.1  justin rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx,
    976   1.1  justin 	int64_t sec, int64_t nsec)
    977   1.1  justin {
    978   1.1  justin 	int nlocks;
    979   1.1  justin 	int rv;
    980   1.1  justin 
    981   1.1  justin 	cv->nwaiters++;
    982   1.1  justin 	cv_unsched(mtx, &nlocks);
    983   1.1  justin 	rv = wait(&cv->waiters, sec * 1000 + nsec / (1000*1000));
    984   1.1  justin 	cv_resched(mtx, nlocks);
    985   1.1  justin 	cv->nwaiters--;
    986   1.1  justin 
    987   1.1  justin 	return rv;
    988   1.1  justin }
    989   1.1  justin 
    990   1.1  justin void
    991   1.1  justin rumpuser_cv_signal(struct rumpuser_cv *cv)
    992   1.1  justin {
    993   1.1  justin 
    994   1.1  justin 	wakeup_one(&cv->waiters);
    995   1.1  justin }
    996   1.1  justin 
    997   1.1  justin void
    998   1.1  justin rumpuser_cv_broadcast(struct rumpuser_cv *cv)
    999   1.1  justin {
   1000   1.1  justin 
   1001   1.1  justin 	wakeup_all(&cv->waiters);
   1002   1.1  justin }
   1003   1.1  justin 
   1004   1.1  justin void
   1005   1.1  justin rumpuser_cv_has_waiters(struct rumpuser_cv *cv, int *rvp)
   1006   1.1  justin {
   1007   1.1  justin 
   1008   1.1  justin 	*rvp = cv->nwaiters != 0;
   1009   1.1  justin }
   1010   1.1  justin 
   1011   1.1  justin /*
   1012   1.1  justin  * curlwp
   1013   1.1  justin  */
   1014   1.1  justin 
   1015   1.1  justin void
   1016   1.1  justin rumpuser_curlwpop(int enum_rumplwpop, struct lwp *l)
   1017   1.1  justin {
   1018   1.1  justin 	struct thread *thread;
   1019   1.1  justin 	enum rumplwpop op = enum_rumplwpop;
   1020   1.1  justin 
   1021   1.1  justin 	switch (op) {
   1022   1.1  justin 	case RUMPUSER_LWP_CREATE:
   1023   1.1  justin 	case RUMPUSER_LWP_DESTROY:
   1024   1.1  justin 		break;
   1025   1.1  justin 	case RUMPUSER_LWP_SET:
   1026   1.1  justin 		thread = get_current();
   1027   1.1  justin 		thread->lwp = l;
   1028   1.1  justin 		break;
   1029   1.1  justin 	case RUMPUSER_LWP_CLEAR:
   1030   1.1  justin 		thread = get_current();
   1031   1.1  justin 		assert(thread->lwp == l);
   1032   1.1  justin 		thread->lwp = NULL;
   1033   1.1  justin 		break;
   1034   1.1  justin 	}
   1035   1.1  justin }
   1036   1.1  justin 
   1037   1.1  justin struct lwp *
   1038   1.1  justin rumpuser_curlwp(void)
   1039   1.1  justin {
   1040   1.1  justin 
   1041   1.1  justin 	return get_current()->lwp;
   1042   1.1  justin }
   1043