Re: Force consecutive operation when using asm volatile macro

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux