Interrupts Disabled After First Context Switch

Joel Sherrill <joel@OARcorp.com> joel.sherrill at OARcorp.com
Fri Jan 6 13:21:12 UTC 2006


Ian Caddy wrote:
> Hi Kevin,
> 
> Which version of RTEMS are you running.  We have been looking through 
> watchdoginsert.c for another problem and in my version, which is from 
> 4.6.5 there is no _ISR_Disable( level ) after the restart.

Ditto for the code on the head of CVS.  Which version of RTEMS is this?
Or which CVS Id is watchdoginsert.c?


> That definitely looks wrong to me.  You can not have 2 disables without 
> an enable in between them.  In fact looking through that code, if the 
> restart is invoked, you will get more _ISR_Disable( level ) than just 
> the 2 as well.

Right.


> The cpukit/score/src/watchdoginsert.c in the 4.6.5 release is correct if 
> you want to have a look at that.
> 
> regards,
> 
> Ian Caddy
> 
> 
> Kirspel, Kevin {Engineering - Osmetech CCD} wrote:
> 
>> 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