EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Software Reuse In Embedded code

Started by steve June 15, 2011
On Thu, 23 Jun 2011 23:05:14 +0200, David Brown
<david.brown@removethis.hesbynett.no> wrote:

>Copyrights are too long - you can blame the USA and their Mickey Mouse >laws here.
Actually you can blame Mickey Mouse. It was a dispute over Walt Disney's copyrights that led to the current "life + 99 years" law which automatically transfers the holder's rights to his/her estate after death. George
On 24/06/2011 02:52, Don Y wrote:
>> One quick fr'instance: there's some (complex) code to manage the MACB, >> which looks after Ethernet traffic. It signals to higher levels that a >> message has been received via a Boolean flag. The higher level, running >> asynchronously and at a non-controlled rate, would poll this flag, read >> the message, and clear the flag. We started seeing cases where it seemed >> that the receive mechanism was one message out of step. We realised this >> happened when 2 (or more) messages arrived (and were properly buffered) >> before the higher level had a chance to poll the Boolean flag. We were >> picking up one message, and clearing the flag... and losing the rest. > > <frown> I'll give you each "partial blame" on that score. You > *could* have looked around to see what the current *state* of > the input queue was -- instead of just assuming "there's a > message there" (apologies if I am assuming too much, here, > based on what little you've said)
Ah. Current state of input queue wasn't available to me as such. The code example was very complex. I made the mistake of assuming it worked, since it was published by the silicon supplier - I'll certainly take the blame for *that* error. (To be real clear, the bug in the "driver" code was down to a Boolean which said "there's a message", when it should have been a counter saying "there are N messages".)
> I've learned that programming defensively when it comes > to dealing with the actual iron pays off in spades! E.g., > just because there was an interrupt doesn't mean there > *should* have been an interrupt! (so, expecting things > to *be* indicating an interrupt can bite you)
Oooh, bigtime (re defensive coding). I've been known to code defensively against errors that simply can't happen *now* on the basis that things change and maybe this could happen *later*.
> The best advice when it comes to low level drivers is to > use the vendor supplied code as examples of what the code > *might* want to do. To, hopefully, clarify something that > is vague in the datasheet.
Again, absolutely. For relatively manageable drivers, I'll always roll my own (and wind up with far more defensive code than the example). In this case, it was huge, and we didn't have time... Steve -- http://www.fivetrees.com
Hi Roberto,

On 6/24/2011 12:42 PM, Roberto Waltman wrote:
>> If I mention open source to a client as a possible short-circuit >> for some portion of the project, the first thing out of their >> mouth is "We don't want to use Linux". *Period* (i.e., drop >> this line of discussion or we'll find someone else who'll >> meet our goals). They equate OSS with Linux and, thus, the GPL >> and rule everything out in one fell swoop. > > At a previous employer, a large project was ported from Linux to > NetBSD because of similar concerns.
Glad to hear NBSD "getting that business". I like the NBSD folks because they are low key, don't waste a lot of time beating their chests about their product -- but just trudge along improving it.
> Or may be, I should say "it was ported from a GPL license to an MIT > license."
Exactly. I see Linux as being available on a wider range of things I might want to *play* with, but nothing that would force/encourage me to adopt it (over something "free-r") for a real product. IMO, these free-r options will eventually put the same pressures on more "encumbered" products that those products put on the "commercial" products.
Hi Albert,

On 6/24/2011 5:21 AM, Albert van der Horst wrote:

