This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Longjmp out of ISR



Hi all,

Yes, I'm longjumping out of an ISR. What I'm trying to do is to implement a simple method to abort an infinite loop as an interrupt occurs.

As a problem, I see that GIE doesn't get restored to 1 after the longjmp (because the ISR couldn't restore the context with RETI, and GIE is reset in the ISR entrance). So I'm just setting it after the paths following the setjmp() call.

Do you know any cleaner workaround, or else a better solution?

  • Long-jumping out of an ISR is not supported by C!

    The reason for this is that the compiler ensures that everything is in order at all points where a longjmp can occur, which is ONLY at function calls. An ISR can occur at any time, in which case the generated code expect execution to continue where it left of.

    Also, as you noticed, a longjump doesn't exit the interrupt.

    A much better method is to let your ISR modify a state somewhere (like a global variable) and modify your infinite loop to that it checks the state.

    Alternatively, if you try to break an involuntarily infinite loop, simply reset the device. You can use a watchdog for this.

        -- Anders Lindgren, IAR Systems, Author of the IAR compiler for MSP430

  • Thanks Anders for the answer!


    I've been studying my solution, and I see it is the only one that really fulfill my needs. In more details, I'm executing a long routine, and I want it to be cancelled when the "CANCEL" button is pressed, like a preemptive task in an RT context, but mine context is much simpler.

    Inserting checks to variables would bloat my code. Besides, as every loop of my routine takes a long time to execute, and library calls are made, it would make my device too much unresponsible to the "CANCEL" button press.

    Actually, I see that in some cases long-jumping out of ISR can cause some state changes to be unrecovered. But in my case I can track and recover all the changes, and go back to a safe point. And I understand the philosofy of C as "you can do everything, but be sure you really know what you're doing". So I'm not convinced (yet) that C can't support this feature.


    What really bothered me is that the implementation of the Texas compiler of setjmp() doesn't save/restore the SR register. I coud get it with __get_SR_register_on_exit() inside of the ISR, save it on a structure, and them restore it after the jump to setjmp().

  • It could work, but you really have to find a really safe point.

    For example, the C standard specifies that local variables declared "volatile" in the function of the "setjmp" should keep their value after the longjump. In your case, this can not be guaranteed. Concretely, this can occur if the interrupt occurs between an ADD and an ADDC of a 32 bit value.

    Anyway, if you are prepared to do this, I would recommend that instead of saving the SR in the ISR, you could make a copy in the routine that calls "setjmp" and save it next to the setjmp buffer. The first thing you could do after the longjmp is to restore the (relevant parts of the) SR.

        -- Anders Lindgren, IAR Systems

  • Thanks Anders for the great answer and the details!


    This solution is really risky and should be used with caution.

    I'm very grateful for your expertise and help.

  • longjmp is possibly the worst idea that ever made it into a programming language standard. Likely it was invented by a former Basic coder who had problems to design a program concept with a procedural language. (having started with assembly and basic myself, I know what I’m talking about).

    If you write an infinite loop, then it is an infinite loop. If you don’t want it to be infinite, then implement a break condition check. And the ISR can set this break condition then.

    volatile bool run;
    
    main(){
      run=true;
      while(run){ … };
      …
    }
    
    Void isr(void){
      run=false;
    }

    A preemptive task switching is something completely different. It does not exit a funciton by jumpin gto its end  form the ISR. It 'just' freezes the current stack and switches to a different stack, to later come back and 'return' to the same point the thread was interrupted.

    To do a longjmp (well, something like this) from an ISR, you would have to
    1) know that the iSR was called while main was running inside the loop
    2) pull the saved status register and return address from the stack
    3) store the new 'return' address and the status register on the stack (no need to use longjmp at all)
    4) know what else the compiler might have done to the stack inside the loop at the moment of interruption, to undo it.
    While 1-3 are certainly doable, part 4 is virtually impossible. So this method will only work when doing all the coding in assembly. Else only the compiler knows what you would have to do - and it won't tell you.

**Attention** This is a public forum