2015-02-26 15:02:31 +00:00
|
|
|
/*
|
|
|
|
PURPOSE: (Graceful Simulation termination with timing data output.)
|
|
|
|
|
|
|
|
PROGRAMMERS:
|
|
|
|
(((Robert W. Bailey) (LinCom) (Feb 1991) (v1.0) (Initial Release.))
|
|
|
|
((Robert W. Bailey) (LinCom) (April 1992) (--) (Realtime clock))
|
|
|
|
((Scott Killingsworth) (LinCom) (September 1997) (--) (Issue #1016)))
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
2015-06-01 15:28:29 +00:00
|
|
|
#include "trick/Executive.hh"
|
2015-06-02 13:29:34 +00:00
|
|
|
#include "trick/ExecutiveException.hh"
|
2015-06-01 15:28:29 +00:00
|
|
|
#include "trick/message_proto.h"
|
|
|
|
#include "trick/message_type.h"
|
|
|
|
#include "trick/release.h"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
@design
|
|
|
|
-# Set the mode to Exit.
|
|
|
|
Requirement [@ref r_exec_mode_3]
|
|
|
|
-# Wait for asynchronous or AMF threads to complete if the user has specified to do so
|
|
|
|
-# The scheduler calls shutdown jobs
|
|
|
|
Requirement [@ref r_exec_discrete_4]
|
|
|
|
-# If an exception is caught during calling the shutdown jobs the exception is ignored as we are already terminating.
|
|
|
|
-# The scheduler prints a simulation shutdown message
|
|
|
|
-# The scheduler kills all child threads
|
|
|
|
-# Return the exception_return value. (Set to 0 if no exception thrown.)
|
|
|
|
*/
|
|
|
|
int Trick::Executive::shutdown() {
|
|
|
|
|
|
|
|
double sim_elapsed_time;
|
|
|
|
double cpu_time;
|
|
|
|
double actual_cpu_time;
|
|
|
|
double sim_to_cpu;
|
|
|
|
unsigned int ii;
|
|
|
|
int process_id = 0 ;
|
|
|
|
struct rusage cpu_usage_buf ;
|
|
|
|
|
|
|
|
SIM_MODE prev_mode = mode ;
|
|
|
|
|
|
|
|
/* Set mode to ExitMode. */
|
|
|
|
mode = ExitMode;
|
|
|
|
|
|
|
|
/* If we made it past initialization */
|
|
|
|
if ( prev_mode != Initialization ) {
|
|
|
|
/* Wait for asynchronous threads to complete if the user has specified to wait. */
|
|
|
|
for (ii = 1; ii < threads.size() ; ii++) {
|
|
|
|
if ( (threads[ii]->process_type == Trick::PROCESS_TYPE_ASYNC_CHILD || threads[ii]->process_type == Trick::PROCESS_TYPE_AMF_CHILD) && threads[ii]->shutdown_wait_async ) {
|
|
|
|
message_publish(MSG_INFO, "Waiting for asynchronous or AMF thread %d to finish\n", ii ) ;
|
|
|
|
while (threads[ii]->child_complete == false) {
|
|
|
|
RELEASE_1();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
/* Call the shutdown jobs. */
|
|
|
|
if (initialization_complete == true) {
|
|
|
|
shutdown_queue.reset_curr_index() ;
|
|
|
|
while ( (curr_job = shutdown_queue.get_next_job()) != NULL ) {
|
|
|
|
curr_job->call() ;
|
|
|
|
}
|
|
|
|
}
|
2015-06-02 13:29:34 +00:00
|
|
|
} catch (Trick::ExecutiveException & ex ) {
|
|
|
|
/* Handle exception type Trick::ExecutiveException. Set the file name and error message.
|
2015-02-26 15:02:31 +00:00
|
|
|
Return the exception return code. */
|
|
|
|
except_return = ex.ret_code ;
|
|
|
|
except_file += std::string(" then exception caught in ") + ex.file ;
|
|
|
|
except_message += std::string(" then exception Message: ") + ex.message ;
|
|
|
|
} catch (const std::exception &ex) {
|
|
|
|
except_return = -1 ;
|
|
|
|
if ( curr_job != NULL ) {
|
|
|
|
except_file += " " + curr_job->name ;
|
|
|
|
} else {
|
|
|
|
except_file += " somewhere in Executive::shutdown" ;
|
|
|
|
}
|
|
|
|
except_message += std::string("standard exception caught") + ex.what();
|
|
|
|
} catch (...) {
|
|
|
|
/* Handle unknown exceptions. Set the file name and error message to unknown. Return -1. */
|
|
|
|
except_return = -1 ;
|
|
|
|
except_file = "somewhere in shutdown()" ;
|
|
|
|
except_message = "unknown error" ;
|
|
|
|
}
|
|
|
|
|
|
|
|
getrusage(RUSAGE_SELF, &cpu_usage_buf);
|
|
|
|
cpu_time = ((double) cpu_usage_buf.ru_utime.tv_sec) + ((double) cpu_usage_buf.ru_utime.tv_usec / 1000000.0);
|
|
|
|
|
|
|
|
/* Calculate simulation elapsed sim time and actual cpu time */
|
|
|
|
sim_elapsed_time = get_sim_time() - sim_start;
|
|
|
|
actual_cpu_time = cpu_time - cpu_start;
|
|
|
|
if (actual_cpu_time <= 1e-6) {
|
|
|
|
sim_to_cpu = 1e8;
|
|
|
|
} else {
|
|
|
|
sim_to_cpu = sim_elapsed_time / actual_cpu_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a shutdown message. */
|
|
|
|
message_publish(MSG_NORMAL , "\n"
|
|
|
|
"SIMULATION TERMINATED IN\n"
|
|
|
|
" PROCESS: %d\n"
|
|
|
|
" ROUTINE: %s\n"
|
|
|
|
" DIAGNOSTIC: %s\n\n"
|
|
|
|
" SIMULATION START TIME: %12.3f\n"
|
|
|
|
" SIMULATION STOP TIME: %12.3f\n"
|
|
|
|
" SIMULATION ELAPSED TIME: %12.3f\n"
|
|
|
|
" ACTUAL CPU TIME USED: %12.3f\n"
|
|
|
|
" SIMULATION / CPU TIME: %12.3f\n"
|
|
|
|
" INITIALIZATION CPU TIME: %12.3f\n" ,
|
|
|
|
process_id, except_file.c_str(), except_message.c_str() ,
|
|
|
|
sim_start , get_sim_time() , sim_elapsed_time , actual_cpu_time , sim_to_cpu , cpu_init ) ;
|
|
|
|
|
|
|
|
/* Kill all threads. */
|
|
|
|
for (ii = 1; ii < threads.size() ; ii++) {
|
|
|
|
if ( threads[ii]->running ) {
|
|
|
|
pthread_cancel(threads[ii]->get_pthread_id()) ;
|
|
|
|
}
|
|
|
|
#if ! ( __APPLE__ || __CYGWIN__ || __Lynx__ )
|
|
|
|
// Even Linux is hanging on this call right now... hmmm.
|
|
|
|
//pthread_join(threads[ii]->thread_id, (void **) NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the exception_return value. This defaults to 0 if no exceptions were thrown. */
|
|
|
|
return(except_return) ;
|
|
|
|
|
|
|
|
}
|