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>