Hello Ian,
Here's an example function from uC/OS where the critical section asm
macro code seems not to work as expected (but with critical section
function it works).
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate
storage for CPU status register */
OS_CPU_SR cpu_sr;
cpu_sr = 0; /* Prevent
compiler warning */
#endif
if (OSIntNesting > 0) { /* See if called
from ISR ... */
*err = OS_ERR_PEND_ISR; /* ... can't PEND
from an ISR */
return;
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate
'pevent' */
*err = OS_ERR_PEVENT_NULL;
return;
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event
block type */
*err = OS_ERR_EVENT_TYPE;
return;
}
OS_ENTER_CRITICAL();
if (pevent->OSEventCnt > 0) { /* If sem. is
positive, resource available ... */
pevent->OSEventCnt--; /* ... decrement
semaphore only if positive. */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
/* Otherwise, must
wait until event occurs */
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not
available, pend on semaphore */
OSTCBCur->OSTCBPendTO = FALSE;
OSTCBCur->OSTCBDly = timeout; /* Store pend
timeout in TCB */
OS_EventTaskWait(pevent); /* Suspend task
until event or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next
highest priority task ready */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBPendTO == TRUE) { /* See if we
timedout */
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* Indicate that
didn't get event within TO */
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
INT8U OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate
storage for CPU status register */
OS_CPU_SR cpu_sr;
cpu_sr = 0; /* Prevent
compiler warning */
#endif
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate
'pevent' */
return (OS_ERR_PEVENT_NULL);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate
event block type */
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* See if
any task waiting for semaphore*/
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready
HPT waiting on event */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find
HPT ready to run */
return (OS_NO_ERR);
}
if (pevent->OSEventCnt < 65535u) { /* Make sure
semaphore will not overflow */
pevent->OSEventCnt++; /* Increment
semaphore count to register event */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
OS_EXIT_CRITICAL(); /* Semaphore value
has reached its maximum */
return (OS_SEM_OVF);
}
With this asm macro implementation the semaphore handling is not working
with new GCC version:
#define OS_ENTER_CRITICAL() asm volatile("mfmsr
%0":"=r"(cpu_sr));asm volatile("mtspr 81,r0")
#define OS_EXIT_CRITICAL() asm volatile("mtmsr %0"::"r"(cpu_sr))
But when using function-type implementation for critical section
enter/exit, the semaphore handling works as expected:
h-file:
void OSEnterCriticalFunc(OS_CPU_SR *cpu_sr);
void OSExitCriticalFunc(OS_CPU_SR *cpu_sr);
#define OS_ENTER_CRITICAL() ( OSEnterCriticalFunc( &cpu_sr ) )
#define OS_EXIT_CRITICAL() ( OSExitCriticalFunc ( &cpu_sr ) )
c-file:
void OSEnterCriticalFunc(OS_CPU_SR *cpu_sr)
{
asm volatile("mfmsr %0":"=r"(*cpu_sr));
asm volatile("mtspr 81,r0");
}
void OSExitCriticalFunc(OS_CPU_SR *cpu_sr)
{
asm volatile("mtmsr %0"::"r"(*cpu_sr));
}
BR. Jari Kuusisto
Ian Lance Taylor wrote:
Jari Kuusisto <jari.h.kuusisto@xxxxxxxxx> writes:
After upgrading from gcc 2.95.3 to 4.3.2 the critical section handling
in the code stopped working. It seems that some of the code that
should be in critical section seems to be relocated outside the
critical section. I do know that asm volatile does not guarantee
consecutive execution of the code. I also know that using singe asm
would fix this problem, but in my case it is not possible.
I've managed to to get around this problem by replacing the critical
section macros with assembler functions as the blr instruction forces
the correct consecutive operation when entering and exiting critical
section. However, this function call type implementation seems to
significantly slow down runtime operation of the software. The result
is that the performance improvement gained with new gcc optimizations
is waisted due to this function call type implementation.
If I enable all other optimizations from -O2 but not the
-freorder-blocks the code is working with the old asm volatile macros,
but this is not an option.
Is there any other way to force the consecutive operation of asm
volatile macros?
You're going to have to show us the code.
Ian