mirror of
https://github.com/nasa/trick.git
synced 2024-12-18 20:57:55 +00:00
Handle thread shutdown gracefully and test (#1448)
--------- Co-authored-by: Dan Jordan <daniel.d.jordan@nasa.gov>
This commit is contained in:
parent
930dfbc683
commit
9c7becb4ff
@ -13,7 +13,7 @@ PROGRAMMERS:
|
|||||||
|
|
||||||
#include "trick/Scheduler.hh"
|
#include "trick/Scheduler.hh"
|
||||||
#include "trick/DataRecordGroup.hh"
|
#include "trick/DataRecordGroup.hh"
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
|
|
||||||
namespace Trick {
|
namespace Trick {
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ namespace Trick {
|
|||||||
bool cancelled;
|
bool cancelled;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
class DRDWriterThread : public Trick::ThreadBase {
|
class DRDWriterThread : public Trick::SysThread {
|
||||||
public:
|
public:
|
||||||
DRDWriterThread(Trick::DRDMutexes & in_mutexes, std::vector <Trick::DataRecordGroup *> & in_groups) ;
|
DRDWriterThread(Trick::DRDMutexes & in_mutexes, std::vector <Trick::DataRecordGroup *> & in_groups) ;
|
||||||
|
|
||||||
|
@ -7,14 +7,14 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "trick/MessageSubscriber.hh"
|
#include "trick/MessageSubscriber.hh"
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
#include "trick/tc.h"
|
#include "trick/tc.h"
|
||||||
|
|
||||||
namespace Trick {
|
namespace Trick {
|
||||||
|
|
||||||
class MessageTCDevice ;
|
class MessageTCDevice ;
|
||||||
|
|
||||||
class MessageTCDeviceListenThread : public Trick::ThreadBase {
|
class MessageTCDeviceListenThread : public Trick::SysThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MessageTCDeviceListenThread(MessageTCDevice * in_mtcd) ;
|
MessageTCDeviceListenThread(MessageTCDevice * in_mtcd) ;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#define MESSAGETHREADEDCOUT_HH
|
#define MESSAGETHREADEDCOUT_HH
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
#include "trick/MessageSubscriber.hh"
|
#include "trick/MessageSubscriber.hh"
|
||||||
|
|
||||||
namespace Trick {
|
namespace Trick {
|
||||||
@ -16,7 +16,7 @@ namespace Trick {
|
|||||||
* This MessageThreadedCout is a class that inherits from MessageSubscriber.
|
* This MessageThreadedCout is a class that inherits from MessageSubscriber.
|
||||||
* It defines a type of MessageSubscriber with its received message sending to the standard output stream.
|
* It defines a type of MessageSubscriber with its received message sending to the standard output stream.
|
||||||
*/
|
*/
|
||||||
class MessageThreadedCout : public MessageSubscriber , public Trick::ThreadBase {
|
class MessageThreadedCout : public MessageSubscriber , public Trick::SysThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
56
include/trick/SysThread.hh
Normal file
56
include/trick/SysThread.hh
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
PURPOSE:
|
||||||
|
(Trick Sys Threads implementation)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SYSTHREAD_HH
|
||||||
|
#define SYSTHREAD_HH
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#if __linux
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include "trick/ThreadBase.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Trick {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purpose of this class is to ensure safe shutdown for Trick system threads, since user threads are handled separately in
|
||||||
|
* the Trick::Threads and Executive classes.
|
||||||
|
*
|
||||||
|
* This class was implemented as a solution to issue https://github.com/nasa/trick/issues/1445
|
||||||
|
*
|
||||||
|
* @author Jackie Deans
|
||||||
|
*
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
class SysThread : public Trick::ThreadBase {
|
||||||
|
public:
|
||||||
|
SysThread(std::string in_name, bool self_deleting = false);
|
||||||
|
~SysThread();
|
||||||
|
|
||||||
|
static int ensureAllShutdown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Had to use Construct On First Use here to avoid the static initialziation fiasco
|
||||||
|
static pthread_mutex_t& list_mutex();
|
||||||
|
static pthread_cond_t& list_empty_cv();
|
||||||
|
|
||||||
|
static std::vector <SysThread *>& all_sys_threads();
|
||||||
|
|
||||||
|
static bool shutdown_finished;
|
||||||
|
|
||||||
|
bool self_deleting;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -130,6 +130,12 @@ namespace Trick {
|
|||||||
*/
|
*/
|
||||||
virtual int cancel_thread() ;
|
virtual int cancel_thread() ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels thread.
|
||||||
|
* @return always 0
|
||||||
|
*/
|
||||||
|
virtual int join_thread() ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The thread body.
|
* The thread body.
|
||||||
* @return always 0
|
* @return always 0
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include "trick/variable_server_sync_types.h"
|
#include "trick/variable_server_sync_types.h"
|
||||||
#include "trick/VariableServerThread.hh"
|
#include "trick/VariableServerThread.hh"
|
||||||
#include "trick/VariableServerListenThread.hh"
|
#include "trick/VariableServerListenThread.hh"
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
|
|
||||||
namespace Trick {
|
namespace Trick {
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "trick/tc.h"
|
#include "trick/tc.h"
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
|
|
||||||
namespace Trick {
|
namespace Trick {
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace Trick {
|
|||||||
This class runs the variable server listen loop.
|
This class runs the variable server listen loop.
|
||||||
@author Alex Lin
|
@author Alex Lin
|
||||||
*/
|
*/
|
||||||
class VariableServerListenThread : public Trick::ThreadBase {
|
class VariableServerListenThread : public Trick::SysThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VariableServerListenThread() ;
|
VariableServerListenThread() ;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "trick/tc.h"
|
#include "trick/tc.h"
|
||||||
#include "trick/ThreadBase.hh"
|
#include "trick/SysThread.hh"
|
||||||
#include "trick/VariableServerReference.hh"
|
#include "trick/VariableServerReference.hh"
|
||||||
#include "trick/variable_server_sync_types.h"
|
#include "trick/variable_server_sync_types.h"
|
||||||
#include "trick/variable_server_message_types.h"
|
#include "trick/variable_server_message_types.h"
|
||||||
@ -25,7 +25,7 @@ namespace Trick {
|
|||||||
This class provides variable server command processing on a separate thread for each client.
|
This class provides variable server command processing on a separate thread for each client.
|
||||||
@author Alex Lin
|
@author Alex Lin
|
||||||
*/
|
*/
|
||||||
class VariableServerThread : public Trick::ThreadBase {
|
class VariableServerThread : public Trick::SysThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ConnectionType { TCP, UDP, MCAST } ;
|
enum ConnectionType { TCP, UDP, MCAST } ;
|
||||||
|
1
test/SIM_earlyterm/RUN_test/input.py
Normal file
1
test/SIM_earlyterm/RUN_test/input.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
#Nothing
|
31
test/SIM_earlyterm/S_define
Normal file
31
test/SIM_earlyterm/S_define
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
PURPOSE: Provide test of simulation early termination. Ensures threads
|
||||||
|
come down appropriately for unit-test-like cases
|
||||||
|
PROGRAMMERS:
|
||||||
|
(((Dan Jordan) (NASA) (Jan 2023) (Deal with it)))
|
||||||
|
*****************************************************************************/
|
||||||
|
#include "sim_objects/default_trick_sys.sm"
|
||||||
|
##include "trick/exec_proto.h"
|
||||||
|
|
||||||
|
class EarlyTerminationSimObject : public Trick::SimObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
double x;
|
||||||
|
|
||||||
|
EarlyTerminationSimObject()
|
||||||
|
:
|
||||||
|
x(0)
|
||||||
|
{
|
||||||
|
("initialization") early_term();
|
||||||
|
};
|
||||||
|
|
||||||
|
void early_term() {
|
||||||
|
std::string message = "Terminating with exit code 0";
|
||||||
|
exec_terminate_with_return(0, "S_define", 24, message.c_str());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
EarlyTerminationSimObject( const EarlyTerminationSimObject&);
|
||||||
|
EarlyTerminationSimObject & operator= ( const EarlyTerminationSimObject&);
|
||||||
|
|
||||||
|
};
|
||||||
|
EarlyTerminationSimObject test;
|
@ -189,6 +189,13 @@ SIM_sun:
|
|||||||
runs:
|
runs:
|
||||||
RUN_test/unit_test.py:
|
RUN_test/unit_test.py:
|
||||||
returns: 0
|
returns: 0
|
||||||
|
SIM_earlyterm:
|
||||||
|
path: test/SIM_earlyterm
|
||||||
|
build_command: "trick-CP -t"
|
||||||
|
binary: "T_main_{cpu}_test.exe"
|
||||||
|
runs:
|
||||||
|
RUN_test/input.py:
|
||||||
|
returns: 0
|
||||||
|
|
||||||
# Special cases
|
# Special cases
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ Trick::DRDMutexes::DRDMutexes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Trick::DRDWriterThread::DRDWriterThread(DRDMutexes & in_mutexes, std::vector <Trick::DataRecordGroup *> & in_groups) :
|
Trick::DRDWriterThread::DRDWriterThread(DRDMutexes & in_mutexes, std::vector <Trick::DataRecordGroup *> & in_groups) :
|
||||||
ThreadBase("DR_Writer"),
|
SysThread("DR_Writer"),
|
||||||
drd_mutexes(in_mutexes) ,
|
drd_mutexes(in_mutexes) ,
|
||||||
groups(in_groups) {}
|
groups(in_groups) {}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "trick/message_proto.h"
|
#include "trick/message_proto.h"
|
||||||
#include "trick/message_type.h"
|
#include "trick/message_type.h"
|
||||||
#include "trick/release.h"
|
#include "trick/release.h"
|
||||||
|
#include "trick/SysThread.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@design
|
@design
|
||||||
@ -75,6 +76,8 @@ int Trick::Executive::shutdown() {
|
|||||||
except_message += std::string(" then exception Message: ") + ex.message ;
|
except_message += std::string(" then exception Message: ") + ex.message ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Trick::SysThread::ensureAllShutdown();
|
||||||
|
|
||||||
getrusage(RUSAGE_SELF, &cpu_usage_buf);
|
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);
|
cpu_time = ((double) cpu_usage_buf.ru_utime.tv_sec) + ((double) cpu_usage_buf.ru_utime.tv_usec / 1000000.0);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "trick/tc_proto.h"
|
#include "trick/tc_proto.h"
|
||||||
|
|
||||||
Trick::MessageTCDeviceListenThread::MessageTCDeviceListenThread(MessageTCDevice * in_mtcd) :
|
Trick::MessageTCDeviceListenThread::MessageTCDeviceListenThread(MessageTCDevice * in_mtcd) :
|
||||||
Trick::ThreadBase("MessageListen"),
|
Trick::SysThread("MessageListen"),
|
||||||
mtcd(in_mtcd) ,
|
mtcd(in_mtcd) ,
|
||||||
listen_dev() {
|
listen_dev() {
|
||||||
/* And a TCDevice for message server @e listen_device is configured. */
|
/* And a TCDevice for message server @e listen_device is configured. */
|
||||||
@ -25,6 +25,7 @@ Trick::MessageTCDeviceListenThread::MessageTCDeviceListenThread(MessageTCDevice
|
|||||||
|
|
||||||
Trick::MessageTCDeviceListenThread::~MessageTCDeviceListenThread() {
|
Trick::MessageTCDeviceListenThread::~MessageTCDeviceListenThread() {
|
||||||
free(listen_dev.error_handler) ;
|
free(listen_dev.error_handler) ;
|
||||||
|
listen_dev.error_handler = NULL;
|
||||||
if ( listen_dev.hostname ) {
|
if ( listen_dev.hostname ) {
|
||||||
free((char*)listen_dev.hostname) ;
|
free((char*)listen_dev.hostname) ;
|
||||||
}
|
}
|
||||||
@ -81,7 +82,7 @@ void * Trick::MessageTCDeviceListenThread::thread_body() {
|
|||||||
|
|
||||||
if (status == TC_SUCCESS) {
|
if (status == TC_SUCCESS) {
|
||||||
mtcd->add_connection(new_connection) ;
|
mtcd->add_connection(new_connection) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ Trick::MessageThreadedCout::MessageThreadedCout() :
|
|||||||
max_buffer_size(4000) ,
|
max_buffer_size(4000) ,
|
||||||
print_immediate(false) ,
|
print_immediate(false) ,
|
||||||
copy_ptr(NULL),
|
copy_ptr(NULL),
|
||||||
write_ptr(NULL) {
|
write_ptr(NULL),
|
||||||
|
SysThread("threadedcout") {
|
||||||
/** By default, this subscriber is enabled when it is created. */
|
/** By default, this subscriber is enabled when it is created. */
|
||||||
Trick::MessageSubscriber::name = "threadedcout" ;
|
Trick::MessageSubscriber::name = "threadedcout" ;
|
||||||
Trick::ThreadBase::name = "threadedcout" ;
|
|
||||||
color_code.reserve(6) ;
|
color_code.reserve(6) ;
|
||||||
StringNode * temp = new StringNode(max_buffer_size) ;
|
StringNode * temp = new StringNode(max_buffer_size) ;
|
||||||
write_ptr = copy_ptr = temp ;
|
write_ptr = copy_ptr = temp ;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
include $(dir $(lastword $(MAKEFILE_LIST)))../../../share/trick/makefiles/Makefile.common
|
include $(dir $(lastword $(MAKEFILE_LIST)))../../../share/trick/makefiles/Makefile.common
|
||||||
include ${TRICK_HOME}/share/trick/makefiles/Makefile.tricklib
|
include ${TRICK_HOME}/share/trick/makefiles/Makefile.tricklib
|
||||||
-include Makefile_deps
|
-include Makefile_deps
|
||||||
|
TRICK_CXXFLAGS += -std=c++11
|
77
trick_source/sim_services/ThreadBase/SysThread.cpp
Normal file
77
trick_source/sim_services/ThreadBase/SysThread.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#if __linux
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#endif
|
||||||
|
#include <signal.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "trick/SysThread.hh"
|
||||||
|
|
||||||
|
bool Trick::SysThread::shutdown_finished = false;
|
||||||
|
|
||||||
|
// Construct On First Use to avoid the Static Initialization Fiasco
|
||||||
|
pthread_mutex_t& Trick::SysThread::list_mutex() {
|
||||||
|
static pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
return list_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cond_t& Trick::SysThread::list_empty_cv() {
|
||||||
|
static pthread_cond_t list_empty_cv = PTHREAD_COND_INITIALIZER;
|
||||||
|
return list_empty_cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Trick::SysThread *>& Trick::SysThread::all_sys_threads() {
|
||||||
|
static std::vector<SysThread *> all_sys_threads;
|
||||||
|
return all_sys_threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trick::SysThread::SysThread(std::string in_name, bool sd) : self_deleting(sd), ThreadBase(in_name) {
|
||||||
|
pthread_mutex_lock(&(list_mutex()));
|
||||||
|
all_sys_threads().push_back(this);
|
||||||
|
pthread_mutex_unlock(&(list_mutex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Trick::SysThread::~SysThread() {
|
||||||
|
pthread_mutex_lock(&(list_mutex()));
|
||||||
|
if (!shutdown_finished) {
|
||||||
|
all_sys_threads().erase(std::remove(all_sys_threads().begin(), all_sys_threads().end(), this), all_sys_threads().end());
|
||||||
|
if (all_sys_threads().size() == 0) {
|
||||||
|
pthread_cond_signal(&(list_empty_cv()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&(list_mutex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Trick::SysThread::ensureAllShutdown() {
|
||||||
|
pthread_mutex_lock(&(list_mutex()));
|
||||||
|
|
||||||
|
for (SysThread * thread : all_sys_threads()) {
|
||||||
|
thread->cancel_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = all_sys_threads().begin();
|
||||||
|
while (it != all_sys_threads().end()){
|
||||||
|
SysThread * thread = *it;
|
||||||
|
if (!(thread->self_deleting)) {
|
||||||
|
thread->join_thread();
|
||||||
|
it = all_sys_threads().erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (all_sys_threads().size() != 0) {
|
||||||
|
pthread_cond_wait(&(list_empty_cv()), &(list_mutex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown_finished = true;
|
||||||
|
pthread_mutex_unlock(&(list_mutex()));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -300,6 +300,13 @@ int Trick::ThreadBase::cancel_thread() {
|
|||||||
return(0) ;
|
return(0) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Trick::ThreadBase::join_thread() {
|
||||||
|
if ( pthread_id != 0 ) {
|
||||||
|
pthread_join(pthread_id, NULL) ;
|
||||||
|
}
|
||||||
|
return(0) ;
|
||||||
|
}
|
||||||
|
|
||||||
void * Trick::ThreadBase::thread_helper( void * context ) {
|
void * Trick::ThreadBase::thread_helper( void * context ) {
|
||||||
|
|
||||||
sigset_t sigs;
|
sigset_t sigs;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "trick/message_type.h"
|
#include "trick/message_type.h"
|
||||||
|
|
||||||
Trick::VariableServerListenThread::VariableServerListenThread() :
|
Trick::VariableServerListenThread::VariableServerListenThread() :
|
||||||
Trick::ThreadBase("VarServListen"),
|
Trick::SysThread("VarServListen"),
|
||||||
port(0),
|
port(0),
|
||||||
user_port_requested(false),
|
user_port_requested(false),
|
||||||
broadcast(true),
|
broadcast(true),
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
Trick::VariableServer * Trick::VariableServerThread::vs = NULL ;
|
Trick::VariableServer * Trick::VariableServerThread::vs = NULL ;
|
||||||
|
|
||||||
Trick::VariableServerThread::VariableServerThread(TCDevice * in_listen_dev) :
|
Trick::VariableServerThread::VariableServerThread(TCDevice * in_listen_dev) :
|
||||||
Trick::ThreadBase("VarServer") ,
|
Trick::SysThread("VarServer", true) ,
|
||||||
listen_dev(in_listen_dev) {
|
listen_dev(in_listen_dev) {
|
||||||
|
|
||||||
debug = 0 ;
|
debug = 0 ;
|
||||||
|
@ -42,8 +42,11 @@ ${LIBDIR}:
|
|||||||
${TRICK_LIB}: ${LIBDIR}/${LIBNAME}
|
${TRICK_LIB}: ${LIBDIR}/${LIBNAME}
|
||||||
cp ${LIBDIR}/${LIBNAME} $(TRICK_LIB)
|
cp ${LIBDIR}/${LIBNAME} $(TRICK_LIB)
|
||||||
|
|
||||||
|
real_clean: clean
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
${RM} -r ${OBJDIR}
|
${RM} -rf ${OBJDIR}
|
||||||
|
${RM} -rf ${LIBDIR}
|
||||||
${MAKE} -C test clean
|
${MAKE} -C test clean
|
||||||
|
|
||||||
spotless:
|
spotless:
|
||||||
|
Loading…
Reference in New Issue
Block a user