/*
 *  netbsd.c -- context switch code for NetBSD 2.
 *
 *  Some Makefile changes are needed to use this code.
 */

#include <ucontext.h>

void mpd_stk_underflow(void);
void mpd_stk_corrupted(void);

static void startup(void (*)(void), unsigned long, unsigned long, unsigned long, unsigned long);

#ifdef __i386__
void pthread__i386_init(void);

#define _setcontext_u(uc)	(*_md_setcontext_u)(uc)
#define _swapcontext_u(oc,nc)	(*_md_swapcontext_u)(oc,nc)

static void mpd_setcontext_u(ucontext_t *);
static void mpd_swapcontext_u(ucontext_t *, ucontext_t *);

void (*_md_getcontext_u) (ucontext_t *);
void (*_md_setcontext_u) (ucontext_t *)			= mpd_setcontext_u;
void (*_md_swapcontext_u)(ucontext_t *, ucontext_t *)	= mpd_swapcontext_u;

static void
mpd_setcontext_u(ucontext_t *uc) {
	pthread__i386_init();
	_setcontext_u(uc);
}

static void
mpd_swapcontext_u(ucontext_t *oldc, ucontext_t *newc) {
	pthread__i386_init();
	_swapcontext_u(oldc, newc);
}
#endif


/*
 *  mpd_build_context (func, buf, bufsize, arg1, arg2, arg3, arg4)
 *
 *  Build a context that will call func(arg1,arg2,arg3,arg4) when activated
 *  and will catch an underflow error if func returns.  We use an intermediary
 *  in order to catch that return.
 */
void
mpd_build_context (func, buf, bufsize, arg1, arg2, arg3, arg4)
void (*func)();
char *buf;
int bufsize;
unsigned long arg1, arg2, arg3, arg4;
{
    ucontext_t *uc = (ucontext_t *) buf;	/* put header at front of buf */

    if (0 != getcontext(uc)) {			/* initialize context */
	mpd_stk_corrupted();
    }

    uc->uc_stack.ss_sp = buf + sizeof (ucontext_t);
    uc->uc_stack.ss_size = bufsize - sizeof (ucontext_t);

    makecontext (uc, startup, 5, func, arg1, arg2, arg3, arg4);
    uc->uc_stack.ss_flags = 0;
}

/*
 *  startup (func, a,b,c,d) -- intermediary for startup and underflow detection.
 */
static void
startup (func, arg1, arg2, arg3, arg4)
void (*func)();
unsigned long arg1, arg2, arg3, arg4;
{
    (*func) (arg1, arg2, arg3, arg4);
    mpd_stk_underflow();
}



/*
 *  mpd_chg_context (newctx, oldctx) -- change contexts.
 */
void
mpd_chg_context (new, old)
char *new, *old;
{
    ucontext_t *oldu, *newu;
    newu = (ucontext_t *)new;

    if (old) {
	oldu = (ucontext_t *)old;
	_swapcontext_u(oldu, newu);
    } else {
	_setcontext_u(newu);
    }
}



/*
 *  mpd_check_stk (stk) -- check for stack overflow.
 *
 *  We have no idea of how to do that, so we do nothing.
 */
void
mpd_check_stk(stk)
char *stk;
{
    /* nothing */
}
