From 7f7eb2bfa105c9660bec6d45692060214c559f52 Mon Sep 17 00:00:00 2001 From: julian Date: Sat, 29 Jun 2002 17:39:07 +0000 Subject: KSE test program --- tools/KSE/ksetest/Makefile | 20 +++ tools/KSE/ksetest/kse_asm.S | 88 +++++++++++ tools/KSE/ksetest/kse_threads_test.c | 275 +++++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+) create mode 100644 tools/KSE/ksetest/Makefile create mode 100644 tools/KSE/ksetest/kse_asm.S create mode 100644 tools/KSE/ksetest/kse_threads_test.c (limited to 'tools') diff --git a/tools/KSE/ksetest/Makefile b/tools/KSE/ksetest/Makefile new file mode 100644 index 0000000..f7bb415 --- /dev/null +++ b/tools/KSE/ksetest/Makefile @@ -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 diff --git a/tools/KSE/ksetest/kse_asm.S b/tools/KSE/ksetest/kse_asm.S new file mode 100644 index 0000000..a12358c --- /dev/null +++ b/tools/KSE/ksetest/kse_asm.S @@ -0,0 +1,88 @@ +/*- + * $FreeBSD$ + */ + +#include + +/*****************************************************************************/ +/* 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 diff --git a/tools/KSE/ksetest/kse_threads_test.c b/tools/KSE/ksetest/kse_threads_test.c new file mode 100644 index 0000000..fb4f22e --- /dev/null +++ b/tools/KSE/ksetest/kse_threads_test.c @@ -0,0 +1,275 @@ +/* + * $FreeBSD$ + */ +#define _KERNEL + +#include +#include +#include +#include +#include + +/*#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; +} + -- cgit v1.1