EmbeddedRelated.com
Forums
Memfault Beyond the Launch

Compiler Support for Ensuring that a Statement is Atomic

Started by Datesfat Chicks January 15, 2010
On Fri, 15 Jan 2010 19:52:21 -0500, "Datesfat Chicks"
<datesfat.chicks@gmail.com> wrote:

> DI(); > sempahore++; > EI();
Nobody has mentioned the problem with using the DI/EI pair in code segments where interrupts can some times be enabled and other times be disabled. The code above will always enable interrupts, even if they were not enabled before the DI was executed.
"Mr. C" <fakeemail@hotmail.com> wrote in message 
news:3q4el5l74vhequ0u08tc6kl87tmt3n4ccp@4ax.com...
> On Fri, 15 Jan 2010 19:52:21 -0500, "Datesfat Chicks" > <datesfat.chicks@gmail.com> wrote: > >> DI(); >> sempahore++; >> EI(); > > Nobody has mentioned the problem with using the DI/EI pair in code > segments where interrupts can some times be enabled and other times be > disabled. The code above will always enable interrupts, even if they > were not enabled before the DI was executed.
This problem is normally very easy to address. It is normal to examine the interrupt mask and make the decision about whether to enable interrupts again based on whether they were enabled originally. It is of course easy to do in assembly language, but some compilers allow testing of the interrupt mask as well. It might go something like this: BOOLEAN im; im = imask(); //Built-in function supported by the compiler. DI(); semaphore++; if (!im) EI(); This is a fairly easy problem, and very common. Did I miss something? Datesfat
Datesfat Chicks wrote:
> This problem is normally very easy to address. It is normal to examine > the interrupt mask and make the decision about whether to enable > interrupts again based on whether they were enabled originally.
Easy, yes. But potentially quite wrong, too. You can't implement a semaphore using a sequence of operations (store current interrupt mask, then disable interrupt) that itself needs to be protected by one to avoid untimely outside interference. That's an exercise in pulling yourself out of the pond by yanking on your own hair.
> im = imask(); //Built-in function supported by the compiler. > > DI();
And you'll be SOL if the interrupt mask gets changed by an interrupt happening in between those two instructions.
Hans-Bernhard Br&#4294967295;ker wrote:
> Datesfat Chicks wrote: >> This problem is normally very easy to address. It is normal to >> examine the interrupt mask and make the decision about whether to >> enable interrupts again based on whether they were enabled originally. > > Easy, yes. But potentially quite wrong, too. You can't implement a > semaphore using a sequence of operations (store current interrupt mask, > then disable interrupt) that itself needs to be protected by one to > avoid untimely outside interference. That's an exercise in pulling > yourself out of the pond by yanking on your own hair. > >> im = imask(); //Built-in function supported by the compiler. >> >> DI(); > > And you'll be SOL if the interrupt mask gets changed by an interrupt > happening in between those two instructions.
It's an unusual system that will change the interrupt mask during an interrupt, and not restore it on exit - and the situation can only be an issue on processors with multiple interrupt levels and no global interrupt flag (such as the m68k). There might be occasions when this sequence is dangerous, but it is normally considered safe.
"Hans-Bernhard Br&#4294967295;ker" <HBBroeker@t-online.de> wrote in message 
news:hj841g$ghb$02$1@news.t-online.com...
> Datesfat Chicks wrote: >> This problem is normally very easy to address. It is normal to examine >> the interrupt mask and make the decision about whether to enable >> interrupts again based on whether they were enabled originally. > > Easy, yes. But potentially quite wrong, too. You can't implement a > semaphore using a sequence of operations (store current interrupt mask, > then disable interrupt) that itself needs to be protected by one to avoid > untimely outside interference. That's an exercise in pulling yourself out > of the pond by yanking on your own hair. > >> im = imask(); //Built-in function supported by the compiler. >> >> DI(); > > And you'll be SOL if the interrupt mask gets changed by an interrupt > happening in between those two instructions.
In most software architectures, the scenario you proposed can't occur. The interrupt mask is typically a part of the PSW or CC register (same animal, depends on who is doing the naming), and it is normally saved and restored by the hardware when an interrupt occurs and when the ISR exits. In most small microcontrollers, the interrupt mask is in the same register as the carry flag, zero flag, overflow flag, etc., so it has to be restored on exit from an ISR. I suppose an enterprising ISR could reach into the stack and modify the value that will be restored when the interrupt exits, but this is not done by sane humans. Generally, can't happen. Datesfat
On Wed, 20 Jan 2010 09:39:39 -0500, Mr.C wrote:

>> DI(); >> sempahore++; >> EI(); > > Nobody has mentioned the problem with using the DI/EI pair in code > segments where interrupts can some times be enabled and other times be > disabled. The code above will always enable interrupts, even if they > were not enabled before the DI was executed.
It's not a problem if you only use DI/EI around very small sections of code so that you know that DI/EI will never nest. For larger sections of code, you should probably be using mutexes, semaphores, RCU, or whatever (which may need to use DI/EI in their implementation).
On Jan 20, 11:46=A0pm, "Datesfat Chicks" <datesfat.chi...@gmail.com>
wrote:
> > On Fri, 15 Jan 2010 19:52:21 -0500, "Datesfat Chicks" > > <datesfat.chi...@gmail.com> wrote: > >> =A0 DI(); > >> =A0 sempahore++; > >> =A0 EI(); > > The code above will always enable interrupts, even if they > > were not enabled before the DI was executed.
I almost posted something like the following, but was busy stamping out flames in another ng. :-)
> This problem is normally very easy to address. =A0It is normal to examine=
the
> interrupt mask and make the decision about whether to enable interrupts > again based on whether they were enabled originally. > > im =3D imask(); //Built-in function supported by the compiler. > DI(); > semaphore++; > if (!im) > =A0 =A0EI();
Nothing to add, except a True Anecdote(tm). Development of a peculiar system(*) was getting behind schedule due to a very intermittent bug. I came across the responsible programmer sitting next to a logic analyzer reading a comic book or something. "Can't do anything until the analyzer triggers again" was his answer. "Problem occurs only once every several hours." I showed him how to research by writing (the equivalent of) assert(imask() =3D=3D ENABLED); before the DI(); and thus make the system "fail" several times a second instead of once every several hours. I'm sure he then figured out the fix himself. (* -- IIRC, it was a processor emulating a disk controller, connected to a disk controller emulating a processor, or some such. :-) James Dow Allen

Memfault Beyond the Launch