Home | History | Annotate | Line # | Download | only in librumpuser
rumpfiber.c revision 1.12.8.1
      1  1.12.8.1     snj /*	$NetBSD: rumpfiber.c,v 1.12.8.1 2018/01/13 21:57:11 snj 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.12.8.1     snj __RCSID("$NetBSD: rumpfiber.c,v 1.12.8.1 2018/01/13 21:57:11 snj 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.12.8.1     snj int
    697  1.12.8.1     snj rumpuser_mutex_spin_p(struct rumpuser_mtx *mtx)
    698  1.12.8.1     snj {
    699  1.12.8.1     snj 
    700  1.12.8.1     snj 	return (mtx->flags & RUMPUSER_MTX_SPIN) != 0;
    701  1.12.8.1     snj }
    702  1.12.8.1     snj 
    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