angus@ (Angus Y. Montgomery) (01/30/91)
We are trying to port some code that does run on other MIPS platforms to the Iris. The assembler that does the context switching seems to be where the problem lies. I have been told that other people have had this problem, and overcame it by "leaving extra space on the stack for interrupts". If anyone feels at all intelligent when confronted by this stuff, or knows of anyone that fits this description, please get me in touch with you/them... The assembler code and a bit of doco for it is available for anyone eager to tackle it! If you think i should post it, then say it. thanx. -- angus@godzilla.cgl.rmit.oz.au
jmb@patton.wpd.sgi.com (Jim Barton) (02/06/91)
I assure you, context switching works fine in Irix :-) I assume that what your are porting is an application which does some kind of non-preemptive tasking within a single process. These kind of packages generally have two components to support context switching (and then you need a scheduler on top of them). First is a way to create a new stack for a thread of execution. This code is usually written in assembler, since it must change the stack pointer and create a new stack frame. When writing such code, a portion of the original stack must be copied because you want to return to the calling subroutine on the new stack. Clearly, you can never return from that routine, so it becomes a new "main", if you will, for that thread. The new stack area is usually statically allocated to some fixed size. Irix stores the complete context of an interrupted process on top of wherever the current stack pointer is pointing. It may be possible that the stack area allocated is not big enough for the threads. The second mechanism is setjmp/longjmp, which is used to switch tasks. So, to create a new task, one might code the following: #include <setjmp.h> extern jmp_buf scheduler; threadmain(char *threadstack, jmp_buf newthread, int (*func)()) { newstack(threadstack); <- running on passed stack area if (setjmp(newthread)) { (*func)(); longjmp(scheduler, 1); /*NOTREACHED*/ } oldstack(threadstack); } ... thescheduler() { setjmp(scheduler); /* ... pick a task to run ... */ longjmp(somethread, 1); /*NOTREACHED*/ } The following (working) stack switching code I produced some years ago: # include <regdef.h> # include <asm.h> LEAF(newstack) addu t5,a0,a1 # base of new stack li t0,6 # save 5 words of stack, + old sp sll t0,t0,2 # number of bytes subu t2,t5,t0 # start for copy move t0,t2 # save new sp addu t1,t0,sp # copy end address move t3,sp # copy start address sw sp,(t5) # save old sp loop: lw t4,(t3) # get a word addiu t3,t3,4 # bump count sw t4,(t2) # store the word addiu t2,t2,4 # and bump the destination count blt t3,t1,loop # do it again move sp,t0 # set top of new stack move fp,t0 # set new frame j ra # back to caller END(newstack) LEAF(oldstack) addu t5,a0,a1 # base of new stack lw sp,(t5) # get back old sp move fp,sp # get back old frame j ra # back to caller END(oldstack) -- Jim Barton Silicon Graphics Computer Systems jmb@sgi.com