• C

setjump,longjump, and thread

Hi folks,

Could you pls explain how setjump, longjump and thread work? Pls consider codes below:



void procA ()
{
while (1) {
printf ("procA\n");
threadYield ();
}
}


void procB ()
{
while (1) {
printf ("procB\n");
threadYield ();
}
}

void threadYield ()
{
Thread *switchTo;
int rtn;
switchTo = readyQueue.dequeue();
if (switchTo) {
readyQueue.enqueue (thisThread);
rtn = setjump (thisThread->env);
if (rtn==0)
longjump (toThread->env,1);
}
}

void main ()
{
Thread *thrA, *thrB;
thrA = threadCreate (procA,0);
thrB = threadCreate (procB,0);
threadStart (thrA);
threadStart (thrB);
threadJoin (thrA);
}
LVL 1
tiger0516Asked:
Who is Participating?
 
grg99Connect With a Mentor Commented:
This is what's known as a "glorious Klooooge".

Setjmp and longjmp were originally designed to let you do an OCCASIONAL jump out of some deeply nested code, back up to the main program.  Common uses would be:  your program has burrowed down deep, maybe 5 to 10 calls down into some low-level routine, say "GetNextByte".  Said routine detects some really bad error, so it can't continue, and it knows that the onylrecourse is to go back to the main loop, many call levels up.  Now it *could* pass back an error flag, to be checked by its caller, who also passes back an error flag to ITS caller, and so on and so forth.   Doable, but CLUMSY and prone to errors.   Another way would be to do a "goto MainLoop", but C doesnt have a inter-function goto.  The answer is to use setjmp and longjmp.    Now since you're buried soooo deep in calls, to do a jump to the main program requires a LOT of unwinding--  the call stack has to be restored to the state it was in at the main program, all the parameters have to be popped off the parameter stack (often the same stack as the call stack, but not always).  ANy exception catching calls have to be undone, again popping exception stack frames off the exception stack (almost always a different stack than the main call stack), AND Any external system state should be restored (but never is-- in a *good* language like Pascal, all file handles on the stack are closed), AND any CPOU state has to restored, ALL the CPU registers.   That's all tricky stuff, but one hopes has been coded correctly in setjmp/longjmp.

Then somebody noticed, since setjmp/longjmp save and restore the CPU state, that's a good bit of what exactly what you need to switch between "threads".   So one can use setjmp/longjmp to save the current program state, and jump to a new or suspended thread.

One glitch-- "threads" are usually given their own stack, so they can have their own local variables.  Setjmp/longjmp don't do this (without using yet another recursive call klooooodge to themselves).  So the threading code has to do something even klooodgier, like peek and poke into the save structure and set a fresgh stack pointer for each thread.  More kloodgy magic..

Hope this makes at least a bit of sense.



0
 
Kent OlsenConnect With a Mentor Data Warehouse Architect / DBACommented:
Hi tiger0516,

Not sure where you got this code, but you should shoot the author.  (Figuratively.)  I'm going to start my own campaign that any C code that is posted to the board with left-alignment (no indentation) be automatically deleted.  :)


A thread is nothing more than a second (or subsequent) execution point within a program or task.  As the coder, it's your responsibility to make sure that the threads (execution paths) don't conflict.

setjump() is a programmable way to define where to assign the processor within the program.  Conceptually it is similar to a thread except that it doesn't define a secondary execution path.  longjump() actually branches to the point defined by setjump().


The code that you've posted seems to take advantage of these tools to do it's own CPU management.  The threadYield() function reassigns the CPU if/when the dequeue function of readyQueue returns a thread for execution.



Good Luck!
Kent
0
 
cwwkieConnect With a Mentor Commented:
>    rtn = setjump (thisThread->env);
>    if (rtn==0)
>        longjump (toThread->env,1);

I think if this is working it is at least very unportable. afaik the call to longjump invalidates the setjump which has just been executed. Something like this would only be possible if the whole stack is saved.

I do however understand what is trying to been archieved. A general explanation is here: http://en.wikipedia.org/wiki/Coroutines

> I'm going to start my own campaign that any C code that is posted to the board with
> left-alignment (no indentation) be automatically deleted.  :)

where is the petition to sign?
0
Improve Your Query Performance Tuning

In this FREE six-day email course, you'll learn from Janis Griffin, Database Performance Evangelist. She'll teach 12 steps that you can use to optimize your queries as much as possible and see measurable results in your work. Get started today!

 
cryptosidCommented:
setjmp and longjmp has saved my life more than once :-) its good to use, if you know what you are doing.

So be careful :-)

Regards,
Siddhesh
0
 
Kent OlsenData Warehouse Architect / DBACommented:

setjmp and longjmp have never found their way into my code.  Never.

And they never will.....
Kent
0
 
cryptosidCommented:
I agree with Kent , they are dangerous.. just like goto statement.. if not used wisely you may end up in hell :-)

Anyways.. this is taking the conversation off track, but couldnt' resist it!

Regards,
Siddhesh
0
 
jinumjoyCommented:
if you end up requiring a setjmp, longjmp or goto in your code.. then its time you relooked at the design.. a well written code should never require these APIs.. we have grown way beyound them..

-Jinu
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.