• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / trick / 25456501308

06 May 2026 07:29PM UTC coverage: 55.935% (-0.8%) from 56.7%
25456501308

Pull #2011

github

web-flow
Merge 7ad262960 into 7054e405e
Pull Request #2011: Single-file CI and code style adoption

14612 of 26123 relevant lines covered (55.94%)

462107.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

19.4
/trick_source/sim_services/MasterSlave/Slave.cpp
1
/*
2
   PURPOSE: (Slave for master/slave synchronization)
3
 */
4

5
#include <iostream>
6
#include <iomanip> // for setprecision
7
#include <sstream>
8
#include <dlfcn.h>
9
#include <stdlib.h> // for getenv
10
#include <cstring>
11

12
#include "trick/Slave.hh"
13
#include "trick/exec_proto.h"
14
#include "trick/message_proto.h"
15
#include "trick/message_type.h"
16
#include "trick/CheckPointRestart_c_intf.hh" // for checkpoint
17
#include "trick/command_line_protos.h" // output dir get/set
18

19
Trick::Slave::Slave() {
183✔
20
    enabled = false ;
183✔
21
    reconnected = false ;
183✔
22
    activated = false;
183✔
23
    msg_published = false;
183✔
24
    sent_reconnect_cmd = false;
183✔
25
}
183✔
26

27
int Trick::Slave::set_connection_type(Trick::MSConnect * in_connection) {
×
28
    connection = in_connection ;
×
29
    return 0 ;
×
30
}
31

32
int Trick::Slave::process_sim_args() {
180✔
33
    /** @par Detailed Design */
34
    if ( connection != NULL ) {
180✔
35
        /** @li the return_value of Trick::MSConnect::process_sim_args() sets the enabled flag for the slave. */
36
        enabled = connection->process_sim_args() ;
×
37
    }
38

39
    return(0) ;
180✔
40
}
41

42
int Trick::Slave::init() {
180✔
43

44
    std::string rts_disable_name ;
180✔
45
    std::string ms_master_disable_name ;
180✔
46
    void* dlhandle ;
47
    int (*rts_disable)(void) = NULL ;
180✔
48
    int (*ms_master_disable)(void) = NULL ;
180✔
49
    long long software_frame_tics ;
50
    long long sync_wait_limit_tics ;
51
    int chkpnt_flag;
52

53
    /** @par Detailed Design */
54

55
    if ( enabled ) {
180✔
56

57
        /** @li Connect to the master by calling Trick::MSConnect::connect() */
58
        connection->connect() ;
×
59

60
        dlhandle = dlopen( NULL, RTLD_LAZY) ;
×
61

62
        /** @li Turn off RealtimeSync if it exists.  We are not assuming that the function even
63
                exists.  Search for the routine and execute it if it exists */
64
        rts_disable_name = "real_time_disable" ;
×
65
        rts_disable = (int (*)(void))dlsym( dlhandle , rts_disable_name.c_str()) ;
×
66
        if ( rts_disable != NULL ) {
×
67
            message_publish(MSG_INFO , "Slave synchronization starting.  Turning realtime synchronization off.\n") ;
×
68
            (*rts_disable)() ;
×
69
        }
70

71
        /** @li Turn off Master synchronization if it exists.  We are not assuming that the function even
72
                exists.  Search for the routine and execute it if it exists */
73
        ms_master_disable_name = "ms_master_disable" ;
×
74
        ms_master_disable = (int (*)(void))dlsym( dlhandle , ms_master_disable_name.c_str()) ;
×
75
        if ( ms_master_disable != NULL ) {
×
76
            message_publish(MSG_INFO , "Slave synchronization starting.  Turning master off.\n") ;
×
77
            (*ms_master_disable)() ;
×
78
        }
79

80
        /** @li Read and set the slave software frame and time tic value according to the master. */
81
        software_frame_tics = connection->read_time() ;
×
82
        exec_set_time_tic_value (connection->read_time());
×
83
        exec_set_software_frame (double (software_frame_tics) / double(exec_get_time_tic_value()) ) ;
×
84
        /** @li Read and set the sync_wait_limit according to the master. */
85
        sync_wait_limit_tics = connection->read_time() ;
×
86
        sync_wait_limit = double (sync_wait_limit_tics) / double(exec_get_time_tic_value()) ;
×
87
        connection->set_sync_wait_limit(sync_wait_limit) ;
×
88

89
        /** @li  Read the initial freeze command from the master. */
90
        exec_set_freeze_command(int(connection->read_command())) ;
×
91
        /** @li Read and set the pre_init, post_init, and end checkpoint flags according to the master. */
92
        chkpnt_flag = (int)connection->read_time();
×
93
        checkpoint_pre_init(chkpnt_flag>>2 & 0x1);
×
94
        checkpoint_post_init(chkpnt_flag>>1 & 0x1);
×
95
        checkpoint_end(chkpnt_flag & 0x1);
×
96

97
        dlclose(dlhandle) ;
×
98

99
        // Executive freezes are only allowed on freeze frame boundaries in Master/Slave
100
        exec_set_freeze_on_frame_boundary(true) ;
×
101

102
        activated = true;
×
103
    }
104

105
    return(0) ;
180✔
106
}
180✔
107

