Prev: ALP for Real Time Clock using timer unit of HC12
Next: How to create a code in C++ for LM3S811 in IAR Embedded Workbench
From: Stefan Reuther on 29 Oct 2009 14:52 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 29 Oct 2009 17:37 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 29 Oct 2009 17:39 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 29 Oct 2009 18:00 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 29 Oct 2009 18:16
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 |