3

A hurdle in using C++ (instead of handling C++ as "C with a few extra features") in low-level embedded development is caused by interrupts. Often there are cases where time must be measured in individual CPU cycles, and some classes have no business being used there. Implicit conversions, copy constructors and similar things can cause issues when used within interrupts, especially if they happen behind the scenes. On the other hand, some carefully designed classes could be meaningfully used in interrupts.

This raises a question: is there an elegant way to signal the compiler that a specific class, function, or variable (or just code lines) should throw a compile error when used inside an interrupt? (to not have to rely so heavily on comments stating //Never call this from an interrupt!)

(If not, would it make sense to try getting something like this into the next C++ standard? I'm thinking of something like how the constexpr specifier informs the compiler what a function or variable can or cannot be used for. Would a nointerrupt specifier make sense, or does something already exist that provides that functionality?)

HelpingHand
  • 1,294
  • 11
  • 27
vsz
  • 4,811
  • 7
  • 41
  • 78
  • I am afraid comments are your only option so far. – πάντα ῥεῖ Apr 24 '19 at 10:41
  • 6
    I doubt it'll be accepted into the standard as a keyword. Seems too specific a language feature to warrant it. But you could go for a pair of attributes I suppose. Something like `[[is_isr]]` for the routine and `[[isr_safe]]` for (member) functions to document it about itself. Then static analysis may proceed. – StoryTeller - Unslander Monica Apr 24 '19 at 10:44
  • If it's all implemented in custom code, `assert()`s might be an option as well (to determine at least at runtime what shouldn't be done). – Scheff's Cat Apr 24 '19 at 10:47
  • 1
    C as well as C++ has no notion of interrupts so this feature can't really get into C++ standard. You can however create some sort of lint for clang-tidy or the like that would check that inside certain functions only specific list of calls is being made. – Dan M. Apr 24 '19 at 10:48
  • 2
    @StoryTeller `[[isr_safe]]` sounds promising. – πάντα ῥεῖ Apr 24 '19 at 10:49
  • @DanM. Well, there are things like _`naked`_ attributes already. – πάντα ῥεῖ Apr 24 '19 at 10:50
  • 1
    @πάνταῥεῖ - Yeah. And come to think of it, there isn't really a need for two attributes. Can be treated like const qualifiers on member functions. Can only call other `[[isr_safe]]` stuff. Might gel well with the standard `signal` stuff too. – StoryTeller - Unslander Monica Apr 24 '19 at 10:51
  • @πάνταῥεῖ those are not part of the standard though. – Dan M. Apr 24 '19 at 10:53
  • 2
    @DanM. Well, as StoryTeller already mentioned, I think we discuss beyond standard already, but attributes might be a good solution for the problem. Embedded (bare metal) programming already needs some special stuff beyond the c++ standard. – πάντα ῥεῖ Apr 24 '19 at 10:55
  • 1
    For me it seems that the problem is actually an ability to put arbitrary code into interrupt callbacks. How about keeping them in isolation allowing client code to consume a friendly interface? – user7860670 Apr 24 '19 at 10:55
  • To answer the question: yes, you can do this by having a C compiler compile the file where the ISR resides. As for future C++ standards, the language has gone complete haywire since C++11. [C++ is _moving away_ from deterministic embedded systems and hardware-related programming](https://embeddedgurus.com/barr-code/2018/02/c-the-immortal-programming-language/). – Lundin Apr 24 '19 at 11:06
  • @Lundin : Mixing two compilers for a single project opens another can of worms, and makes it more difficult to use classes in the ISR. Also, no one is forced to use **all** new features added since C++11. And the statistics you cited shows a slight increase for the last 3 years, and is around 25% anyway, so it's in no way dying out. And those statistics fail to consider that many embedded projects are only a few dozens or hundreds of lines long (blinking lights in cheap toys or in Christmas lights) were there is no point in using C++. Maybe in 10000+ line applications C++ is more common? – vsz Apr 24 '19 at 11:20
  • The main problem with any programming language is this: as soon as you add some sort of feature to the standard, you can be _dead certain_ that someone will use it all over the place, good practice or bad practice. C++ suffers greatly from this, since the language contains such extreme amounts of features that can be potentially misused. For example, a list _summarizing_ all poorly-defined behavior in C++ is enough to fill a thick book. I think it is around 20 pages in C (already a fiasco there) and somewhere around 200 pages in C++. – Lundin Apr 24 '19 at 11:32
  • @vsz I believe the survey was directed to professional embedded devs only, which suits the trend I'm seeing too. Those will all be 10k+ LOC projects. If they would have asked hobbyists too, you'd get entirely different statistics. As you'd then get them Christmas light people, namely the Arduino mob. They are all exclusively using C++ on a completely unsuitable MCU (8 bit AVR), every single one a walking example of C++ use gone terribly wrong. – Lundin Apr 24 '19 at 11:37
  • 1
    wow that is a lot of assumptions. Not possible for C++ to replace C for certain applications, this being one of them. There was no reason to try to make such claims to get to your question you could have just asked your question....although it isnt a stackoverflow question it is closer to a programmers.stackexchange question but they may also reject it there. I would avoid starting with such statements in the future, get to the point. – old_timer Apr 24 '19 at 13:38
  • @old_timer : If I just asked the one-sentence question in the title, I would have gotten lots of comments and answers asking why I need such a thing. If you have a certain sentence in mind the removal of which would improve the question and make it easier to be answered, just point out and I'll remove it if it's necessary. – vsz Apr 24 '19 at 14:14
  • 1
    If you want to change the C++ standard this is very much the wrong place to do it, there are no doubt forums and meetings within that standards body for this discussion. Definitely not a stackoverflow question in any way. Now if you were to take a current compiler and the mcu thing is irrelevant to your question anyway, and show I want to have the compiler flag this code in this example, this is what I tried, it failed is there any other way with this compiler and language. That "might" be a stackoverflow question. – old_timer Apr 24 '19 at 16:58
  • 1
    C barely fits into baremetal programming, have to toss almost all of the C library functions. C++ is even less of a fit. They will always be shimmed in with duct tape and bailing wire, those languages do not fit there naturally nor natively nor will they. If you truly want clean C or C++ on what is traditionally baremetal then run an RTOS instead and call it done. – old_timer Apr 24 '19 at 17:00
  • The primary compilers are open source and a number of vendors customize them for this environment you can simply add this feature and provide that toolchain to the masses. In your case it is even broader unlike the cpu and mcu vendors adding stuff for their solution yours sounds to be for everyone not just cpus and mcus. – old_timer Apr 24 '19 at 17:02
  • @old_timer : basically my question was about a problem I would like to solve. Just as it says in the title. About the C++ standard, it was meant as a side comment. My main point was this part: *"... or does something already exist that provides that functionality?"*. I'll edit it to make the question less focused on it. – vsz Apr 24 '19 at 17:55
  • Since there is no means for the compiler to know that a function is an interrupt routine, and an interrupt vector can be assigned at runtime, I cannot see how this could work or would solve any issue. It could also be defeated by callbacks through pointers, and the issue is not specific to C++, it is as likely that some C function is inappropriate or ill-advised in an interrupt. On the subject of "opinion", it is certainly an opinion that this is a problem, and you are canvassing opinion on a solution. My opinion is that the solution lies in good design, design guidelines and code review. – Clifford Apr 24 '19 at 22:30
  • 2
    If it worked at all, this seems like the perfect use-case for a compiler #pragma, since a) it really doesn't belong in the C++ standard and b) it really will be compiler-specific (even if the end result is almost always the same generated code). That said, as Clifford pointed out, the concern is that this could provide a false sense of security, because things like function pointers and linker symbols mean that you could probably bypass this protection anyway. The day something like this is my biggest problem is the day I can retire. – Dan Apr 25 '19 at 00:15
  • @Dan : `const` in C also provides a false sense of security, because it can be defeated through pointers. It is still a useful feature. Many safety features can be circumvented, in C and C++ you can shoot yourself in the foot if you really really want to. Many language features are there to help you to prevent accidentally shooting yourself in the foot, and just because they don't prevent you from *deliberately* shooting yourself in the foot doesn't mean they are completely useless. – vsz Apr 25 '19 at 04:20
  • @vsz: Wow! Defensive much? _Of course_ `const` can be circumvented by casting it away. But that's **deliberate** (your use case was essentially accidentally/unknowingly calling a dangerous function). Even a simple declaration of a local `int a[1000]` can cause a crash (MCU, limited RAM for stack). We could talk all day about ways to shoot yourself in the foot. Trust me, I know C (and C++) very well. I think you're a little too invested in your idea. And you didn't address #pragma, which is one of the most common ways compilers tag ISRs. Peace out. – Dan Apr 26 '19 at 10:29
  • @Dan : *"Of course const can be circumvented by casting it away. But that's deliberate"* - You said that a hypothetical protection from accidentally calling a dangerous function can be bypassed by function pointers and linker symbols. Woulnd't that sort of bypassing be just as *deliberate*? – vsz Apr 26 '19 at 10:46
  • @vsz: No. You can still call a function whose use from interrupt is of unknown suitability. You could from naiveté or ignorance call a function that you shouldn't. However, I have never seen a time when casting away const was a) made sense or b) couldn't be done another way. I've never seen a "casting away const" that made sense, but I'm sure we could artificially create such a scenario. [I don't have a dog in this hunt.](https://www.google.com/search?q=i+don%27t+have+a+dog+in+this+fight&oq=i+don%27t+have+a+dog+in+this+fiht&aqs=chrome..69i57j0l3.4823j1j7&sourceid=chrome&ie=UTF-8) – Dan Apr 28 '19 at 01:07

1 Answers1

0

Like the main system context (and task functions, if you are using an OS), interrupt service routines are just other contexts. The question which code to run (methods of which subset of classes) is orthogonal to the technique of the (class) libraries itself.

RTOS libraries often impose "limits" which APIs may be called in ISRs (or, in ISRs with a given priority) - but these limits are "only" required to maintain data consistency, and not for HW technical reasons imposed by the µC infrastructure.

You want to limit the use of the existing class libraries to certain context(s) because some class implementations consume more resources (time, stack memory space?) than you can afford in ISRs, but this is a matter of your deployment decisions in SW project architecture.

Therefore, the most elegant solution from my point of view would be to go back to SW architecture level, create a neat piece of documentation (maybe a UML deployment diagram may already help you quite a lot), and to specify in which contexts you want which code to be executed. You will probably find that in ISR contexts, only a tiny fraction of your code is to be executed, so it may be feasible to mark the subset of classes (or, subsets of methods of classes) that are supposed to run in ISR contexts from the top-down perspective. You can backup this procedure by starting/finishing every ISR by setting/resetting an ISR-specific flag within a dedicated shared memory area, and to add assert statements to the critical classes/methods that detect if the particular code is run in an unwanted ISR context.

HelpingHand
  • 1,294
  • 11
  • 27