h4yn0nnym0u5e
Well-known member
Hi folks
This is directly-related to Teensy only in that I've been banging my head against this wall for a few days with getting some Audio library objects to die quietly and not take the whole system with them! I've tried Googling but not really found much that's relevant. Do bear in mind my C++ understanding is pretty superficial at the moment: I'm pretty experienced at embedded C, but I'm closer to bare metal there.
So, background, just in case. I'm working on dynamic audio objects, where they can be created and destroyed in a running system with new and delete, or by making them automatic variables in a function. Obviously all useful object classes are (a) derived from the AudioStream class, and maybe others, and (b) provide an update() function that is called under interrupt every 2.9ms, if the object's "active" flag is set. I believe I've got the infrastructure working OK, so on object destruction connections get unlinked, pending audio blocks are handed back to the system etc., which is mostly taken care of in the ~AudioStream() code as it's essentially common to all objects. Some classes use audio blocks which the base AudioStream isn't aware of, and those need their own destructor code to return them to the pool, to avoid "block leaks". The unlinking process is fairly hairy, and interrupts are thus internally disabled while that's going on, using __disable_irq() and __enable_irq(), similar to other places in the code.
My understanding of the C++ destructor process is that destructors get called in turn in "reverse order", so last-created-first-destroyed, derived class destructor before base, etc.. Only after this process has finished is the object's memory freed up and possibly corrupted, and / or other actions taken by the C++ run-time system. As destructors operate on the object being destroyed, I'd presume it still exists while the destructor "housekeeping" is executing.
What I have found is that if the whole destruction process is not protected by wrapping the delete in Audio[No]Interrupts() calls, or by setting the active flag to false in the derived class's destructor (doing this in ~AudioStream is too late, apparently), then an audio interrupt occurring prior to the __disable_irq() in the ~AudioStream() destructor can cause the object's update() call never to return. I don't understand this, because although the destruction process has started, essentially at this point it's surely just another piece of foreground code, and as very little of my destructor code has run, none of which will have put the data structure in an unsafe state, I would expect simply to get one last-gasp execution of the update() code before the destruction resumes and completes. Actually what happens is update() is called, and never returns. CrashReport yields no information.
While it's not vital, it's a bit of a pain to mandate every Audio class provides a destructor with active = false in it; wrapping every delete in Audio[No]Interrupts() calls is tedious for the programmer, and in any case isn't possible for objects instantiated as automatic variables in a function.
Any ideas? I'd be more than happy with a solution that works at the AudioStream base class level.
Cheers
Jonathan
This is directly-related to Teensy only in that I've been banging my head against this wall for a few days with getting some Audio library objects to die quietly and not take the whole system with them! I've tried Googling but not really found much that's relevant. Do bear in mind my C++ understanding is pretty superficial at the moment: I'm pretty experienced at embedded C, but I'm closer to bare metal there.
So, background, just in case. I'm working on dynamic audio objects, where they can be created and destroyed in a running system with new and delete, or by making them automatic variables in a function. Obviously all useful object classes are (a) derived from the AudioStream class, and maybe others, and (b) provide an update() function that is called under interrupt every 2.9ms, if the object's "active" flag is set. I believe I've got the infrastructure working OK, so on object destruction connections get unlinked, pending audio blocks are handed back to the system etc., which is mostly taken care of in the ~AudioStream() code as it's essentially common to all objects. Some classes use audio blocks which the base AudioStream isn't aware of, and those need their own destructor code to return them to the pool, to avoid "block leaks". The unlinking process is fairly hairy, and interrupts are thus internally disabled while that's going on, using __disable_irq() and __enable_irq(), similar to other places in the code.
My understanding of the C++ destructor process is that destructors get called in turn in "reverse order", so last-created-first-destroyed, derived class destructor before base, etc.. Only after this process has finished is the object's memory freed up and possibly corrupted, and / or other actions taken by the C++ run-time system. As destructors operate on the object being destroyed, I'd presume it still exists while the destructor "housekeeping" is executing.
What I have found is that if the whole destruction process is not protected by wrapping the delete in Audio[No]Interrupts() calls, or by setting the active flag to false in the derived class's destructor (doing this in ~AudioStream is too late, apparently), then an audio interrupt occurring prior to the __disable_irq() in the ~AudioStream() destructor can cause the object's update() call never to return. I don't understand this, because although the destruction process has started, essentially at this point it's surely just another piece of foreground code, and as very little of my destructor code has run, none of which will have put the data structure in an unsafe state, I would expect simply to get one last-gasp execution of the update() code before the destruction resumes and completes. Actually what happens is update() is called, and never returns. CrashReport yields no information.
While it's not vital, it's a bit of a pain to mandate every Audio class provides a destructor with active = false in it; wrapping every delete in Audio[No]Interrupts() calls is tedious for the programmer, and in any case isn't possible for objects instantiated as automatic variables in a function.
Any ideas? I'd be more than happy with a solution that works at the AudioStream base class level.
Cheers
Jonathan