KSE test program

This commit is contained in:
Julian Elischer 2002-06-29 17:39:07 +00:00
parent e602ba25fd
commit 92fd482f2b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=99073
3 changed files with 383 additions and 0 deletions

View file

@ -0,0 +1,20 @@
# $FreeBSD$
# @(#)Makefile 8.1 (Berkeley) 6/2/93
PROG= ksetest
SRCS= kse_threads_test.c kse_asm.S
#
# To support "lazy" ps for non root/wheel users
# add -DLAZY_PS to the cflags. This helps
# keep ps from being an unnecessary load
# on large systems.
#
CFLAGS=-static -g -O
#WARNS= 0
#DPADD= ${LIBM} ${LIBKVM}
#LDADD= -lm -lkvm
#BINGRP= kmem
#BINMODE=2555
NOMAN=yes
.include <bsd.prog.mk>

View file

@ -0,0 +1,88 @@
/*-
* $FreeBSD$
*/
#include <machine/asmacros.h>
/*****************************************************************************/
/* Scheduling */
/*****************************************************************************/
.data
.text
#define TF_GS -0x04 /* don't laugh! */
#define TF_FS 0x00
#define TF_ES 0x04
#define TF_DS 0x08
#define TF_EDI 0x0c
#define TF_ESI 0x10
#define TF_EBP 0x14
#define TF_ISP 0x18
#define TF_EBX 0x1c
#define TF_EDX 0x20
#define TF_ECX 0x24
#define TF_EAX 0x28
#define TF_TRAPNO 0x2c
#define TF_ERR 0x30
#define TF_EIP 0x34
#define TF_CS 0x38
#define TF_EFLAGS 0x3c
#define TF_ESP 0x40
#define TF_SS 0x44
/*
* savethread
*/
GEN_ENTRY(savethread)
/* Switch to new thread. First, save context as needed. */
pushl %edx
movl 8(%esp), %edx /* get context area */
movl %eax,TF_EAX(%edx)
movl %ebx,TF_EBX(%edx)
movl %ecx,TF_ECX(%edx)
popl %eax /* get dx off the stack again */
movl %eax,TF_EDX(%edx)
movl (%esp),%eax /* get the return address */
movl %eax,TF_EIP(%edx)
movl %esp,TF_ESP(%edx)
movl %esp,TF_ISP(%edx) /* XXX */
movl %ebp,TF_EBP(%edx)
movl %esi,TF_ESI(%edx)
movl %edi,TF_EDI(%edx)
movl %cs,TF_CS(%edx)
movl %ds,TF_DS(%edx)
movl %es,TF_ES(%edx)
movl %fs,TF_FS(%edx)
movl %gs,TF_GS(%edx)
ret
GEN_ENTRY(loadthread)
mov 4(%esp), %edx /* get context area */
/* movl TF_ISP(%edx), %esp */ /* select which is correct */
movl TF_ESP(%edx), %esp /* get the new stack online */
movl TF_EBP(%edx), %ebp
movl TF_EIP(%edx),%eax
push %eax /* return adddress */
#if 0
movl TF_CS(%edx), %cs
movl TF_DS(%edx), %ds
movl TF_ES(%edx), %es
movl TF_FS(%edx), %fs
movl TF_GS(%edx), %gs
#endif
movl TF_ESI(%edx), %esi
movl TF_EDI(%edx), %edi
movl TF_EDX(%edx), %eax
pushl %eax
movl TF_ECX(%edx), %ecx
movl TF_EBX(%edx), %ebx
movl TF_EAX(%edx), %eax
popl %edx
ret

View file