108
std::string Trick::Slave::get_checkpoint_name(MS_SIM_COMMAND command) {
×
109

110
    std::string dir;
×
111
    std::stringstream file_name_stream ;
×
112
    /** @par Detailed Design */
113
    /** @li Read the checkpoint name from master, it's in the form "dir/filename" */
114
    connection->read_name(chkpnt_name, sizeof(chkpnt_name)); // dir/filename
×
115
    /** @li Return the appropriate checkpoint name to use for given dump/load command */
116
    // ascii checkpoint() only wants a filename -- no dir path
117
    if (command == MS_ChkpntDumpAsciiCmd) {
×
118
        if (chkpnt_name[0] != MS_ERROR_NAME) {
×
119
            file_name_stream << strrchr(chkpnt_name, '/')+1; // filename only
×
120
            //std::cout << "----> Slave: parsed checkpoint file name: " << file_name_stream.str() << std::endl;
121
        } else { // create default name
122
            file_name_stream << "chkpnt_" << std::fixed << std::setprecision(2) << exec_get_sim_time() ;
×
123
        }
124
    }
125
    // ascii load_checkpoint() wants the dir/filename path
126
    if (command == MS_ChkpntLoadAsciiCmd) {
×
127
        dir = command_line_args_get_output_dir(); // run dir
×
128
        if (chkpnt_name[0] != MS_ERROR_NAME) {
×
129
            file_name_stream << dir << std::string(strrchr(chkpnt_name, '/')); // my run dir / filename
×
130
        } else { // create default name
131
            file_name_stream << dir << "/chkpnt_" << std::fixed << std::setprecision(2) << exec_get_sim_time() ;
×
132
        }
133
    }
134

135
    return(file_name_stream.str()) ;
×
136
}
×
137

