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