Interrupts Disabled After First Context Switch

Kirspel, Kevin {Engineering - Osmetech CCD} kevin.kirspel at osmetech.com
Thu Jan 5 23:46:58 UTC 2006


I'm not sure this is a bug but I tracked down my problem to
_Watchdog_Insert().  Below is the relevant code snippet. Upon entering
watchdog insert the routine disables interrupts.  This sets my interrupt
level to 15 ( which blocks all interrupts ).  The returned interrupt
level from the _ISR_Disable() call shows that the previous interrupt
level to be zero.  This is correct.  It then disables the interrupts
again right after the restart label.  Since the interrupt level is
current 15 the returned interrupt level from the _ISR_Disable() is now
15.  When it finally enables interrupts at the end, the level is set to
15 masking all interrupts. To fix the problem I commented out the
_ISR_Disable() right below the restart label.  Is this a bug or is rtems
intended to work this way?

void _Watchdog_Insert(
  Chain_Control         *header,
  Watchdog_Control      *the_watchdog
)
{
  ISR_Level          level;
  Watchdog_Control  *after;
  unsigned32         insert_isr_nest_level;
  Watchdog_Interval  delta_interval;


  insert_isr_nest_level   = _ISR_Nest_level;

	_ISR_Disable( level );

  /*
   *  Check to see if the watchdog has just been inserted by a
   *  higher priority interrupt.  If so, abandon this insert.
   */

  if ( the_watchdog->state != WATCHDOG_INACTIVE ) {
    _ISR_Enable( level );
    return;
  }

  the_watchdog->state = WATCHDOG_BEING_INSERTED;

  _Watchdog_Sync_count++;

restart:
  delta_interval = the_watchdog->initial;

  _ISR_Disable( level ); //I commented this Disable to fix problem

for ( after = _Watchdog_First( header ) ;
        ;
        after = _Watchdog_Next( after ) ) {

     if ( delta_interval == 0 || !_Watchdog_Next( after ) )
       break;

     if ( delta_interval < after->delta_interval ) {
       after->delta_interval -= delta_interval;
       break;
     }

     delta_interval -= after->delta_interval;

     /*
      *  If you experience problems comment out the _ISR_Flash line.
      *  3.2.0 was the first release with this critical section
redesigned.
      *  Under certain circumstances, the PREVIOUS critical section
algorithm
      *  used around this flash point allowed interrupts to execute
      *  which violated the design assumptions.  The critical section
      *  mechanism used here WAS redesigned to address this.
      */

     _ISR_Flash( level );

     if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
       goto exit_insert;
     }

     if ( _Watchdog_Sync_level > insert_isr_nest_level ) {
       _Watchdog_Sync_level = insert_isr_nest_level;
       goto restart;
     }
  }

  _Watchdog_Activate( the_watchdog );

  the_watchdog->delta_interval = delta_interval;

  _Chain_Insert_unprotected( after->Node.previous, &the_watchdog->Node
);

  the_watchdog->start_time = _Watchdog_Ticks_since_boot;

exit_insert:
  _Watchdog_Sync_level = insert_isr_nest_level;
  _Watchdog_Sync_count--;
  _ISR_Enable( level );
}



Kevin Kirspel
Osmetech 
235 Hembree Park Drive
Roswell GA, 30076
770-510-4444 x4568


-----Original Message-----
From: Joel Sherrill <joel at OARcorp.com>
[mailto:joel.sherrill at OARcorp.com] 
Sent: Thursday, January 05, 2006 4:44 PM
To: Kirspel, Kevin {Engineering - Osmetech CCD}
Cc: rtems-users at rtems.com
Subject: Re: Interrupts Disabled After First Context Switch

Kirspel, Kevin {Engineering - Osmetech CCD} wrote:
> During _Thread_Dispatch() I was printing the state of the SR register.
I
> found that by the third context switch the interrupts were disabled
> going into _Thread_Dispatch().  So when _ISR_Disable() is called it
> returns the SR register with interrupts disabled.  Since the
> _ISR_Enable() routine just sets the SR register with the given level,
> interrupts are disabled even after the _ISR_Enable() call.  Is it
> possible to enter the _Thread_Dispatch() routine while interrupts are
> disable ( i.e. _ISR_Disable() was called prior to _Thread_Dispatch()
)?

Yes.  Interrupt level is maintained across context switches on a per 
thread basis.

I suspect that the third context switch you see is actually from 
__ISR_Dispatch and that the level is somehow not being maintained across

a preemption from ISR.

The sequence should be something like this for your test:

   (1) 1st context switch (initialization to 1st thread)
   (2) 1st thread to IDLE (wake after)
     ... clock tick isrs
   (3) IDLE to 1st thread FROM ISR!!

The FROM ISR on (3) is critical.  That puts you through the tail of 
__ISR_Handler and possibly needing some magic.  On other CPUs, that
code is tricky.  The SH code is straightforward but might be missing
something on the SH3/4.


