mirror of
https://github.com/nasa/trick.git
synced 2024-12-24 15:26:41 +00:00
c4e60d9f9a
* Proposed fix for deadlock on shutdown * Terminate C style comment. * Added needed libs for applicable tests and updated the logic for when allowing/disallowing connections. * Need to load additional trick libs for applicable tests for Linux. --------- Co-authored-by: Hong Chen <hong.chen-1@nasa.gov>
159 lines
6.1 KiB
C++
159 lines
6.1 KiB
C++
/*
|
|
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 <iostream>
|
|
#include <sys/resource.h>
|
|
|
|
#include "trick/Executive.hh"
|
|
#include "trick/ExecutiveException.hh"
|
|
#include "trick/message_proto.h"
|
|
#include "trick/message_type.h"
|
|
#include "trick/release.h"
|
|
#include "trick/SysThread.hh"
|
|
#include "trick/VariableServer.hh"
|
|
extern Trick::VariableServer * the_vs ;
|
|
|
|
/**
|
|
@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 user_cpu_time, kernal_cpu_time;
|
|
double sim_to_cpu;
|
|
unsigned int ii;
|
|
int process_id = 0 ;
|
|
struct rusage cpu_usage_buf ;
|
|
double sim_mem;
|
|
long v_context_switch_run, iv_context_switch_run;
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Stop new connections to the Variable Server. */
|
|
the_vs->shutdownConnections();
|
|
|
|
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() ;
|
|
}
|
|
}
|
|
} catch (Trick::ExecutiveException & ex ) {
|
|
/* Handle exception type Trick::ExecutiveException. Set the file name and error message.
|
|
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 ;
|
|
}
|
|
|
|
Trick::SysThread::ensureAllShutdown();
|
|
|
|
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);
|
|
|
|
/* Get memory usage in MB for the calling process. Note that ru_maxrss returns long value in bytes on Mac and kilobytes on Linux. */
|
|
#if __APPLE__
|
|
sim_mem = (double)cpu_usage_buf.ru_maxrss / (1024 * 1024);
|
|
#else
|
|
sim_mem = (double)cpu_usage_buf.ru_maxrss / 1024;
|
|
#endif
|
|
|
|
/* Calculate simulation elapsed sim time and actual cpu time */
|
|
sim_elapsed_time = get_sim_time() - sim_start;
|
|
user_cpu_time = cpu_time - user_cpu_start;
|
|
|
|
/* */
|
|
cpu_time = ((double) cpu_usage_buf.ru_stime.tv_sec) + ((double) cpu_usage_buf.ru_stime.tv_usec / 1000000.0);
|
|
kernal_cpu_time = cpu_time - kernal_cpu_start;
|
|
|
|
if ((user_cpu_time + kernal_cpu_time) <= 1e-6) {
|
|
sim_to_cpu = 1e8;
|
|
} else {
|
|
sim_to_cpu = sim_elapsed_time / (user_cpu_time + kernal_cpu_time);
|
|
}
|
|
|
|
/* Calculate voluntary and involuntary context switch usage during run */
|
|
v_context_switch_run = cpu_usage_buf.ru_nvcsw - v_context_switch_init ;
|
|
iv_context_switch_run = cpu_usage_buf.ru_nivcsw - iv_context_switch_init ;
|
|
|
|
/* 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"
|
|
" USER CPU TIME USED: %12.3f\n"
|
|
" SYSTEM CPU TIME USED: %12.3f\n"
|
|
" SIMULATION / CPU TIME: %12.3f\n"
|
|
" INITIALIZATION USER CPU TIME: %12.3f\n"
|
|
" INITIALIZATION SYSTEM CPU TIME: %12.3f\n"
|
|
" SIMULATION RAM USAGE: %12.3fMB\n"
|
|
" (External program RAM usage not included!)\n"
|
|
" VOLUNTARY CONTEXT SWITCHES (INIT): %12ld\n"
|
|
"INVOLUNTARY CONTEXT SWITCHES (INIT): %12ld\n"
|
|
" VOLUNTARY CONTEXT SWITCHES (RUN): %12ld\n"
|
|
" INVOLUNTARY CONTEXT SWITCHES (RUN): %12ld\n\n",
|
|
process_id, except_file.c_str(), except_message.c_str(),
|
|
sim_start, get_sim_time(), sim_elapsed_time,
|
|
user_cpu_time, kernal_cpu_time, sim_to_cpu,
|
|
user_cpu_init, kernal_cpu_init, sim_mem,
|
|
v_context_switch_init, iv_context_switch_init,
|
|
v_context_switch_run, iv_context_switch_run) ;
|
|
|
|
/* 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) ;
|
|
|
|
}
|