From: Stefan Reuther on
D Yuniskis wrote:
> Stefan Reuther wrote:
>> D Yuniskis wrote:
>>> E.g., if the jiffy comes along (perhaps the most notable
>>> active element that *would* be interrupt spawned and asynchronously
>>> compete for access to those strctures), it has to notice that a
>>> critical region has been entered (by whatever it has interrupted!)
>>> and then "schedule" a defered activation. [...]
>>
>> The problem here is how you "schedule" the deferred activity. You can
>> make an array of sig_atomic_t variables, one for each possible activity,
>> the interrupt sets them, the kernel exit checks and clears them. But
>> this obviously does not scale.
>
> Append a pointer to the ASR that needs to be deffered to
> the end of a list of "deffered procedure calls". When the
> ISR returns, the OS schedules this "list" of DPC's (in
> sequential order).

Exactly this "append a pointer" thing is where an atomic operation can
come in very handy. You shouldn't append to the list while it's being
processed, nor should you interrupt another instance in another
interrupt (if you have nested interrupts).

All this is totally simple when you can use CLI/STI:
void atomic_swap(node** a, node** b, node* c) {
cli(); *a = *b; *b = c; sti();
}

// prepend new node to a list (easier than appending...)
node* list;
node* newNode;
atomic_swap(&newNode->next, &list, newNode);

// get list (for processing) and make it empty
node* oldList;
atomic_swap(&oldList, &list, 0);
(some strategically-placed 'volatile' can be appropriate.)

>> When you make something generic, you'll start needing linked lists of
>> stuff where you put the deferred actions in. So you now need some kind
>> of atomic link-creation or swap routine. Okay, this can also be
>> implemented without disabling interrupts, by having the interrupt
>> routine detect whether it interrupted the atomic routine. It's possible,
>> but it's easy to get wrong.
>
> This last point is why folks seem to resort to the more heavy-handed
> approach of unilaterally disabling interrupts for *everything*
> that is "hard" or "easy to get wrong".

Actually I see much more often that people do not use proper locking and
ponder about the occasional crashes that happen once in a fortnight :-)

By "easy to get wrong" I mean, for example, that you have to tell all
your interrupt routines about your atomic_swap routine, so that they can
see that they've interrupted it and can complete or restart it. This is
nasty asm trickery. It enlarges all your interrupts by a dozen
instructions (at least some compares and jumps). And all that just
for a sticker "never disables interrupts" in the glossy brochures?
Sorry, I'd rather take the additional three-cycle interrupt latency for
running atomic_link under CLI.

>> It's much simpler to just wrap the three statements into a CLI/STI.
>> In particular when your processor has multi-cycle instructions which
>> implicitly block interrupts for a dozen cycles while they execute - so
>> why should these be permitted and a three-cycle CLI/STI should not?
>
> There is nothing wrong with disabling interrupts! But, like
> everything else, you have to understand *why* you are doing
> it and when it is *appropriate* to do so.

I'm quite optimistic that I understand :-)


Stefan

From: D Yuniskis on
Stefan Reuther wrote:
> D Yuniskis wrote:
>> This last point is why folks seem to resort to the more heavy-handed
>> approach of unilaterally disabling interrupts for *everything*
>> that is "hard" or "easy to get wrong".
>
> Actually I see much more often that people do not use proper locking and
> ponder about the occasional crashes that happen once in a fortnight :-)
>
> By "easy to get wrong" I mean, for example, that you have to tell all
> your interrupt routines about your atomic_swap routine, so that they can
> see that they've interrupted it and can complete or restart it. This is
> nasty asm trickery. It enlarges all your interrupts by a dozen
> instructions (at least some compares and jumps). And all that just
> for a sticker "never disables interrupts" in the glossy brochures?
> Sorry, I'd rather take the additional three-cycle interrupt latency for
> running atomic_link under CLI.

