Force consecutive operation when using asm volatile macro

Jari Kuusisto jari.h.kuusisto@gmail.com
Tue Oct 7 04:43:00 GMT 2008


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@gmail.com> 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
>   



More information about the Gcc-help mailing list