138
int Trick::Slave::end_of_frame() {
3,685✔
139

140
    long long master_time ;
141
    MS_SIM_COMMAND command ;
142
    MS_SIM_COMMAND slave_command ;
143
    std::string chkpt_name_str;
3,685✔
144

145
    /** @par Detailed Design */
146
    if ( (enabled) and (activated) ){
3,685✔
147

148
        /** @li write the current slave exec_command to the master */
149
        slave_command = (MS_SIM_COMMAND)exec_get_exec_command();
×
150

151
        // send a special command so master knows to print a "we reconnected" message
152
        if (reconnected) {
×
153
            slave_command = MS_ReconnectCmd;
×
154

155
            if (msg_published)
×
156
                reconnected = false;
×
157
            else
158
                sent_reconnect_cmd = true;
×
159
        }
160

161
        //printf("DEBUG slave write %d command to master\n", slave_command); fflush(stdout);
162
        connection->write_command(slave_command) ;
×
163

164
        /** @li read the simulation time according to the master */
165
        master_time = connection->read_time() ;
×
166

167
        if ( master_time == MS_ERROR_TIME ) {
×
168

169
            if ( sync_error_terminate == true ) {
×
170
                /** @li if reading the master time returned an error exit the sim if sync_error_terminate == true */
171
                message_publish(MSG_ERROR , "Slave lost sync with master. sync_error_terminate is true: Slave is terminating.\n") ;
×
172
                exec_terminate_with_return(-1, __FILE__, __LINE__ , "Slave lost sync with master") ;
×
173
            }
174
            else {
175
                if (slave_command != MS_FreezeCmd){
×
176
                    /** @li if reading the master time returned an error freeze the sim if sync_error_terminate == false */
177
                    activated = false;
×
178
                    message_publish(MSG_ERROR , "Slave lost sync with master. sync_error_terminate is false: Slave is entering Freeze mode.\n") ;
×
179
                    exec_set_exec_command(FreezeCmd) ;
×
180
                    connection->write_command(MS_FreezeCmd) ;
×
181
                    return(0);
×
182
                }
183
            }
184
        }
185

186
        /** @li read the master mode command */
187
        command = connection->read_command() ;
×
188
        //printf("DEBUG slave read %d command from master\n", command); fflush(stdout);
189

190
        switch ( command ) {
×
191
            case (MS_ErrorCmd):
×
192
                if ( sync_error_terminate == true ) {
×
193
                    /** @li if reading the master mode command returned an error exit the sim if sync_error_terminate == true */
194
                    message_publish(MSG_ERROR , "Slave lost sync with master. sync_error_terminate is true: Slave is terminating.\n") ;
×
195
                    exec_terminate_with_return(-1, __FILE__, __LINE__ , "Slave lost sync with master") ;
×
196
                }
197
                else {
198
                    if (slave_command != MS_FreezeCmd) {
×
199
                        /** @li if reading the master mode command returned an error freeze the sim if sync_error_terminate == false */
200
                        activated = false;
×
201
                        message_publish(MSG_ERROR , "Slave lost sync with master. sync_error_terminate is false: Slave is entering Freeze mode.\n") ;
×
202
                        exec_set_exec_command(FreezeCmd) ;
×
203
                        connection->write_command(MS_FreezeCmd) ;
×
204
                        return(0);
×
205
                    }
206
                }
207
                break;
×
208
            /** @li if reading the master mode command returned a checkpoint dump command, dump a checkpoint */
209
            case (MS_ChkpntDumpAsciiCmd):   // Master tells slave to dump an ascii checkpoint
×
210
                message_publish(MSG_WARNING , "Slave received Checkpoint Dump command from master.\n") ;
×
211
                chkpt_name_str = get_checkpoint_name(MS_ChkpntDumpAsciiCmd);
×
212
                checkpoint(chkpt_name_str.c_str());
×
213
                break;
×
214
            /** @li if reading the master mode command returned a checkpoint load command, load a checkpoint */
215
            case (MS_ChkpntLoadAsciiCmd):  // Master tells slave to load an ascii checkpoint
×
216
                message_publish(MSG_WARNING , "Slave received Checkpoint Load command from master.\n") ;
×
217
                chkpt_name_str = get_checkpoint_name(MS_ChkpntLoadAsciiCmd);
×
218
                load_checkpoint(chkpt_name_str.c_str()); // load done in freeze or end_of_frame job
×
219
                //load_checkpoint_job(); // do the load NOW
220
                break;
×
221
            default:
×
222
                /** @li if reading the master mode command returned an Executive mode, set the slave mode command to the master mode command */
223
                exec_set_exec_command((SIM_COMMAND)command) ;
×
224
                if (reconnected) {
×
225
                    message_publish(MSG_INFO , "Slave has reconnected to master.\n") ;
×
226
                    if (sent_reconnect_cmd)
×
227
                        reconnected = false;
×
228
                    else
229
                        msg_published = true;
×
230
                }
231
                break;
×
232
        }
233
    }
234

235
    return(0) ;
3,685✔
236
}
3,685✔
237

238
int Trick::Slave::freeze_init() {
×
239
    /** @par Detailed Design */
240
    if ( enabled ) {
×
241
        /** @li Set the connection sync_wait_limit to infinite upon entering freeze */
242
        connection->set_sync_wait_limit(-1.0) ;
×
243
    }
244
    return(0) ;
×
245
}
246

247
int Trick::Slave::freeze() {
×
248
    /** @par Detailed Design */
249
    /** @li Call Trick::Slave::end_of_frame() */
250

251
    if ( enabled ) {
×
252
        exec_set_exec_command(NoCmd) ; // so master won't keep reading freeze command during freeze
×
253
        end_of_frame() ;
×
254
    }
255
    return(0) ;
×
256
}
257

258
int Trick::Slave::unfreeze() {
×
259
    /** @par Detailed Design */
260
    if ( enabled ) {
×
261
        /** @li Set the connection sync_wait_limit to the default upon exiting freeze */
262
        connection->set_sync_wait_limit(sync_wait_limit) ;
×
263
    }
264
    return(0) ;
×
265
}
266

267
int Trick::Slave::shutdown() {
150✔
268
    /** @par Detailed Design */
269
    if ( enabled ) {
150✔
270
        /** @li write the exit mode command to the master when the slave is shutting down */
271
        connection->write_command(MS_ExitCmd) ;
×
272
    }
273
    return(0) ;
150✔
274
}
275

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc