Using embOS API in C++ constructor of global objects
Contents
Introduction
Global objects of C++ classes need to be constructed by the runtime initialization. The runtime initialization code calls the C++ constructors before main().
#include "RTOS.h"
#include "stdlib.h"
class foo {
public:
foo(void) {
OS_MUTEX_Create(&m); // Called before OS_Init()
}
private:
OS_MUTEX m;
};
static foo MyFoo;
int main(void) {
OS_Init(); // Initialize embOS
OS_Start(); // Start embOS
return 0;
}
embOS API like OS_MUTEX_Create() must be called after OS_Init() only but in the above example it will actually be called before main() and with it before OS_Init(). This example will result in OS_Error() with the error number OS_ERR_INIT_NOT_CALLED (165).
Toolchains provide different solutions for this problem:
IAR EWARM
The IAR linker option --manual_dynamic_initialization can be used to skip the C++ dynamic initialization phase in the startup code. The application must then call __iar_dynamic_initialization() (declared in iar_dynamic_init.h) after OS_Init().
#include "RTOS.h"
#include "stdlib.h"
#include "iar_dynamic_init.h"
class foo {
public:
foo(void) {
OS_MUTEX_Create(&m); // Called after OS_Init()
}
private:
OS_MUTEX m;
};
static foo MyFoo;
int main(void) {
OS_Init(); // Initialize embOS
__iar_dynamic_initialization(); // Late initialization of constructors
OS_Start(); // Start embOS
return 0;
}
Embedded Studio
Automatic Initialization
The SEGGER Linker automatically calls the constructor of global objects of C++ classes. With a global class object, such as the following, the constructor for the instance is linked into the section .ctors or into init_array.
class foo {
public:
foo(void) {
}
};
static foo MyFoo;
The linker script defines a block for all constructors and automatically does the initialization when there is at least one constructor to call.
define block ctors { section .ctors, section .ctors.*, block with alphabetical order { init_array } };
define block dtors { section .dtors, section .dtors.*, block with reverse alphabetical order { fini_array } };
initialize by calling __SEGGER_init_ctors { block ctors }; // Call constructors for global objects which need to be constructed before reaching main (if any). Make sure this is done after setting up heap.
Manual Initialization
With Embedded Studio the solution is to remove initialize by calling __SEGGER_init_ctors from the linker script and add the following function:
extern void (*__ctors_start__[])(void);
extern void (*__ctors_end__[])(void);
void init_ctors(void);
void init_ctors(void) {
void (**f)(void);
for (f = __ctors_start__; f < __ctors_end__; f++) {
(*f)();
}
}
init_ctors must then be called in the application after OS_Init():
#include "RTOS.h"
#include "stdlib.h"
class foo {
public:
foo(void) {
OS_MUTEX_Create(&m); // Called after OS_Init()
}
private:
OS_MUTEX m;
};
static foo MyFoo;
int main(void) {
OS_Init(); // Initialize embOS
init_ctors(); // Late initialization of constructors
OS_Start(); // Start embOS
return 0;
}