312 lines
7.6 KiB
C
312 lines
7.6 KiB
C
#include <lwp/common.h>
|
|
#include <lwp/queue.h>
|
|
#include <machlwp/machdep.h>
|
|
#include <lwp/queue.h>
|
|
#include <lwp/lwperror.h>
|
|
#include <lwp/cntxt.h>
|
|
#include <lwp/process.h>
|
|
#include <lwp/schedule.h>
|
|
#include <lwp/alloc.h>
|
|
#include <lwp/condvar.h>
|
|
#include <lwp/monitor.h>
|
|
#ifndef lint
|
|
SCCSID(@(#) cntxt.c 1.1 92/07/30 Copyr 1987 Sun Micro);
|
|
#endif lint
|
|
|
|
int CtxType; /* memory type for context list entry in a lwp context */
|
|
|
|
/*
|
|
* List of save and restore routines and context sizes for all special
|
|
* contexts
|
|
*/
|
|
STATIC cntxt_actions_t SwtchActs[MAXSWTCHACTS];
|
|
|
|
/*
|
|
* Table to keep track of the special context to be saved lazily
|
|
*/
|
|
STATIC context_t *LazyCntxts[MAXSWTCHACTS];
|
|
|
|
/*
|
|
* Table to keep track of the pids belonging to lazy contexts
|
|
*/
|
|
STATIC lwp_t *LazyPids[MAXSWTCHACTS];
|
|
|
|
/*
|
|
* This file contains code for manipulating special context
|
|
* information that is saved/restored across context switches
|
|
* only for those lwps that request it (via lwp_cntxinit).
|
|
* Each context kind should provide routines to
|
|
* save into and restore from the context.
|
|
* Context is saved and restored lazily: only if a new thread uses
|
|
* the same special context type is an actual swutch done.
|
|
* Pure data may be stored in a context by specifying
|
|
* null save and restore routiines.
|
|
*
|
|
* PRIMITIVES contained herein:
|
|
* lwp_ctxinit(tid, ctx)
|
|
* lwp_ctxremove(tid, ctx)
|
|
* lwp_ctxset(saveproc, restoreproc, ctxsize, optimize)
|
|
* lwp_ctxmemget(mem, tid, ctx)
|
|
* lwp_ctxmemset(mem, tid, ctx)
|
|
*/
|
|
|
|
/*
|
|
* lwp_ctxinit -- PRIMITIVE.
|
|
* Announce that a given lwp is to have a special context
|
|
* save/restored across its context switches.
|
|
* We zero the memory.
|
|
*/
|
|
int
|
|
lwp_ctxinit(tid, ctx)
|
|
thread_t tid; /* thread with special contexts */
|
|
int ctx; /* type of context */
|
|
{
|
|
lwp_t *pid = (lwp_t *)(tid.thread_id);
|
|
register context_t *context;
|
|
register caddr_t ctxmem;
|
|
register __queue_t *cq;
|
|
register int size;
|
|
|
|
LWPINIT();
|
|
for (cq = FIRSTQ(&pid->lwp_ctx); cq != QNULL; cq = cq->q_next) {
|
|
if (ctx == ((context_t *)cq)->ctx_type) {
|
|
TERROR(LE_INUSE);
|
|
}
|
|
}
|
|
GETCHUNK((context_t *), context, CtxType);
|
|
context->ctx_type = ctx;
|
|
GETCHUNK((caddr_t), ctxmem, SwtchActs[ctx].cntxt_memtype);
|
|
context->ctx_mem = ctxmem;
|
|
size = MEMSIZE(SwtchActs[ctx].cntxt_memtype);
|
|
bzero(ctxmem, (u_int)size);
|
|
INS_QUEUE(&pid->lwp_ctx, context);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* lwp_ctxremove -- PRIMITIVE.
|
|
* Remove a previously-established special context for a given thread.
|
|
*/
|
|
int
|
|
lwp_ctxremove(tid, ctx)
|
|
thread_t tid; /* thread with special contexts */
|
|
int ctx; /* type of context */
|
|
{
|
|
register lwp_t *pid = (lwp_t *)(tid.thread_id);
|
|
register __queue_t *cq;
|
|
|
|
CLR_ERROR();
|
|
for (cq = FIRSTQ(&pid->lwp_ctx); cq != QNULL; cq = cq->q_next) {
|
|
if (ctx == ((context_t *)cq)->ctx_type) {
|
|
/*
|
|
* inefficient since this loops too, but shouldn't
|
|
* matter much since this operation is rare and
|
|
* queues should be short.
|
|
*/
|
|
REMX_ITEM(&pid->lwp_ctx, cq);
|
|
FREECHUNK(ctx, ((context_t *)cq)->ctx_mem);
|
|
if (LazyCntxts[ctx] == ((context_t *)cq)) {
|
|
LazyCntxts[ctx] = CONTEXTNULL;
|
|
LazyPids[ctx] = LWPNULL;
|
|
}
|
|
FREECHUNK(CtxType, ((context_t *)cq));
|
|
return (0);
|
|
}
|
|
}
|
|
TERROR(LE_NONEXIST);
|
|
}
|
|
|
|
/*
|
|
* lwp_ctxmemget -- PRIMITIVE.
|
|
* Return the memory associated with a context.
|
|
*/
|
|
int
|
|
lwp_ctxmemget(mem, tid, ctx)
|
|
register caddr_t mem;
|
|
thread_t tid;
|
|
int ctx;
|
|
{
|
|
lwp_t *pid = (lwp_t *)(tid.thread_id);
|
|
register __queue_t *q;
|
|
register caddr_t ctxmem;
|
|
register int size;
|
|
|
|
q = FIRSTQ(&pid->lwp_ctx);
|
|
while (q != QNULL) {
|
|
if (ctx == ((context_t *)q)->ctx_type) {
|
|
ctxmem = ((context_t *)q)->ctx_mem;
|
|
size = MEMSIZE(SwtchActs[ctx].cntxt_memtype);
|
|
bcopy(ctxmem, mem, (u_int)size);
|
|
break;
|
|
}
|
|
q = q->q_next;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* lwp_ctxmemset -- PRIMITIVE.
|
|
* Initialize the memory associated with a context.
|
|
*/
|
|
int
|
|
lwp_ctxmemset(mem, tid, ctx)
|
|
register caddr_t mem;
|
|
thread_t tid;
|
|
int ctx;
|
|
{
|
|
lwp_t *pid = (lwp_t *)(tid.thread_id);
|
|
register __queue_t *q;
|
|
register caddr_t ctxmem;
|
|
register int size;
|
|
|
|
q = FIRSTQ(&pid->lwp_ctx);
|
|
while (q != QNULL) {
|
|
if (ctx == ((context_t *)q)->ctx_type) {
|
|
ctxmem = ((context_t *)q)->ctx_mem;
|
|
size = MEMSIZE(SwtchActs[ctx].cntxt_memtype);
|
|
bcopy(mem, ctxmem, (u_int)size);
|
|
break;
|
|
}
|
|
q = q->q_next;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Define a switchable context.
|
|
* The cookie returned is used to subsequently tell the nugget that a given
|
|
* lwp will use this kind of context.
|
|
*/
|
|
int
|
|
lwp_ctxset(saveproc, restoreproc, ctxsize, optimize)
|
|
void (*saveproc)();
|
|
void (*restoreproc)();
|
|
unsigned int ctxsize;
|
|
int optimize; /* FALSE if switching is forced each time */
|
|
{
|
|
static int index = 0;
|
|
|
|
register int cookie = index++;
|
|
|
|
CLR_ERROR();
|
|
if (cookie >= MAXSWTCHACTS) {
|
|
SET_ERROR(__Curproc, LE_NOROOM);
|
|
return (-1);
|
|
}
|
|
SwtchActs[cookie].cntxt_save = saveproc;
|
|
SwtchActs[cookie].cntxt_restore = restoreproc;
|
|
SwtchActs[cookie].cntxt_memtype =
|
|
__allocinit(ctxsize, MAXCTX, IFUNCNULL, FALSE);
|
|
SwtchActs[cookie].cntxt_optimize = (bool_t)optimize;
|
|
LazyCntxts[cookie] = CONTEXTNULL;
|
|
LazyPids[cookie] = LWPNULL;
|
|
return (cookie);
|
|
}
|
|
|
|
void
|
|
__init_ctx()
|
|
{
|
|
CtxType = __allocinit(sizeof (context_t), MAXCONTEXT, IFUNCNULL, FALSE);
|
|
}
|
|
|
|
/*
|
|
* called when a process is destroyed to clean up any special contexts
|
|
*/
|
|
void
|
|
__freectxt(lwp)
|
|
register lwp_t *lwp;
|
|
{
|
|
register qheader_t *q = &(lwp->lwp_ctx);
|
|
register context_t *ctx;
|
|
register int type;
|
|
|
|
while (!ISEMPTYQ(q)) {
|
|
REM_QUEUE((context_t *), q, ctx);
|
|
type = ctx->ctx_type;
|
|
FREECHUNK(SwtchActs[type].cntxt_memtype, ctx->ctx_mem);
|
|
if (LazyCntxts[type] == ctx) {
|
|
LazyCntxts[type] = CONTEXTNULL;
|
|
LazyPids[type] = LWPNULL;
|
|
}
|
|
FREECHUNK(CtxType, ctx);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Save and restore special contexts using lazy evaluation.
|
|
*/
|
|
void
|
|
__ctx_change(old, new)
|
|
lwp_t *old;
|
|
lwp_t *new;
|
|
{
|
|
register __queue_t *q;
|
|
register int type;
|
|
register context_t *lazy;
|
|
register void (*func)();
|
|
thread_t oldt, newt;
|
|
|
|
newt.thread_id = (caddr_t)new;
|
|
if (new != LWPNULL)
|
|
newt.thread_key = new->lwp_lock;
|
|
|
|
/*
|
|
* save special contexts belonging to process being switched out
|
|
* by being lazy and just recording the address of the context
|
|
* to be saved and the thread using it.
|
|
* Need to do this loop even if old = new, since could have
|
|
* added contexts during thread execution.
|
|
*/
|
|
if (old != LWPNULL) {
|
|
for (q = FIRSTQ(&((old)->lwp_ctx)); q != QNULL; q = q->q_next) {
|
|
type = ((context_t *)q)->ctx_type;
|
|
func = SwtchActs[type].cntxt_save;
|
|
if (func == VFUNCNULL)
|
|
continue;
|
|
if (!SwtchActs[type].cntxt_optimize) { /* immed. save */
|
|
oldt.thread_id = (caddr_t)old;
|
|
oldt.thread_key = old->lwp_lock;
|
|
func(((context_t *)q)->ctx_mem, oldt, newt);
|
|
LazyCntxts[type] = CONTEXTNULL;
|
|
} else {
|
|
LazyCntxts[type] = (context_t *)q;
|
|
LazyPids[type] = old;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Restore special contexts belonging to process being switched in.
|
|
* It's possible that restore is done in the case save was never called.
|
|
*/
|
|
if (new != LWPNULL) {
|
|
for (q = FIRSTQ(&((new)->lwp_ctx)); q != QNULL; q = q->q_next) {
|
|
type = ((context_t *)q)->ctx_type;
|
|
lazy = LazyCntxts[type];
|
|
func = SwtchActs[type].cntxt_save;
|
|
oldt.thread_id = (caddr_t)LazyPids[type];
|
|
if (LazyPids[type] != LWPNULL)
|
|
oldt.thread_key = LazyPids[type]->lwp_lock;
|
|
if ((func != VFUNCNULL) &&
|
|
(lazy != (context_t *)q) &&
|
|
(old != LWPNULL) &&
|
|
(lazy != CONTEXTNULL)) {
|
|
func(lazy->ctx_mem, oldt, newt);
|
|
}
|
|
|
|
/*
|
|
* if thread destroyed, lazy is CONTEXTNULL
|
|
* and the new process still needs context
|
|
*/
|
|
func = SwtchActs[type].cntxt_restore;
|
|
if ((func != VFUNCNULL) &&
|
|
(!SwtchActs[type].cntxt_optimize ||
|
|
(lazy != (context_t *)q)) ||
|
|
old == LWPNULL) {
|
|
func(((context_t *)q)->ctx_mem, oldt, newt);
|
|
}
|
|
}
|
|
}
|
|
}
|