/* * This routine is the initialization task for this test program. * It is called from init_exec and has the responsibility for creating * and starting the tasks that make up the test. If the time of day * clock is required for the test, it should also be set to a known * value by this function. * * Input parameters: NONE * * Output parameters: NONE * * COPYRIGHT (c) 1994 by Division Incorporated * Based in part on OAR works. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. * * * by Rosimildo da Silva: * Modified the test a bit to indicate when an instance is * global or not, and added code to test C++ exception. */ #include #include #include #include #include #include #include #include #ifdef RTEMS_TEST_IO_STREAM #include #endif const char rtems_test_name[] = "CONSTRUCTOR/DESTRUCTOR"; extern "C" { #include extern rtems_task main_task(rtems_task_argument); } static int num_inst = 0; static void check_end_of_test(void) { if ( num_inst == 0 ) { TEST_END(); } } class AClass { public: AClass(const char *p = "LOCAL" ) : ptr( p ) { num_inst++; printf( "%s: Hey I'm in base class constructor number %d for %p.\n", p, num_inst, this ); /* * Make sure we use some space */ string = new char[50]; sprintf(string, "Instantiation order %d", num_inst); }; virtual ~AClass() { // MUST USE PRINTK -- RTEMS IS SHUTTING DOWN WHEN THIS RUNS printk( "%s: Hey I'm in base class destructor number %d for %p.\n", ptr, num_inst, this ); printk("Derived class - %s\n", string); num_inst--; check_end_of_test(); }; #if __cplusplus >= 201103L AClass& operator=(const AClass&) = default; #endif virtual void print() { printf("%s\n", string); }; protected: char *string; const char *ptr; }; class BClass : public AClass { public: BClass(const char *p = "LOCAL" ) : AClass( p ) { num_inst++; printf( "%s: Hey I'm in derived class constructor number %d for %p.\n", p, num_inst, this ); /* * Make sure we use some space */ string = new char[50]; sprintf(string, "Instantiation order %d", num_inst); }; ~BClass() { printk( "%s: Hey I'm in derived class destructor number %d for %p.\n", ptr, num_inst, this ); printk("Derived class - %s\n", string); num_inst--; check_end_of_test(); }; void print() { printf("Derived class - %s\n", string); } }; class RtemsException { public: RtemsException( const char *module, int ln, int err = 0 ) : error( err ), line( ln ), file( module ) { printf( "RtemsException raised=File:%s, Line:%d, Error=%X\n", file, line, error ); } void show() { printf( "RtemsException ---> File:%s, Line:%d, Error=%X\n", file, line, error ); } private: int error; int line; const char *file; }; AClass foo( "GLOBAL" ); BClass foobar( "GLOBAL" ); void cdtest(void) { AClass bar, blech, blah; BClass bleak; #ifdef RTEMS_TEST_IO_STREAM std::cout << "Testing a C++ I/O stream" << std::endl; #else printf("IO Stream not tested\n"); #endif bar = blech; rtems_task_wake_after( 5 * rtems_clock_get_ticks_per_second() ); } // // main equivalent // It can not be called 'main' since the bsp owns that name // in many implementations in order to get global constructors // run. // static void foo_function() { try { throw "foo_function() throw this exception"; } catch( const char *e ) { printf( "foo_function() catch block called:\n < %s >\n", e ); throw "foo_function() re-throwing execption..."; } } rtems_task main_task( rtems_task_argument ) { cdtest(); printf( "*** TESTING C++ EXCEPTIONS ***\n\n" ); try { foo_function(); } catch( const char *e ) { printf( "Success catching a char * exception\n%s\n", e ); } try { throw std::runtime_error("thrown std::runtime object"); } catch (std::exception const& e) { printf("throw std::runtime: caught: %s\n", e.what()); } try { printf( "throw an instance based exception\n" ); throw RtemsException( __FILE__, __LINE__, 0x55 ); } catch( RtemsException & ex ) { printf( "Success catching RtemsException...\n" ); ex.show(); } catch(...) { printf( "Caught another exception.\n" ); } printf( "Exceptions are working properly.\n" ); rtems_task_wake_after( 5 * rtems_clock_get_ticks_per_second() ); printf( "Global Dtors should be called after this line....\n" ); exit(0); } /* * Exceptions during system initialization work only on targets which do not * need a registration of exception frames during the global construction. In * particular, targets which use the DWARF2 unwinder cannot use exceptions * during system initialization. */ #if defined(__arm__) #define CAN_DO_EXCEPTIONS_DURING_SYSINIT #endif #ifdef CAN_DO_EXCEPTIONS_DURING_SYSINIT static void early_exception() { try { throw "early exception"; } catch( const char *e ) { rtems_test_assert(strcmp(e, "early exception") == 0); throw "early exception 2"; } } #endif static void test_exceptions_during_system_init() { TEST_BEGIN(); #ifdef CAN_DO_EXCEPTIONS_DURING_SYSINIT try { early_exception(); } catch( const char *e ) { rtems_test_assert(strcmp(e, "early exception 2") == 0); } #endif } RTEMS_SYSINIT_ITEM( test_exceptions_during_system_init, RTEMS_SYSINIT_IDLE_THREADS, RTEMS_SYSINIT_ORDER_LAST );