pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ) (03/22/91)
In article <104499@unix.cis.pitt.edu> bill@hpb.cis.pitt.edu (Bill Broadly) writes: > > I need a small C program that allows running more that >one thread, using setjmp, and longjmp, on a ms-dos machine. Nothing >pre-emptive needed. > Exactly what I wanted was in the Jan issue of C users Journal, >but I couldn't get it to work, and the author is in England (no Email >address). > Anybody out there have such a beast? Or get the one from the >magazine to work? > I don't want anything so involved as Ctask. I don't need real >multitasking just the ability for one process to say "I done for now, >next process can run". > I will happily mail the code to anyone if they want the >original (non-working) code from the article. > I have (bought) MSC 6.0 (with revision), MSC 5.1, TC++. > -Bill > Broadley@schneider3.lrdc.pitt.edu > >-- >Bill Broadley >Broadley@schneider3.lrdc.pitt.edu > "GISMO" This is a nice thought, but it doesn't work. I actually tried this scenario, but the problem is that all threads have the same stack. As soon as any one of them do a longjmp(), it throws away a piece of the stack. Then the next thread writes over the values that were written there when it uses the stack. When control gets back to the first thread, it can't continue where it left off because much of its stack, containing local variables, function arguments, and return addresses, is gone forever. There are certain very simple situations in which it seems to work, usually in a program called test.c :) If you test this method in such a way that the stack level is the same from one thread to another, then it will work by happenstance. But if you use it for any real work at all, then it will fail. Note that even if you try to design the threads so that the stack levels are the same, that doesn't guarantee that it will work, because the compiler may allocate different amounts of stack space for each thread to use as temporaries in evaluating expressions. The fundamental truth here is this: you MUST have a separate stack for each thread. There is no way around this. There is a way to do something similar to coroutines with setjmp/longjmp, but it is rather delicate and unelegant. Good idea, but it just doesn't work... -- Jeff D. Pipkins (pipkinsj@cpqhou.se.hou.COM or uunet!cpqhou!pipkinsj) Disclaimer: My opinions do not necessarily reflect those of my employer. "Things should be made as simple as possible, but no simpler" --Einstein
cadsi@ccad.uiowa.edu (CADSI) (03/23/91)
From article <1991Mar22.155529.22@cpqhou.uucp>, by pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ): > In article <104499@unix.cis.pitt.edu> bill@hpb.cis.pitt.edu (Bill Broadly) writes: >> > > This is a nice thought, but it doesn't work. I actually tried this scenario, > but the problem is that all threads have the same stack. As soon as any > one of them do a longjmp(), it throws away a piece of the stack. Then > the next thread writes over the values that were written there when it > uses the stack. When control gets back to the first thread, it can't > continue where it left off because much of its stack, containing local > variables, function arguments, and return addresses, is gone forever. > > There are certain very simple situations in which it seems to work, usually > in a program called test.c :) If you test this method in such a way > that the stack level is the same from one thread to another, then it will > work by happenstance. But if you use it for any real work at all, then > it will fail. Note that even if you try to design the threads so that > the stack levels are the same, that doesn't guarantee that it will work, > because the compiler may allocate different amounts of stack space for > each thread to use as temporaries in evaluating expressions. > > The fundamental truth here is this: you MUST have a separate stack for > each thread. There is no way around this. > > There is a way to do something similar to coroutines with setjmp/longjmp, > but it is rather delicate and unelegant. Actually, if you look through the back issues of Computer Language magazine, John Du Glosz (sp?) presented an article that did a similar procedure. He created stack arrays for each thread, and switched stacks as new threads came into scope. HOWEVER, he did not implement preemptive tasking, just Yield type calls. His algorithm is easily upgraded though. |----------------------------------------------------------------------------| |Tom Hite | The views expressed by me | |Manager, Product development | are mine, not necessarily | |CADSI (Computer Aided Design Software Inc. | the views of CADSI. | |----------------------------------------------------------------------------|
markh@csd4.csd.uwm.edu (Mark William Hopkins) (03/29/91)
In article <104499@unix.cis.pitt.edu> bill@hpb.cis.pitt.edu (Bill Broadly) writes: > I need a small C program that allows running more that >one thread, using setjmp, and longjmp, on a ms-dos machine. Nothing >pre-emptive needed. In article <1991Mar22.155529.22@cpqhou.uucp> pipkinsj@cpqhou.UUCP (Jeff Pipkins @Adv Dev@SE hou ) writes: >This is a nice thought, but it doesn't work. I actually tried this scenario, >but the problem is that all threads have the same stack. As soon as any >one of them do a longjmp(), it throws away a piece of the stack. You'll have to elaborate on this one. The longjmp() routine saves the current stack pointer, and whether a part of the stack is thrown away or not, when you start up the next thread with another longjmp() the stack pointer is switched there over to another completely different part of the stack segment before the previous part of the stack segment has had a chance to get corrupted. >There are certain very simple situations in which it seems to work, usually >in a program called test.c :) I actually got test.c to switch data segments under certain cases too thus allowing rudimentary swapping. :) >There is a way to do something similar to coroutines with setjmp/longjmp, >but it is rather delicate and unelegant. In the Empire Strikes Back, to Obi-Wan's lament "That boy is our last hope", Yoda said "No, there is another...". Don't leave us waiting 3 years. :)
resnicks@netcom.COM (Steve Resnick) (03/30/91)
In article <10592@uwm.edu> markh@csd4.csd.uwm.edu (Mark William Hopkins) writes: >In article <104499@unix.cis.pitt.edu> bill@hpb.cis.pitt.edu (Bill Broadly) writes: >> I need a small C program that allows running more that >>one thread, using setjmp, and longjmp, on a ms-dos machine. Nothing >>pre-emptive needed. > >In article <1991Mar22.155529.22@cpqhou.uucp> pipkinsj@cpqhou.UUCP (Jeff Pipkins @Adv Dev@SE hou ) writes: >>This is a nice thought, but it doesn't work. I actually tried this scenario, >>but the problem is that all threads have the same stack. As soon as any >>one of them do a longjmp(), it throws away a piece of the stack. > >You'll have to elaborate on this one. The longjmp() routine saves the current >stack pointer, and whether a part of the stack is thrown away or not, when >you start up the next thread with another longjmp() the stack pointer is >switched there over to another completely different part of the stack segment >before the previous part of the stack segment has had a chance to get corrupted. > If you don't switch stacks, anything which uses a reasonable amount of stack space will get munged pretty badly. I wrote a multi-thread thingy with Turbo C and assembler. The assembly piece is used to launch the new routine with a new stack. The assembler (for large model code) is: -------------------- Cut Here ---------- Cut Here -------------------------- .model large EXTRN _EndTask:FAR .code PUBLIC _StartTask ; ; Usage: StartTask( void far (*entrypt)(void),char far * Stack) ; ; StartTask sets up a new stack for a particular task, and then calls the ; task entry point. If the newly created task returns, EndTask() is called ; to invalidate the current task, and no more processing occurs. ; _StartTask PROC PUSH BP MOV BP,SP ; Save current stack frame MOV AX,[BP+12] ; Segment Address of New Stack MOV BX,[BP+10] ; Offset Address of New Stack MOV CX,[BP+8] ; Segment Address of entry point MOV DX,[BP+6] ; Offset Address of entry point MOV SS,AX ; Select new stack segment MOV SP,BX ; And set new stack pointer MOV AX,offset CEtsk ; Get IP Value for dummy return PUSH CS ; Make return segment point to here PUSH AX ; Make return offset point to CEtsk PUSH CX ; Push return CS PUSH DX ; Push Return IP RET CEtsk: CALL far ptr _EndTask ; EndTask is a routine which ; invalidates the current thread. _StartTask ENDP END ----------------------------------------------------------------------------- Have fun! :) Steve -- ------------------------------------------------------------------------------- resnicks@netcom.com, steve@camphq, IFNA: 1:143/105.0, USNail: 530 Lawrence Expressway, Suite 374 Sunnyvale, Ca 94086 - In real life: Steve Resnick. Flames, grammar and spelling errors >/dev/null 0x2b |~ 0x2b, THAT is the question. The Asylum OS/2 BBS - (408)263-8017 12/2400,8,1 - Running Maximus CBCS 1.2 -------------------------------------------------------------------------------