Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Feb 2002 19:17:36 -0800 (PST)
From:      Julian Elischer <julian@elischer.org>
To:        Glenn Gombert <ggombert@imatowns.com>
Cc:        arch@freebsd.org
Subject:   Re: simple KSE test program
Message-ID:  <Pine.BSF.4.21.0202051916190.88466-100000@InterJet.elischer.org>
In-Reply-To: <3.0.6.32.20020205201946.00d9eef8@imatowns.com>

next in thread | previous in thread | raw e-mail | index | archive | help
the version off my freebsd web page compiles and runs correctly
you need to make a new libc for it to link of course
(and need to have the new syscall definitions in teh kernel tree
for libc to find them.



On Tue, 5 Feb 2002, Glenn Gombert wrote:

> 
> 
> I have a kernel running with all the latest kse changes from cvsup10
> running on my dual PIII system (with SMP support commented out of the
> kernel config file) and it appears to be running most things well in
> 'uni-processor' mode. I am trying to get the protoype test program compiled
> below and was wondering if you had a compiled version working yet? Or shall
> I post mine as soon as I get it working.....
> 
> Glenn G. 
> 
> At 01:41 AM 1/24/2002 -0800, Julian Elischer wrote:
> >
> >Several people have asked how a KSE program would look.
> >
> >Here is a program I am writing for testing KSEs:
> >I hope to be using it within a day or two.
> >it includes 2 new syscalls (kse_new() and kse_yield()).
> >One function not yet written is the function loadthread()
> >which reads the registers in from the saved context in a user_thread
> >structure, in a similar way to how longjmp() does, but with 
> >more to load. I need to add that in a .s file.
> >
> >
> >First I include the kse include file:
> >  
> >#ifndef SYS_KSE_H
> >#define SYS_KSE_H
> >  
> >/*
> > * This file defines the structures needed for communication between 
> > * the userland and the kernel when running a KSE-based threading system.
> > * The only programs that should see this file are the UTS and the kernel.
> > */
> > 
> >/*
> > * Each userland thread has one of these buried in it's
> > * Thread control structure somewhere.
> > */
> >struct thread_mailbox
> >{
> >        struct thread_mailbox *next_completed;
> >        unsigned int    flags;
> >        void            *UTS_handle; /* UTS can use this for anything */
> >        mcontext_t      ctx;      /* thread's saved context goes here. */
> >/* The ctx field will become a union of types trapframe and mcontext_t
> >aligned accordingly. */
> >};
> > 
> > 
> >/*
> > * You need to supply one of these as the argument to the
> > * kse_new() system call.
> > */
> >struct kse_mailbox
> >{  
> >        struct thread_mailbox *current_thread;
> >        struct thread_mailbox *completed_threads;
> >        unsigned int    flags;
> >        void            *UTS_handle;    /* The UTS can use this for
> >anything */
> >};
> >#define KEMBXF_CRITICAL 0x00000001
> > 
> >struct kse_global_mailbox
> >{  
> >        unsigned int    flags;
> >};
> >#define GMBXF_CRITICAL 0x00000001
> > 
> >/* some provisional sycalls: */
> >
> >int     kse_new(struct kse_mailbox *mbx, int new_grp_flag);
> >int     kse_exit(void);                 /* last will clear KSE mode */
> >int     thread_wakeup(struct thread_mailbox *tmbx); /* make it complete */
> >int     kse_wakeup(void);               /* wake any idle KSEs */
> >void	kse_yield(void);		/* this kse can become idle */
> >
> >---------------------------------------------------------------
> >and here is the program.
> >
> >Only the last 4 functions should be in the program itself.
> >All the rest make up the basis of what would be in a library.
> >In fact some of what is done in main() might even be abstracted too.
> >
> >I hope to be testing this within a couple of days (given a few cleanups
> >and loose-ends to fix)
> >----------
> >
> > 
> >#include <stdio.h>
> >#include <stdlib.h>
> >#include <setjmp.h>
> >#include <sys/kse.h>
> > 
> >/*************************************************************  
> > * 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;
> >        struct user_thread *runq_next; 
> >};
> >
> >struct per_kse {
> >        struct kse_mailbox *mbox;
> >        struct user_thread *curthread
> >};      
> >/*************************************************************
> > * Debug stuff
> > **************************************************************/
> >
> >#if 0
> >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]);
> >        }
> >}
> >#endif
> >/*************************************************************
> > * Globals
> > **************************************************************/
> >struct per_kse first_kse; /* for NOW cheat and make it global */
> >struct user_thread *runqueue;
> >struct user_thread **runq_last;
> >/*************************************************************
> > * 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)
> >{
> >        thread->runq_next = NULL;
> >        *runq_last = thread;
> >        runq_last = &thread->runq_next;
> >}
> >         
> >static struct user_thread *
> >select_thread(void)
> >{
> >        struct user_thread *thread;
> >        if ((thread = runqueue)) {
> >                if ((runqueue = thread->runq_next) == NULL) {
> >                        runq_last = &runqueue;
> >                }
> >        }
> >        return (thread);
> >}
> >
> >/*************************************************************
> > * The UTS upcall entrypoint
> > * Called once on startup (and left by longjump)
> > * and there-after, returned to by the upcall many times.
> > **************************************************************/
> >static void
> >UTS(struct _jmp_buf *jb1, struct per_kse *ksedata, int newgroup)
> >{
> >        struct kse_mailbox ke_mbox;
> >        struct user_thread *thread;
> >        struct thread_mailbox *completed;
> >
> >        /* Let the caller know where our mailbox is */
> >        ksedata->mbox = &ke_mbox;
> >        ke_mbox.UTS_handle = ksedata;
> >
> >        if (kse_new(&ke_mbox, newgroup)) {      /* initial call returns */
> >                _longjmp(jb1, 1); /* go back to caller's stack and caller
> >*/
> >                /* NOTREACHED */
> >        }
> >
> >        /**********************************/
> >        /* UTS upcall starts running here. */
> >        /**********************************/
> >        /**********************************/
> >        printf("we are in the UTS with mailbox at 0x%x\n", &ke_mbox);
> >
> >        /* If there are returned syscall threads, put them on the run
> >queue */
> >        if ((completed = ke_mbox.completed_threads)) {
> >                ke_mbox.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.current_thread = &thread->mbox;
> >                loadthread(thread) /* loads context similar to
> >longjmp() */
> >                /* NOTREACHED */
> >        }
> >        kse_yeild();     /* 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;
> >        int i;
> >
> >        newstack = malloc(K_STACKSIZE);
> >        printf("newstack is at 0x%x-0x%x\n",
> >		newstack, newstack + K_STACKSIZE);
> >        if (_setjmp(jb1) == 0) {
> >                if (_setjmp(jb2) == 0) {
> >                        jb2[0]._jb[2] = &newstack[K_STACKSIZE - 16];
> >                        _longjmp(jb2, 1);
> >                }
> >                /* running with a different SP */
> >                {
> >                        /* Get all the rest set up. */
> >                        UTS(&jb1[0], ksedata, newgroup);
> >                        /* NOTREACHED */
> >                }
> >        }
> >        return(1);
> >}
> >
> >
> >static struct kse_mailbox *
> >startkse(struct per_kse *ksedata)
> >{
> >        return (kickkse(ksedata, 0));
> >}
> >
> >static struct kse_mailbox *
> >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.trapframe.tf_isp);
> >        *--SP = value;
> >        tcb->mbox.ctx.trapframe.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);
> >
> >
> >        /* set the PC to the fn */
> >        tcb->mbox.ctx.trapframe.tf_eip = fn;
> >
> >        /* Set the stack and push on the args and a dammy return address
> >*/
> >        tcb->mbox.ctx.trapframe.tf_isp = tcb->stack + tcb->stack_size -
> >16;
> >        pushontostack(tcb, (int)arg2);
> >        pushontostack(tcb, (int)arg1);
> >        pushontostack(tcb, (int)&badreturn); /* safety return address */
> >}
> >
> >/*************************************************************
> > * 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);
> >        }
> >}
> >
> >
> >
> >static struct thread_mailbox *
> >main()
> >{
> >        struct kse_mailbox *k_mbox;
> >
> >        /* set up global structures */
> >        runq_last = &runqueue;
> >        runqueue = NULL;
> >
> >        /* 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 */
> >        firstkse->curthread = makethread(&thread3_code, 0, NULL);
> >
> >        /* start two KSEs in different KSEGRPs */
> >        k_mbox = startkse(&first_kse);
> >
> >        /* 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 */
> >        firstkse->mbox->current_thread = curthread->mbox;
> >        thread3_code(NULL);
> >}
> >
> >
> >
> >
> >To Unsubscribe: send mail to majordomo@FreeBSD.org
> >with "unsubscribe freebsd-arch" in the body of the message
> >
> Glenn Gombert
> ggombert@imatowns.com
> 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0202051916190.88466-100000>