NetBSD-5.0.2/sys/rump/librump/rumpkern/intr.c

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: intr.c,v 1.9 2008/10/30 01:54:25 christos Exp $	*/

/*
 * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/cpu.h>
#include <sys/kthread.h>
#include <sys/intr.h>

#include <rump/rumpuser.h>

#include "rump_private.h"

/*
 * Interrupt simulator.  It executes hardclock() and softintrs.
 */

time_t time_uptime = 1;

struct softint {
	void (*si_func)(void *);
	void *si_arg;
	bool si_onlist;
	bool si_mpsafe;

	LIST_ENTRY(softint) si_entries;
};
static LIST_HEAD(, softint) si_pending = LIST_HEAD_INITIALIZER(si_pending);
static kmutex_t si_mtx;
static kcondvar_t si_cv;

static void
intr_worker(void *arg)
{
	struct softint *si;
	void (*func)(void *) = NULL;
	void *funarg = NULL; /* XXX gcc */
	bool mpsafe = false; /* XXX gcc */
	int ticks;

	for (ticks = 0;;ticks++) {
		/*
		 * XXX: not exactly executed once per tick, but without
		 * a proper timer ticktocking we don't really care.
		 */
		callout_hardclock();

		/* advance uptime with the same leisurely attitude */
		if (ticks & 0x80) {
			time_uptime++;
			ticks = 0;
		}

		mutex_enter(&si_mtx);
		if (LIST_EMPTY(&si_pending)) {
			cv_timedwait(&si_cv, &si_mtx, 1);
		} else {
			si = LIST_FIRST(&si_pending);
			func = si->si_func;
			funarg = si->si_arg;
			mpsafe = si->si_mpsafe;

			si->si_onlist = false;
			LIST_REMOVE(si, si_entries);
		}
		mutex_exit(&si_mtx);

		if (func) {
			if (!mpsafe)
				KERNEL_LOCK(1, curlwp);
			func(funarg);
			func = NULL;
			if (!mpsafe)
				KERNEL_UNLOCK_ONE(curlwp);
		}
	}
}

void
softint_init(struct cpu_info *ci)
{
	int rv;

	mutex_init(&si_mtx, MUTEX_DEFAULT, IPL_NONE);
	cv_init(&si_cv, "intrw8");

	/* XXX: should have separate "wanttimer" control */
	if (rump_threads) {
		rv = kthread_create(PRI_NONE, 0, NULL, intr_worker, NULL, NULL,
		    "rumpmtr");
		if (rv)
			panic("timer thread creation failed %d", rv);
	}
}

/*
 * Soft interrupts bring two choices.  If we are running with thread
 * support enabled, defer execution, otherwise execute in place.
 * See softint_schedule().
 * 
 * As there is currently no clear concept of when a thread finishes
 * work (although rump_clear_curlwp() is close), simply execute all
 * softints in the timer thread.  This is probably not the most
 * efficient method, but good enough for now.
 */
void *
softint_establish(u_int flags, void (*func)(void *), void *arg)
{
	struct softint *si;

	si = kmem_alloc(sizeof(*si), KM_SLEEP);
	si->si_func = func;
	si->si_arg = arg;
	si->si_onlist = false;
	si->si_mpsafe = flags & SOFTINT_MPSAFE;

	return si;
}

void
softint_schedule(void *arg)
{
	struct softint *si = arg;

	if (!rump_threads) {
		si->si_func(si->si_arg);
	} else {
		mutex_enter(&si_mtx);
		if (!si->si_onlist) {
			LIST_INSERT_HEAD(&si_pending, si, si_entries);
			si->si_onlist = true;
		}
		cv_signal(&si_cv);
		mutex_exit(&si_mtx);
	}
}

bool
cpu_intr_p(void)
{

	return false;
}