Jump to content

Recommended Posts

I am porting code that uses setjmp/longjmp. I can't find a reference to it in the SourceBoost documentation.

 

Is it available?

 

If not, does anyone have code that will implement it?

 

Tks

Share this post


Link to post
Share on other sites

JMoore,

I am porting code that uses setjmp/longjmp. I can't find a reference to it in the SourceBoost documentation.
What are setjmp/longjmp used for ?

 

Regards

Dave

Share this post


Link to post
Share on other sites
JMoore,
I am porting code that uses setjmp/longjmp. I can't find a reference to it in the SourceBoost documentation.
What are setjmp/longjmp used for ?

 

Regards

Dave

setjmp/longjmp are used sort of like Java exceptions - to allow control to jump out of multiple levels of subroutine calls. It is part of ANSI C.

 

In my case, I have a user interface that makes calls in many places to input routines, some of which themselves call lower level routines.

 

I need to have an input timeout, so that when it times out, control jumps back up out of the user interface.

 

Example:

jmp_buf abortJmpBuf; // The buffer for holding the jump context

 

...

// Arm the timeout escape

c = setjmp(abortJmpBuf); // If longjmp is called, it will look like a return from this

if ( c == MY_TIMEOUT ) { // See if longjump popped us back to here

return MY_ERROR; // Yes - leave user interface

}

 

// ... somewhere deep in low level subroutines

if ( timedOut ) {

longjmp(abortJmpBuf, MY_TIMEOUT);

}

 

 

 

Share this post


Link to post
Share on other sites

The problem with a command like this on a tiny PIC is the ability to overflow or crash the hardware stack. Every time a function is called from within a function the return address of the calling function is placed on the hardware stack. Do this enough times and the stack overflows. Jumping way out from deeply nested subroutines will leave the stack a mess because none of the “stacked” addresses will be cleared off in an orderly fashion like it would be when returning from each function one at a time. The hardware stack is a first on last off type of memory structure and needs to be loaded or unloaded in this way.

 

Perhaps you need to visualize a different approach. One that comes to mind is a global variable called “timeOutFlag”. This variable is monitored by each subroutine to see if it’s set by the timer. If true then the most current function returns to its calling function which in turn tests this flag. Again if it tests out as true (which it should) then it returns to its calling function whereby the "test and return" process repeats for as many levels deep until you get to where you need to be. Here you clear the flag and go about your business. This approach will cleanly clear off the hardware stack in an orderly way and eliminate the potential for a crash. You also need to be careful on how many nested function calls you make depending upon the processor type chosen. A PIC16 series only has 8 stack levels, PIC18 has 31 levels, PIC24 has even more due a “software” style stack approach. Choose wisely.

Share this post


Link to post
Share on other sites
The problem with a command like this on a tiny PIC is the ability to overflow or crash the hardware stack. Every time a function is called from within a function the return address of the calling function is placed on the hardware stack. Do this enough times and the stack overflows. Jumping way out from deeply nested subroutines will leave the stack a mess because none of the “stacked” addresses will be cleared off in an orderly fashion like it would be when returning from each function one at a time.