You can wrap all of your interrupts with a common dispatch routine.
But, it boils down to the same thing: there is more to get done.

The one thing in your favor is that these ISR's are, in theory,
relegated to the operating system's responsibility. It is
a fair bit harder when you let "user code" migrate into this
realm.

[which is another aspect of this: folks who do things *in* ISRs
that don't need to be handled there -- resulting in bloated ISRs
which impacts the responsiveness of the whole system... which
causes folks to tend to put more in *other* ISRs... which...]

>>> It's much simpler to just wrap the three statements into a CLI/STI.
>>> In particular when your processor has multi-cycle instructions which
>>> implicitly block interrupts for a dozen cycles while they execute - so
>>> why should these be permitted and a three-cycle CLI/STI should not?
>> There is nothing wrong with disabling interrupts! But, like
>> everything else, you have to understand *why* you are doing
>> it and when it is *appropriate* to do so.
>
> I'm quite optimistic that I understand :-)
From: ChrisQ on
Stefan Reuther wrote:

> By "easy to get wrong" I mean, for example, that you have to tell all
> your interrupt routines about your atomic_swap routine, so that they can
> see that they've interrupted it and can complete or restart it. This is
> nasty asm trickery. It enlarges all your interrupts by a dozen
> instructions (at least some compares and jumps). And all that just
> for a sticker "never disables interrupts" in the glossy brochures?
> Sorry, I'd rather take the additional three-cycle interrupt latency for
> running atomic_link under CLI.

A related problem is where a single shared variable at driver level that
needs to be accessed from different functions, all of which disable the
interrupt within the critical section. Disabling interrupts is fine, but
it is necessary to know at the time of reenabling any instance, what the
current interrupt state was for the device, prior to the call. The
solution was to write a couple of functions to stack the current device
interrupt state before disabling, then pop on exit, rather than just a
hard disable / reenable.

I suppose this will turn out to be a standard technique, but new to me
at least...

Regards,

Chris
From: FreeRTOS info on
ChrisQ wrote:

> A related problem is where a single shared variable at driver level that
> needs to be accessed from different functions, all of which disable the
> interrupt within the critical section. Disabling interrupts is fine, but
> it is necessary to know at the time of reenabling any instance, what the
> current interrupt state was for the device, prior to the call. The
> solution was to write a couple of functions to stack the current device
> interrupt state before disabling, then pop on exit, rather than just a
> hard disable / reenable.
>
> I suppose this will turn out to be a standard technique, but new to me
> at least...
>
> Regards,
>
> Chris

....and also a technique that won't work on most compiler/architecture
combinations as modifying the stack in this way will prevent the code in
the critical region from executing correctly (any stack pointer relative
addressing just 'aint going to work).

--

Regards,
Richard.

+ http://www.FreeRTOS.org
Designed for Microcontrollers. More than 7000 downloads per month.

+ http://www.SafeRTOS.com
Certified by T�V as meeting the requirements for safety related systems.

From: ChrisQ on
FreeRTOS info wrote:
> ChrisQ wrote:
>
>> A related problem is where a single shared variable at driver level
>> that needs to be accessed from different functions, all of which
>> disable the interrupt within the critical section. Disabling
>> interrupts is fine, but it is necessary to know at the time of
>> reenabling any instance, what the current interrupt state was for the
>> device, prior to the call. The solution was to write a couple of
>> functions to stack the current device interrupt state before
>> disabling, then pop on exit, rather than just a hard disable / reenable.
>>
>> I suppose this will turn out to be a standard technique, but new to me
>> at least...
>>
>> Regards,
>>
>> Chris
>
> ...and also a technique that won't work on most compiler/architecture
> combinations as modifying the stack in this way will prevent the code in
> the critical region from executing correctly (any stack pointer relative
> addressing just 'aint going to work).
>

No, not using the system stack. By writing functions, I mean functions
using an short byte array to simulate a stack...

Regards,

Chris