> Kevin Kirspel
> Osmetech 
> 235 Hembree Park Drive
> Roswell GA, 30076
> 770-510-4444 x4568
> 
> 
> -----Original Message-----
> From: Joel Sherrill <joel at OARcorp.com>
> [mailto:joel.sherrill at OARcorp.com] 
> Sent: Thursday, January 05, 2006 1:04 PM
> To: Kirspel, Kevin {Engineering - Osmetech CCD}
> Cc: rtems-users at rtems.com
> Subject: Re: Interrupts Disabled After First Context Switch
> 
> Kirspel, Kevin {Engineering - Osmetech CCD} wrote:
> 
>>1) Renesas SH-3 but it's pretty much the same as the SH-4.
>>
>>2) the rtems_interrupt_disable() routine returns the value in the SR
>>register of the sh-3/4.  The SR register contains a BL bit that masks
>>interrupts.  It also contains an interrupt level mask that prevents
> 
> any
> 
>>interrupt lower than the level in the SR register from executing.  The
>>SH4 port sets the interrupt level to 15 to mask all interrupts (
>>rtems_interrupt_disable ).  Upon the printf statement below, the
>>interrupt level in the SR register is set to 15 masking all
> 
> interrupts.
> 
>>3)Yes.
>>
>>Case 1: using interrupt mask level 15 to disable interrupts. (
> 
> interrupt
> 
>>masks bits are bits 4-7 which is 0 before and F after).
>>INT BEFORE: 0x40001000
>>INT AFTER:  0x400011F1
>>
>>Case 2: using interrupt BL bit to disable interrupts. ( interrupt BL
> 
> bit
> 
>>is bit 28 which is 0 before and 1 after).
>>INT BEFORE: 0x40001000
>>INT AFTER:  0x50001101
> 
> 
> Is BL implicitly modified by an interrupt?  I don't know the SH well 
> enough to trace the code in my head but since you are doing a 
> delaying/blocking wake_after, there will be a context switch to IDLE, 
> then some clock tick ISRs, then a preempt of IDLE via the
__ISR_Handler
> routine in cpu_asm.c.  If the BL bit is not preserved across the (a) 
> context switch or (b) interrupt preemption, then it might be what you 
> are seeing.
> 
> I do not think it is (a) because that is a simple load/store of the
sr.
> 
> The __ISR_Handler code is always tricky to get right but I don't see
how
> 
> it could be messed up either.
> 
> To eliminate some possibilities and assuming this is a single task
test,
> 
> change the wake after(100) to wake after(0).  And do not print until 
> after all of the interrupt level changes.  I suspect it is the
interrupt
> 
> context switch somehow.  Just a guess.
> 
> 
> 
> 
>>Kevin Kirspel
>>Osmetech 
>>235 Hembree Park Drive
>>Roswell GA, 30076
>>770-510-4444 x4568
>>
>>
>>-----Original Message-----
>>From: Joel Sherrill <joel at OARcorp.com>
>>[mailto:joel.sherrill at OARcorp.com] 
>>Sent: Thursday, January 05, 2006 11:20 AM
>>To: Kirspel, Kevin {Engineering - Osmetech CCD}
>>Cc: rtems-users at rtems.com
>>Subject: Re: Interrupts Disabled After First Context Switch
>>
>>Kirspel, Kevin {Engineering - Osmetech CCD} wrote:
>>
>>
>>>Upon entering a task, the interrupts at the hardware level are
>>
>>enabled.
>>
>>
>>>After a call to rtems_task_wake_after() the interrupts are disabled
>>
>>and
>>
>>
>>>remain disabled while the task is running.  What part of the code
>>
>>should
>>
>>
>>>I look at to diagnose this issue? It seems that interrupts get
>>
>>disabled
>>
>>
>>>before the task switch is performed.
>>>
>>>The code sample below illustrates what I am doing. At the first
>>>printf(), the interrupts are enabled.  After the second printf(), the
>>>interrupts are disabled.
>>>
>>>rtems_task GUITask ( rtems_task_argument ignored )
>>>{
>>> //Local Varaibles
>>> rtems_interrupt_level level;
>>>
>>> /* Wait 100ms til everyone is up and running */
>>> rtems_interrupt_disable(level);
>>> rtems_interrupt_enable(level);
>>> printf( "\r\nINT BEFORE: %08lX", level );
>>> rtems_task_wake_after( 10 );
>>> rtems_interrupt_disable(level);
>>> rtems_interrupt_enable(level);
>>> printf ( "\r\nINT AFTER: %08lX", level );
>>>}
>>
>>
>>I have more questions than answers.
>>
>>rtems_interrupt_enable/disable are implemented as inline assembly 
>>language routines.  They are port specific which leads to
>>
>>(1) Which CPU are you using?
>>
>>There is no guarantee on the contents of level after calling enable
>>so
>>
>>(2) are you sure they are really off?
>>
>>(3) can you print out the status register or whatever it is on this
> 
> CPU 
> 
>>and we really check?
>>
>>
>>
>>>Kevin Kirspel
>>>Osmetech 
>>>235 Hembree Park Drive
>>>Roswell GA, 30076
>>>770-510-4444 x4568
>>>
>>>
>>
>>
>>
> 
> 


-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel at OARcorp.com                 On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
    Support Available             (256) 722-9985




More information about the users mailing list