I have some questions about inits during C++ constructors on the SBL2e. I have code that does this at boot on many of the mod52xx platforms that seems to crash on the SBL2e. I have found that the SBL2e code cannot use the iprintf() statements in the constructors and I must use writestring() instead. Also, I seem to remember discussion on this forum a while ago indicating that the GetSR and SetSR calls that make the init possible might not be needed in future revs, but I am using the rev 2.50 beta. Has this been resolved on the MOD platforms, but just works differently on the SBL2e? Also, it seems like the GetSR_IntLevel() and SetSR_IntLevel() might reasonably be compatible so that whatever was returned by the GetSR_IntLevel() call could be compatible with the SetSR_IntLevel() call without the (GetSR_IntLevel() & 0x0F00 ) >> 8 steps....On the Mod52 platforms the constructor inits use the following code:
// 1) -------------
// Lock tasks or ISRs out so we can init the global struct in a sec...
// Instead, set the SR register to prevent interrupts, which will prevent
// any task switching. There are functions to read and write the SR
// in cfinter.h.
// The following gets SR value and converts to interrupt level.
WORD Current_Int_Level = ( ( GetSR_IntLevel() & 0x0F00 ) >> 8 );
//
//// 2) -------------
//// Set SR so only un-maskable interrupts can occur
SetSR_IntLevel( 7 );
// iprintf("_Level 7 = %X, ret= %X\r\n",
// Current_Int_Level,
// GetSR_IntLevel() );
//// 3) -------------
// Now safely can init class objects without potential for disturbance.
//// 4) -------------
//// And finally, unlock:
SetSR_IntLevel( Current_Int_Level );
Your subject line caught my attention, in particular the static constructor piece. I wrote a Wiki article about the dangers of making OS calls in static constructors, in the paragraph on Initializing Statics - A Cautionary Tale(scroll to the bottom of the article, it's the second to the last paragraph). This may have nothing to do with your problem, but if your crash is happening before you reach UserMain() I would suspect it is relevant.
I've worked around this in the pas by creating C++ classes derived from a base class that has an init call in it.
The constructors then do nothing but put themselves on a linked list that then calls all the init functions AFTER the RTOS is started up.
Tod & Paul:
Thanks for your replies. Paul, do you have any code showing how to delay the linked list inits of the OS calls for static class constructors until after UserMain runs? Tod, I hear you on trying to avoid the NLSOs, however in my case the whole point of the class is to be a global repository for data and methods that act on it: a place where many tasks can share data. To do this, one of the private objects in the class is an OS_CRIT section that allows some of the class's methods a way to lock a large struct member during access. This ensures that different tasks each have a complete set of non-atomic data. The reason the constructor gets into trouble is that it needs to call OSCritInit for the OS_CRIT object and of course, since this runs before UserMain it causes trouble. I am not sure how to do this without having an instance of the class declared as an external object outside of UserMain or any other function or task. Suggestions?
Thanks, Ridgeglider
I've really moved away from static classes (mostly for unit testing and dependency injection reasons). However, in the embedded world a class that ACTS like a static class can be really useful. I usually have ONE and only one true static class. It contains a private constructor and the only methods it has are calls that return instances of other classes that I want to act like static (or singleton) classes. It's basically a wrapper that "externalizes" the singleton pattern. Instead of writing every class you need with a singleton pattern I just have this one class that I code to return a singleton instance of any class I need to use that way. You probably need to write your constructor to do less (yes it will violate RAII). Then add an Initialize() method that does the OS stuff. Then in UserMain you do something like:
YourClass instance_of_your_class = Startup::GetYourClassAsSingleton(); //yes this can be a local var that goes away.
instance_of_your_class.Initialize(); //You'll only every call Initialize this once.
Now anywhere else in your code you can get the initialized version with
Startup::GetYourClassAsSingleton(); //It will always return the same (now initialized) instance.
I'm in a bit of a time bind right now. If this isn't clear I'll put up some code on GitHub later or if you can't wait download the AjaxII sample and look at the Startup code - I'm pretty sure I used this approach in that code.
Tod: thanks for your tips. After looking at your suggestions and your AJAXII code, I confess to still being a bit fuzzy. Your offer to put some add'l code up would be really greatly appreciated. There is lots of good stuff here. Keep proselytizing C++!
Some background might be helpful. In C# and Java there is a lot written about dependency injection and Inversion of Control (IoC). As a consequence there are a number of IoC containers available in those languages that make life easier. The point of all this is generally to make code reusability, unit testing, and long-term maintenance easier. A "Service Provider" is sort of a dumbed down IoC container. The IoC containers I have used all have the ability to return an object as a singleton so you never have to bother implementing the singleton pattern inside a class itself. This makes your library more reusable. Most of the time I have only one TcpServer in my code but now if I want to have more than one I don't need to rewrite anything. What I've shown in the posted code is a very limited Service Provider (it only provides two objects) but it makes for a decent example.
I think of static classes as no better than global data wrapped in a namespace. In fact they might be worse. If you just wrapped methods and variables in a namespace you wouldn't be tempted to write a constructor. As soon as you see the need for a constructor extract the associated data and methods into a non-static class and use some form of the singleton pattern. You don't need to use the techniques I've shown here you can just hard code the singleton pattern into your class (especially if it's not part of a library).