summaryrefslogtreecommitdiffstats
path: root/tools/KSE
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2002-06-29 17:39:07 +0000
committerjulian <julian@FreeBSD.org>2002-06-29 17:39:07 +0000
commit7f7eb2bfa105c9660bec6d45692060214c559f52 (patch)
tree6224a43119dbd43fa4c985d93ae964705e4cefca /tools/KSE
parentaa2dc0a5d9e7a19420c153cd414fefa8498eab71 (diff)
downloadFreeBSD-src-7f7eb2bfa105c9660bec6d45692060214c559f52.zip
FreeBSD-src-7f7eb2bfa105c9660bec6d45692060214c559f52.tar.gz
KSE test program
Diffstat (limited to 'tools/KSE')
-rw-r--r--tools/KSE/ksetest/Makefile20
-rw-r--r--tools/KSE/ksetest/kse_asm.S88
-rw-r--r--tools/KSE/ksetest/kse_threads_test.c275
3 files changed, 383 insertions, 0 deletions
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 <bsd.prog.mk>
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 <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
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 <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;
+}
+
OpenPOWER on IntegriCloud