EmbeddedRelated.com
Forums

Question About Sequence Points and Interrupt/Thread Safety

Started by Jujitsu Lizard February 24, 2009
"Jujitsu Lizard" <jujitsu.lizard@gmail.com> writes:
> Addendum to my previous post ... > > I did a little more dinking with the compiler, and I'm convinced now > that it can't be fully trusted. > > Here is the code (just dinking around): > > UINT8 in_nelem22; > > void MF_decu8arr_nbz(UINT8 *in_arg, UINT16 in_nelem) > { > while (in_nelem) > { > DI(); > in_nelem22 += 3; > EI(); > in_nelem22 += 5; > in_nelem22 += 7; > in_nelem++; > } > } > > and here is what it got me: >
[assembly code snipped]
> > Note that the EI() caused it to split up the additions into +3 and > +12, but that IT DID NOT WRITE THE VARIABLE BACK TO MEMORY UNTIL LATER > (it kept the contents in the accumulator). > > This is a danger sign. > > It means in a complex code sequence with DI() and EI(), it might get me!
What happens if you declare in_nelem22 as volatile? -- Keith Thompson (The_Other_Keith) kst@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"
Kaz Kylheku <kkylheku@gmail.com> writes:
[...]
> I.e. suppose we want this: > > DI(); > if (condition(x)) > x++; > EI(); > > If x is volatile int, the semantics is that there are two accesses > to x and one store.
[...] Quibble 1: a store is an access. C99 3.1 defines "access" as "<execution-time action> to read or modify the value of an object", with a note: Where only one of these two actions is meant, ``read'' or ``modify'' is used. Quibble 2: C99 6.7.3p6 says: What constitutes an access to an object that has volatile-qualified type is implementation-defined. This doesn't contradict your advice, though; judicious use of the volatile qualifier just might be what the OP needs to get his program working with his particular compiler. (Kaz, would you mind making your lines a trifle shorter? The often go past 80 columns when quoted with "> ". I usually format paragraphs to 70 or 72 columns.) -- Keith Thompson (The_Other_Keith) kst@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"

Jujitsu Lizard wrote:

> I've included a function below and the generated STM8 > assembly-language. As it ends up (based on the assembly-language), the > function is interrupt safe as intended. > > My question is, let's assume I have this: > > DI(); > if (x) > x--; > EI(); > > where DI and EI just expand to the compiler's asm( ) feature to insert > the right machine instruction to disable and enable interrupts, ...
You can not make any assumptions. There is no guarantee of the correct behavior of this piece of code. If you need to ensure the atomicity, use the explicit critical section functions provided by OS or develop the assembly functions of your own. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
"Keith Thompson" <kst-u@mib.org> wrote in message 
news:lnab8bgtym.fsf@nuthaus.mib.org...
> "Jujitsu Lizard" <jujitsu.lizard@gmail.com> writes: >> Addendum to my previous post ... >> >> I did a little more dinking with the compiler, and I'm convinced now >> that it can't be fully trusted. >> >> Here is the code (just dinking around): >> >> UINT8 in_nelem22; >> >> void MF_decu8arr_nbz(UINT8 *in_arg, UINT16 in_nelem) >> { >> while (in_nelem) >> { >> DI(); >> in_nelem22 += 3; >> EI(); >> in_nelem22 += 5; >> in_nelem22 += 7; >> in_nelem++; >> } >> } >> >> and here is what it got me: >> > [assembly code snipped] >> >> Note that the EI() caused it to split up the additions into +3 and >> +12, but that IT DID NOT WRITE THE VARIABLE BACK TO MEMORY UNTIL LATER >> (it kept the contents in the accumulator). >> >> This is a danger sign. >> >> It means in a complex code sequence with DI() and EI(), it might get me! > > What happens if you declare in_nelem22 as volatile?
Assembly language below. Looks a bit different! BTW, the ld instructions are in the form ld destination, source which might help with clarity. 701 ; 291 void MF_decu8arr_nbz(UINT8 *in_arg, UINT16 in_nelem) 701 ; 292 { 702 switch .text 703 00b4 f_MF_decu8arr_nbz: 705 00b4 89 pushw x 706 00000000 OFST: set 0 709 00b5 201d jra L552 710 00b7 L352: 711 ; 295 DI(); 714 00b7 9b sim 716 ; 296 in_nelem22 += 3; 718 00b8 c60000 ld a,_in_nelem22 719 00bb ab03 add a,#3 720 00bd c70000 ld _in_nelem22,a 721 ; 297 EI(); 724 00c0 9a rim 726 ; 298 in_nelem22 += 5; 728 00c1 c60000 ld a,_in_nelem22 729 00c4 ab05 add a,#5 730 00c6 c70000 ld _in_nelem22,a 731 ; 299 in_nelem22 += 7; 733 00c9 c60000 ld a,_in_nelem22 734 00cc ab07 add a,#7 735 00ce c70000 ld _in_nelem22,a 736 ; 300 in_nelem++; 738 00d1 5c incw x 739 00d2 1f06 ldw (OFST+6,sp),x 740 00d4 L552: 741 ; 293 while (in_nelem) 743 00d4 1e06 ldw x,(OFST+6,sp) 744 00d6 26df jrne L352 745 ; 302 } 748 00d8 85 popw x 749 00d9 87 retf
On Tue, 24 Feb 2009 20:23:56 -0500, "Jujitsu Lizard"
<jujitsu.lizard@gmail.com> wrote in comp.arch.embedded:

> Addendum to my previous post ... > > I did a little more dinking with the compiler, and I'm convinced now that it > can't be fully trusted.
As others have pointed out, this is beyond the C standard and off-topic in comp.lang.c, but definitely topical in comp.arch.embedded.
> Here is the code (just dinking around): > > UINT8 in_nelem22;
You have no reason whatsoever to expect much of anything without a real function call, unless you define the object as volatile. A macro that expands to inline assembly language that does not include a subroutine call does not show the compiler that some external code is going to access the object.
> void MF_decu8arr_nbz(UINT8 *in_arg, UINT16 in_nelem) > { > while (in_nelem) > { > DI(); > in_nelem22 += 3; > EI(); > in_nelem22 += 5; > in_nelem22 += 7; > in_nelem++; > } > }
The other problem is that it can be even worse than you think even if you do define it as volatile. First, there's the fact that the definition of volatile is just plain broken in the C language and standard. It is no particular consolation that it is even more broken in C++. The real crime is the fact there's a paper showing a number of compilers that actually have errors in their implementation of volatile that can be detected by a strictly conforming program. See: http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf Hopefully, compilers for real embedded systems processor architectures do better than this. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
On Tue, 24 Feb 2009 19:17:52 -0500, Jujitsu Lizard wrote:

> "Richard Heathfield" <rjh@see.sig.invalid> wrote in message > news:-q6dnZpxK-fwETnUnZ2dnUVZ8j-WnZ2d@bt.com... >>> >>> Is there any reason that the compiler cannot delay writing "x" back so >>> that I get effectively this: >>> >>> DI(); >>> cpu_register = x; >>> if(cpu_register) >>> cpu_register--; >>> EI(); >>> x = cpu_register; >>> >>> ??? >> >> 3.6: "A full expression is an expression that is not part of another >> expression. Each of the following is a full expression: an >> initializer; the expression in an expression statement; the controlling >> expression of a selection statement ( if or switch ); the controlling >> expression of a while or do statement; each of the three expressions of >> a for statement; the expression in a return statement. The end of a >> full expression is a sequence point." >> >> Having said that, the "as if" rule applies. If the implementation >> "wants" to delay the assignment to x, it is permitted to do so >> /provided/ that a strictly conforming program can't tell the >> difference. >> >> <snip> > > "tell the difference" is a bit of an ambiguous phrase. > > I think you are saying that in this case the compiler is not free to > delay the write of "x" because that would be a logical error -- a > conforming ISR could in fact "tell the difference", and it would result > in logical errors in the program. > > Am I understanding your response correctly? > > Thanks, The Lizard
But there is no such thing as a "conforming ISR" in C, because ISR's are, strictly speaking, outside of the C language's paradigm. As are, for that matter, asm statements. So you have one of three choices: 1: Write all your really critical stuff in assembly. 2: Write your critical stuff in C, check the compiler output, and be prepared for bugs if you get a different compiler -- even a new version of the same old. 3: (I hate these folks) Write your critical stuff in whatever, and move on to a new job before your sins catch up to you. -- http://www.wescottdesign.com
"Kaz Kylheku" <kkylheku@gmail.com> wrote in message 
news:20090304003253.906@gmail.com...
> On 2009-02-25, Jujitsu Lizard <jujitsu.lizard@gmail.com> wrote: >> Addendum to my previous post ... >> >> I did a little more dinking with the compiler, and I'm convinced now that >> it >> can't be fully trusted. > > What if you make DI and EI into external functions, in a separate > compilation > unit? That could just be the silver bullet for this compiler; no need to > snapshot the assembly language. >
The link-time optimizer, assuming the compiler in question has one, can still ruin everything.
"Tim Wescott" <tim@seemywebsite.com> wrote in message 
news:aMudnZUqkt-1KjnUnZ2dnUVZ_vqdnZ2d@web-ster.com...
> > So you have one of three choices: > > 1: Write all your really critical stuff in assembly. > 2: Write your critical stuff in C, check the compiler output, and > be prepared for bugs if you get a different compiler -- even > a new version of the same old. > 3: (I hate these folks) Write your critical stuff in whatever, > and move on to a new job before your sins catch up to you.
#3 shows that you are not under 30 years old. You understand the dark side of the force.
"Jack Klein" <jackklein@spamcop.net> wrote in message 
news:gqc9q4hjd9cguqvvdcd2efbd6ti9qehmgq@4ax.com...
> > The real crime is the fact there's a paper showing a number of > compilers that actually have errors in their implementation of > volatile that can be detected by a strictly conforming program. See: > > http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf > > Hopefully, compilers for real embedded systems processor architectures > do better than this.
That is the single most depressing paper I've read recently. But thanks for the link : ) The Lizard
"Jujitsu Lizard" <jujitsu.lizard@gmail.com> wrote in message 
news:u4-dnQJnm70QdznUnZ2dnUVZ_uudnZ2d@giganews.com...
> "Jack Klein" <jackklein@spamcop.net> wrote in message > news:gqc9q4hjd9cguqvvdcd2efbd6ti9qehmgq@4ax.com... >> >> The real crime is the fact there's a paper showing a number of >> compilers that actually have errors in their implementation of >> volatile that can be detected by a strictly conforming program. See: >> >> http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf >> >> Hopefully, compilers for real embedded systems processor architectures >> do better than this. > > That is the single most depressing paper I've read recently. > > But thanks for the link : ) > > The Lizard
Jack, In fact, the paper you linked to was SO depressing, I just had to try to match you ... try this one on for size: http://sunnyday.mit.edu/papers/therac.pdf What always amazed me about the Therac affair is the initial denial of the existence of a problem. The Lizard