>> But I certainly agree that a lot of people have used the GPL without >> understanding it - it is very common to equate "open source" and "free >> software" with the GPL, and a lot of code is released under the GPL (no >> version specified) because "I want other people to be able to use my >> code as they wish". In particular, you can find plenty of example code >> and libraries for embedded systems under the GPL, even though the author >> is quite happy for you to use the code in your own systems with any >> other license. > > What is missing here is that you can negotiate with an author > about a separate contract. I would gladly sign a one thousand > dollar contract allowing Microsoft to make millions. > (Non-exclusive, non-transferable, but no obligation to publish > source based on my GPL-ed code.) > The BSD author would got nada.
But, the BSD author wasn't *expecting* (or asking for) anything. So, he doesn't feel "disappointed". Presumably, he made a conscious decision *not* to hide or otherwise "protect" his product -- for whatever reason -- and, seeing it used elsewhere is exactly his goal!
On 24/06/2011 16:02, steve wrote:
> Ok, let me ask the opposite question, since I can't evaluate yours or > anyone elses claims, how many resell their software, where the > customer reuses it as-is in a wide variety of unrelated products. That > surely is an more objective measure of code reuseability. > > You said that the head honcho of well-known embedded RTOS supplier had > terrible coding guidelines, but they must be selling lots of code to > someone repeatedly to be well known so how do you resolve that > apparent conflict? Maybe marketing. But the only reasonable answer is > his coding guidelines are different, not better or worse then yours. I > don't know if he was against table driven code or pro globals but > certainly their are situations where higher levels of code abstraction > aren't necessarily the best solution and trying to shoe horn those > concepts into a product may result is an inferior product that has > limited uses (due to performance, say).
I resolve the conflict by noting that the said head honcho is unlikely to be doing much coding these days ;). Re different coding guidelines: give me just a *bit* of credit for knowing the difference between e.g. use of a tab character and e.g. use of a goto. (Different style I can live with; dangerous practices I can't.) And yes, his guidelines were dangerous (obviously IMO). As for the implication that "higher levels of code abstraction" affect performance: I'll grant you that there are a myriad ways in which you can be too clever for your own good, and wind up with something that is abstracted across too many layers and performs poorly. But, for me, that's just another example of poor code. I wouldn't defend that on the basis of coding guidelines or any other criterion. However, part of the art of coding is knowing the difference. For instance, the goto: I've seen it defended (many times) on the basis of either performance, or error-handling, or any one of many other things. To me, this is all nonsense. I've *never, *ever** come across a case in which a goto can't be eliminated by a proper understanding of code flow, or use of a state machine. (I used to do a lot of legacy code maintenance, so this came up a lot.) Similarly, I've seen a lot of code that is absolutely *infested* with if/then/elses, where my background in hardware (Karnaugh maps, De Morgan's theorem) has allowed me to simplify it to a few logical cases. I always find it shocking that such basic things (e.g. logic rules) are not known to the coders... Steve -- http://www.fivetrees.com
Hi Steve,

On 6/24/2011 2:56 PM, Steve at fivetrees wrote:
> On 24/06/2011 02:52, Don Y wrote: >>> One quick fr'instance: there's some (complex) code to manage the MACB, >>> which looks after Ethernet traffic. It signals to higher levels that a >>> message has been received via a Boolean flag. The higher level, running >>> asynchronously and at a non-controlled rate, would poll this flag, read >>> the message, and clear the flag. We started seeing cases where it seemed >>> that the receive mechanism was one message out of step. We realised this >>> happened when 2 (or more) messages arrived (and were properly buffered) >>> before the higher level had a chance to poll the Boolean flag. We were >>> picking up one message, and clearing the flag... and losing the rest. >> >> <frown> I'll give you each "partial blame" on that score. You >> *could* have looked around to see what the current *state* of >> the input queue was -- instead of just assuming "there's a >> message there" (apologies if I am assuming too much, here, >> based on what little you've said) > > Ah. Current state of input queue wasn't available to me as such. The
OK. I was assuming you accessed the current message through a FIFO's pointers, etc. (i.e., could do the pointer arithmetic to see how much was "available"). 'Nuff said -- *you* saw the code, not I! :> As an aside: I have a philosophical issue regarding duplicating data. I.e., I like having one representation of a datum ("state") wherever possible instead of two (or more) which could potentially get out of sync (similar to your problem). It seems to lead to more robust code -- every "consumer" uses the same "copy" of the datum and in the same *way*. E.g., if you store a "string length" with a string (like "counted strings" in Pascal(?)) but also have another means by which length can be deduced (like ASCIZ strings in C) then you run the risk of one piece of code using the count and another counting them explicitly (strlen()). Fine - until someone forgets to update one or the other (at which time, things fail in irrational ways).
> code example was very complex. I made the mistake of assuming it worked, > since it was published by the silicon supplier - I'll certainly take the > blame for *that* error.
Yup. I looked at a design for a camera circuit some time ago. The components used suggested a different resolution than was *claimed*. Turned out the design had been lifted from an app note and contained that error! Ooops!
> (To be real clear, the bug in the "driver" code was down to a Boolean > which said "there's a message", when it should have been a counter > saying "there are N messages".) > >> I've learned that programming defensively when it comes >> to dealing with the actual iron pays off in spades! E.g., >> just because there was an interrupt doesn't mean there >> *should* have been an interrupt! (so, expecting things >> to *be* indicating an interrupt can bite you) > > Oooh, bigtime (re defensive coding). I've been known to code defensively > against errors that simply can't happen *now* on the basis that things > change and maybe this could happen *later*.
This can actually be *really* hard to do! I faced the same problem recently when trying to code a test suite for a memory management suite. The code could detect things that simply "*couldn't* happen". Period. (i.e., you'd need to blame alpha particles for these sorts of errors) The problem I faced was trying to *fabricate* test cases that I could throw against the code to verify that the code was well-behaved in those situations! <frown> Some environments provide tools to help you stress your code (e.g., starving the free memory pool, etc.). Jaluna included some things to help you harden your drivers.
>> The best advice when it comes to low level drivers is to >> use the vendor supplied code as examples of what the code >> *might* want to do. To, hopefully, clarify something that >> is vague in the datasheet. > > Again, absolutely. For relatively manageable drivers, I'll always roll > my own (and wind up with far more defensive code than the example). In > this case, it was huge, and we didn't have time...
I think this goes to the issue of the thread's title. "Author X" prepares a particular code fragment/suite that fits *his* (actual and/or envisioned) needs. "Consumer Y" assumes (hopes?) said code will address *his* needs as well. But, somewhere in between, an assumption falls apart... And, of course, "Consumer Y" is left holding the proverbial bag! <grin>
Don Y wrote:
> Hi Steve, > > On 6/24/2011 2:56 PM, Steve at fivetrees wrote: >>... >> Again, absolutely. For relatively manageable drivers, I'll always roll >> my own (and wind up with far more defensive code than the example). In >> this case, it was huge, and we didn't have time... > > I think this goes to the issue of the thread's title. > "Author X" prepares a particular code fragment/suite that > fits *his* (actual and/or envisioned) needs. "Consumer Y" > assumes (hopes?) said code will address *his* needs as > well. But, somewhere in between, an assumption falls apart...
A good description of the causes of the Ariane 501 disaster. In a nutshell.
> And, of course, "Consumer Y" is left holding the proverbial bag! > <grin>
Or, digging the pieces of his expensive rocket and satellites out of a tropical swamp to try to understand why it didn't work. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .
Hi Steve,

On 6/24/2011 3:14 PM, Steve at fivetrees wrote:

> However, part of the art of coding is knowing the difference. For > instance, the goto: I've seen it defended (many times) on the basis of > either performance, or error-handling, or any one of many other things. > To me, this is all nonsense. I've *never, *ever** come across a case in > which a goto can't be eliminated by a proper understanding of code flow, > or use of a state machine. (I used to do a lot of legacy code > maintenance, so this came up a lot.)
(sigh) I have to defend the value of the (rare) goto. (Recalling largely from memory and expressing as pseudo-C) my variable precision decimal math package does it's "from_string" conversion something like: do { if (compare(ptr, "nan") == TRUE) { ptr += strlen("nan") if (*ptr != '\0') return ERROR /* nothing else accompanies <NaN> */ /* have a NaN, act accordingly */ break } /* !"NaN" */ if (*ptr == '-') { sign = -1 ptr++ } else if (*ptr == '+') { sign = +1 ptr++ } /* so far: <sign>? */ if (compare(ptr, "infinity")) { /* have: <sign>?<infinity>, act accordingly */ if (*ptr != '\0') return ERROR /* nothing else accompanies <Infinity> */ break } /* so far: <sign>? but not Infinity. *Must* be mumeric */ while (*ptr == '0') { /* note leading zeroes */ ptr++ } /* so far: <sign>?0* next must be part of number */ while (isdigit(*ptr)) { /* accumulate digits left of DP */ ptr++ } /* so far: <sign>?0*([1-9][0-9]*)? next must be DP or exp */ if (*ptr == '.') { /* note position of DP */ ptr++ while (isdigit(*ptr)) { /* accumulate digits right of DP */ ptr++ } } /* so far: <sign>?0*([1-9][0-9]*)?(.[0-9]*) next must be exp */ if ((*ptr == 'e') || (*ptr == 'E')) { ptr++ while (isdigit(ptr)) { /* accumulate exponent */ ptr++ } } if (*ptr != '\0') { return ERROR } while (ONCE); /* hack -- skips a break */ win: /* have a valid string and all the parameters needed to convert * it to internal representation */ [apologies if I've made some horrendous screwup -- I'm rushing to finish before my custard cools...] The actual code is much longer (in terms of amount of paper used, not much more in terms of *complexity* -- but there are lots of pointers to track so you can figure out how many significant digits were present int he input, where the DP was located, etc. The point here is that there are several places where "goto win" would have cleaned up the code. The do-while hack runs the risk of not being familiar to novices (and, also gives trouble if you want to "break break" -- requiring a flag and some kludge logic). And, the do-while cheats me out of three characters per line (because it introduces another indent level) [actually, I think I wrote this inside out -- breaking for errors instead of "wins". dunno. Same argument applies]
> Similarly, I've seen a lot of code that is absolutely *infested* with > if/then/elses, where my background in hardware (Karnaugh maps, De > Morgan's theorem) has allowed me to simplify it to a few logical cases.
<grin> I find I have to leave notes for folks explaining odd choices of conditionals. E.g., if (! ((*ptr != 'e') && (*ptr != 'E')) ) { though that would be a bad choice, here.
> I always find it shocking that such basic things (e.g. logic rules) are > not known to the coders...
I think use of finite automata, logic reduction, *state* reduction ("implication tables") tend to be more hardware taught skills than software. I.e., I was exposed to all of them in my *hardware* classes, not in software. If you think about it, why are so many programmers puzzled by races and hazzards? ("Hmmm... how'd *that* happen?") The apparent aversion to pointers? etc. I think hardware mindsets also come up with different (not necessarily *better*) ways of partitioning things.
On 06/25/2011 10:39 AM, Don Y wrote:

> The point here is that there are several places where "goto win" > would have cleaned up the code. The do-while hack runs the > risk of not being familiar to novices (and, also gives trouble > if you want to "break break" -- requiring a flag and some > kludge logic). And, the do-while cheats me out of three > characters per line (because it introduces another indent level)
I use goto whenever it results in clearer and more readable code. Using "goto error" in a function that ends like this: error: cleanup_stuff(); return retval; } is easy to understand. The 'error' label makes it clear what the purpose is, even without reading any further, and it helps to keep the mainline code free of error handling. It may be possible to rewrite the code to avoid the 'goto', but if that doesn't result in any tangible benefits, why bother ? The extra indentation shouldn't be a problem, though. If you need more than 3-4 levels of indentation, you should probably restructure the code and/or use some extra functions anyway.
>> Similarly, I've seen a lot of code that is absolutely *infested* with >> if/then/elses, where my background in hardware (Karnaugh maps, De >> Morgan's theorem) has allowed me to simplify it to a few logical cases. > > <grin> I find I have to leave notes for folks explaining odd > choices of conditionals. E.g., > if (! ((*ptr != 'e') && (*ptr != 'E')) ) { > though that would be a bad choice, here.
I never worry about simplifying the logic, unless it helps readability.
On 24/06/11 21:39, George Neuner wrote:
> On Thu, 23 Jun 2011 23:17:25 +0200, David Brown > <david.brown@removethis.hesbynett.no> wrote: > >> On 23/06/11 21:01, George Neuner wrote: >>> >>> GPL v1& v2 were not too objectionable, but there has been a general >>> backlash against GPL v3. It's largest failure to date has been Linus >>> Torvald's categorical refusal to put Linux under v3. >> >> As far as Linux goes, Linus Torvalds is very much a pragmatist. When >> publishing Linux, he felt the GPL v2 expressed what he wanted in a >> license, so he used it. Since the GPL v2 did the job, he explicitly >> limited Linux to the GPL v2 (standard GPL's allow the the code to be >> re-licensed under newer versions). Having made that decision early on, >> it was fixed. Linus is not in the position to change it now - that >> would require the permission of every contributor to Linux over the >> years (or the removal of their code). So when the question of putting >> Linux under the GPL v3 came up, he made it barely bothered discussing >> something that was clearly impossible (and that he didn't agree with >> anyway). > > Not exactly. You're absolutely correct that many contributors would > need to OK putting a distribution under new license, and the effort to > do that is considerable ... but Torvalds himself maintains exclusive > control over licensing of the kernel. He has written extensively > about his dislike for GPL v3 and why he felt the kernel could not be > subjected to it - much of which has to do with the increasing use of > Linux in embedded systems. >
It's true that Linus Torvalds prefers the GPLv2 to GPLv3 for Linux (I fully agree with him here), and one of the many reasons is that the GPLv3 would make it more difficult to use Linux in embedded systems. Your other claim that "Torvalds himself maintains exclusive control over licensing of the kernel" is quite simply incorrect. With Linux, every contributor retains the copyrights to their contribution (unlike some other projects, like gcc or Open Office), and thus the individuals retain the right to control the licence used. The licence for a file in the Linux source code cannot be changed without the consent of all the copyright owners for all the parts of that file - and I'd be surprised if there are more than a handful of files in Linux that have only one contributor. Torvalds is probably still the single largest individual contributor, at least in the deep kernel itself, but he has far from any exclusive rights there. It's probably been a decade since he made the top ten code contributors list for any Linux releases.

The 2024 Embedded Online Conference