@ -0,0 +1,275 @@
/*
* $FreeBSD$
*/
#define _KERNEL
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <sys/kse.h>
#include <sys/queue.h>
/*#define DEBUG*/
/*************************************************************
* These should probably be in a .h file
**************************************************************/
typedef void thread_fn(void *arg);
struct user_thread {
struct thread_mailbox mbox;
char *stack;
int stack_size;
TAILQ_ENTRY(user_thread) runq_next;
};
struct per_kse {
struct kse_mailbox mbox;
struct user_thread *curthread;
};
/*************************************************************
* Debug stuff
**************************************************************/
#ifdef DEBUG
jmp_buf jb3;
#define DUMPREGS(desc) do {_setjmp(jb3); printjb(jb3, desc); } while (0)
char *regname[] = {"%eip","%ebx","%esp","%ebp",
"%esi","%edi","fpcr","MSK0",
"MSK1","MSK2","MSK3"};
static
printjb(struct _jmp_buf *jb, char *desc)
{
int i;
printf("jb (%s) is at 0x%x\n", desc, jb);
for( i = 0; i< _JBLEN-4; i++) {
printf("jb[%d] (%s) = 0x%x\n", i, regname[i], jb[0]._jb[i]);
}
}
#else
#define DUMPREGS(desc) do {} while (0)
#endif
/*************************************************************
* Globals
**************************************************************/
struct per_kse first_kse; /* for NOW cheat and make it global */
TAILQ_HEAD(, user_thread) runqueue = TAILQ_HEAD_INITIALIZER(runqueue);
/*************************************************************
* Implementation parameters
**************************************************************/
#define T_STACKSIZE (16*4096) /* thread stacksize */
#define K_STACKSIZE (1*4096) /* KSE (UTS) stacksize */
/*************************************************************
* UTS funcions.
* Simple round_robin for now.
**************************************************************/
static void
runq_insert(struct user_thread *thread)
{
TAILQ_INSERT_TAIL(&runqueue, thread, runq_next);
}
static struct user_thread *
select_thread(void)
{
struct user_thread *thread;
if ((thread = TAILQ_FIRST(&runqueue))) {
TAILQ_REMOVE(&runqueue, thread, runq_next);
}
return (thread);
}
/*************************************************************
* The UTS upcall entrypoint
* Called once on startup (and left by longjump)
* and there-after, returned to by the upcall many times.
**************************************************************/
void
UTS(struct kse_mailbox *ke_mbox)
{
struct user_thread *thread;
struct thread_mailbox *completed;
struct per_kse *ksedata;
int done = 0;
/**********************************/
/* UTS upcall starts running here. */
/**********************************/
/**********************************/
ksedata = ke_mbox->kmbx_UTS_handle;
/* If there are returned syscall threads, put them on the run queue */
if ((completed = ke_mbox->kmbx_completed_threads)) {
ke_mbox->kmbx_completed_threads = NULL;
while (completed) {
thread = completed->UTS_handle;
completed = completed->next_completed;
runq_insert(thread);
}
}
/* find highest priority thread and load it */
if ((thread = select_thread())) {
ksedata->curthread = thread;
ke_mbox->kmbx_current_thread = &thread->mbox;
/* loads context similar to longjmp() */
loadthread(&thread->mbox.ctx.tfrm.tf_tf);
/* NOTREACHED */
}
kse_yield(); /* in the kernel it does a thread_exit() */
/* NOTREACHED */
}
/*************************************************************
* Startup mechanism functions
**************************************************************/
static int
kickkse(struct per_kse *ksedata, int newgroup)
{
char * newstack;
jmp_buf jb1;
jmp_buf jb2;
struct kse_mailbox *mboxaddr;
struct per_kse *user_UTS_info;
int err;
newstack = malloc(K_STACKSIZE);
mboxaddr = &ksedata->mbox;
mboxaddr->kmbx_stackbase = newstack;
mboxaddr->kmbx_stacksize = K_STACKSIZE;
mboxaddr->kmbx_upcall = &UTS;
mboxaddr->kmbx_UTS_handle = ksedata;
err = kse_new(mboxaddr, newgroup);
return(err);
}
static int
startkse(struct per_kse *ksedata)
{
return (kickkse(ksedata, 0));
}
static int
startksegrp(struct per_kse *ksedata)
{
return(kickkse(ksedata, 1));
}
void badreturn()
{
printf("thread returned when shouldn't\n");
exit(1);
}
__inline__ void
pushontostack(struct user_thread *tcb, int value)
{
int *SP;
SP = (int *)(tcb->mbox.ctx.tfrm.tf_tf.tf_isp);
*--SP = value;
tcb->mbox.ctx.tfrm.tf_tf.tf_isp = (int)SP;
}
struct user_thread *
makethread(thread_fn *fn, int arg1, void *arg2)
{
struct user_thread *tcb;
/* We could combine these mallocs */
tcb = malloc(sizeof *tcb);
bzero(tcb, sizeof(*tcb));
tcb->mbox.UTS_handle = tcb; /* back pointer */
/* malloc the thread's stack */
/* We COULD mmap it with STACK characteristics */
/* Then we could add a guard page. */
tcb->stack_size = T_STACKSIZE; /* set the size we want */
tcb->stack = malloc(tcb->stack_size);
/* Make sure there are good defaults */
savethread(&tcb->mbox.ctx.tfrm.tf_tf);
/* set the PC to the fn */
tcb->mbox.ctx.tfrm.tf_tf.tf_eip = (int) fn;
/* Set the stack and push on the args and a dummy return address */
tcb->mbox.ctx.tfrm.tf_tf.tf_ebp =
tcb->mbox.ctx.tfrm.tf_tf.tf_isp =
tcb->mbox.ctx.tfrm.tf_tf.tf_esp =
(int)(&tcb->stack[tcb->stack_size - 16]);
pushontostack(tcb, (int)arg2);
pushontostack(tcb, (int)arg1);
pushontostack(tcb, (int)&badreturn); /* safety return address */
return (tcb);
}
/*************************************************************
* code for three separate threads. (so we can see if it works)
*************************************************************/
static void
thread1_code(void *arg)
{
for(;;) {
sleep (1);
write(1,".",1);
}
}
static void
thread2_code(void *arg)
{
for(;;) {
sleep (3);
write(1,"+",1);
}
}
static void
thread3_code(void *arg)
{
for(;;) {
sleep (5);
write(1,"=",1);
}
}
int main()
{
/* set up global structures */
TAILQ_INIT(&runqueue);
/* define two threads to run, they are runnable but not yet running */
runq_insert( makethread(&thread1_code, 0, NULL));
runq_insert( makethread(&thread2_code, 0, NULL));
/* and one which we will run ourself */
first_kse.curthread = makethread(&thread3_code, 0, NULL);
/* start two KSEs in different KSEGRPs */
if (startkse(&first_kse)) {
perror("failed to start KSE");
exit(1);
}
/* startksegrp(&second_kse); */ /* we can't do 2 KSEs yet */
/* One will be sufficient */
/* we are a thread, start the ball rolling */
/* let the kernel know we are it */
first_kse.mbox.kmbx_current_thread = &first_kse.curthread->mbox;
thread3_code(NULL);
return 0;
}