I have to disagree. This can be done cleanly, and other compilers do it. I have also used it on small 8-bit Atmel processors, which are just as tiny and also have the (cursed) Harvard architecture. It is independent of how deep the stack can be (i.e. if I have too deep a stack, it's a fail with or without longjmp).

 

The setjmp buffer holds enough information to restore the stack (or at least the items still active after the longjmp) to the point it was at when setjmp was called. This is obviously compiler dependent, but is quite doable. Usually it is just the address the stack was at, but if the stack uses dynamically allocated stack frames, the longjmp would have to de-allocate them. Since I don't know how this compiler handles the stack, I can't write the code myself (and doing so by experimentation would make me vulnerable to version changes).

 

It is a feature I think should be in any C compiler library.

 

The other approach you suggested is, of course, an alternative which I had considered. However, the setjmp/longjmp approach is much, much cleaner in the code. I don't have to worry about the timeout except where it is detected, and at the place I want to end up as a result of the timeout. Furthermore, I am porting Atmel code that already uses it. The flag approach means that every place I call a routine that could time out, I have to remember to put in the check - bunches of code, and easy to forget. Since I am parsing input data, I call a get character routine from all over the place, and each of those would have to check (there is an alternative trick, but its ugly - have get character return something really illegal, and only check where a retry would happen).

 

For me, not being able to do setjmp/longjmp is a deal breaker. I need the functionality - I'm not going to clutter up my code with bug-prone checks all over the place.

 

Hopefully the proprietors will answer this or point me to a reference that would allow me to code it myself.

 

Thanks for your response

Share this post


Link to post
Share on other sites

I think you are missing the point that the little PICs have a hardware stack so there is no way for the compiler to generate code to read or write the contents of the stack. There is no way to deal with this unless the compilier gives up the performance of the hardware stack and implements a software stack (no calls and no rets just jumps) which would generate larger code and execute slower. I have not seen how they do it but it could be similar to how we did things back in the 70s with RCA's 1802 microprocessor which had no call and no return instruction. Instead it had multiple program counters which a couple could be dedicated to point at tiny pieces of code to implement call and return managing its own software stack. Fun times back then.

 

Now I think our friends at SourceBoost Technologies have implemented software stacks so it may be possible to get this feature you request but in order to use it, you will have to give up performance.

Edited by trossin

Share this post


Link to post
Share on other sites
I think you are missing the point that the little PICs have a hardware stack so there is no way for the compiler to generate code to read or write the contents of the stack. There is no way to deal with this unless the compilier gives up the performance of the hardware stack and implements a software stack (no calls and no rets just jumps) which would generate larger code and execute slower. I have not seen how they do it but it could be similar to how we did things back in the 70s with RCA's 1802 microprocessor which had no call and no return instruction. Instead it had multiple program counters which a couple could be dedicated to point at tiny pieces of code to implement call and return managing its own software stack. Fun times back then.

 

Now I think our friends at SourceBoost Technologies have implemented software stacks so it may be possible to get this feature you request but in order to use it, you will have to give up performance.

I don't think it is necessary to read or write the stack - only the stack pointer.

 

You need to do two things;

1) Put the stack pointer back to where it was when the setjmp was called. I don't know if the PIC has the instructions to do this, but I would expect so. Note that MCC18 allows this.

2) Restore any non-stacked context (register held local variables, for example) that was present when the setjmp was called. The buffer provided to setjmp is where this information (stack pointer or level, other context).

3) Set the return from setjmp to the appropriate value.

 

BTW, without software stacks, how do you handle local variables? In a classic implementation, they are stored after/before the PC in the stack frame, or if optimized, in registers that are stored when a subsequent routine is called (or in higher levels of optimization, different registers are allocated as needed, which is the equivalent of a software stack).

 

It's been too (4) many decades since my last compiler construction course. :angry:

Share this post


Link to post
Share on other sites

The PIC18 devices allow access to the stack pointer (stkptr) for read and write. You can also read/write the contents of the stack using the top-of-stack locations. So setjmp is probably possible with this series of devices. PIC16 a little bit harder using software stack system.

 

MicroC impliment setjmp etc.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Yes the mikroElectronika C compiler for PIC's offers Setjmp and Longjmp commands.

From the help file...

This library contains functions and types definitions for bypassing the normal function call and return discipline. The type declared is jmp_buf which is an array type suitable for holding the information needed to restore a calling environment.

 

Type declaration is contained in sejmp16.h and setjmp18.h header files for PIC16 and PIC18 family mcus respectively. These headers can be found in the include folder of the compiler. The implementation of this library is different for PIC16 and PIC18 family mcus. For PIC16 family Setjmp and Longjmp are implemented as macros defined in setjmp16.h header file and for PIC18 family as functions defined in setjmp library file.

I've never used this command with mikroC so I don't know how robust it is or how bloated the code gets. Perhaps download the demo and see.

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...