Why vPortEnterCritical() is not safe called from an interrupt context?

void vPortEnterCritical( void )

	/* This is not the interrupt safe version of the enter critical function so
	assert() if it is being called from an interrupt context.  Only API
	functions that end in "FromISR" can be used in an interrupt.  Only assert if
	the critical nesting count is 1 to protect against recursive calls if the
	assert function also uses a critical section. */
	if( uxCriticalNesting == 1 )
        configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );

I’m trying to understand why this function is not safe called from an interrupt context. The only reason i gussed is that this function is using a global variable, but it has close the interupt before oprating. is it because not all interrupts are masked?

Hi dan-hou,

Depending on the port, it may or may not be safe to call this from and ISR context. If you wish to be portable, then use the xxxFromISR() version; in some ports, it resolves to something different than the “unsafe” version.

Do you mean whether safe or not it depends on the implementation portDISABLE_INTERRUPTS()? I’m using port files in GCC\ARM_CM7\r0p1. Is that safe?


It probably is, I don’t have access to the code right now. You should be able to figure that one out yourself, though. After all, it’s your code and your responsibility. I wouldn’t ever rely on a forum member’s statement. The ultimate test is whether your code proves in the field.

The issue is that vPortExitCritical, which needs to be used with it will reenable ALL the interrupts, but if you are inside an ISR, you generally only want to reenable those higher than you.

The Task Level routines save a few cycles by knowing that no interrupt levels are disabled.

The FromISR version of this function (at least on ports which have multiple ISR levels) will save the current Interrupt level so the Critical Exit can go back to that same level.

en~~ Even if I enable ISR those have lower priority, they can’t interrupt current ISR. So, why not enable all ISR directly?

It depends on the processor. Some do keep track of the current level elsewhere so that isn’t fully needed, but for some processors this manipulates the one true definition of interrupt level. The ‘rules’ in FreeRTOS are sometimes written in a more general sense, and might not be needed for a given machine.

The port file I use now have 2 APIs (one have _FROM_ISR suffix) to disable ISRs, the only difference is that one will save the current BASEPRI while another doesn’t. I think they are same because the BASEPRI only has one possible value where I configured in config file. Have you ever met situations in which the xxxFromISR() version of disable ISRs API has totally different things to resolve?

Again, you must answer this for yourself. You can look at all the ports FreeRTOS provides, and I’m sure you’ll find a few in which there are differences between the two implementations that prohibit collapsing.

If you believe that the port you are using does not need to distinguish the two versions AND you benefit from NOT using the functions as documented, you are free to use them against the coding standards. Just be sure to document this so well that whoever will at some point want to port your code to another processor architecture will be aware of your non standard usage.

Do you mean that some processor will process the ISR handler later, when the processor has exit ISR context? That sound reasonable, but why they don’t process the ISR handler just in the ISR context?

Why bother with all the implementation details out of your control and responsibility ?
You really should follow the official (and tested !) API specification and you’ll be fine.
Be sure there is a reason why the spec is as it is.
Also if one day something isn’t working as expected and you can refer the official spec it’s possible/likely to get supported which is impossible/unlikely if you don’t.

A couple of reasons. First, and as already mentioned, some ports allow synchronous interrupts from inside a critical section that blocks asynchronous interrupts. Those ports necessarily save the critical nesting depth as part of the task context - so using that variable from an interrupt will cause corruption (at some point, probably not straight away). Second taskENTER_CRITICAL() is called from inside functions that are non-interrupt safe, so that assert is designed to assist when the non “FromISR” version of a function is used (so taskENTER_CRITICAL() is called from a function that is itself called from the application, rather than directly by the application).