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

nasa / trick / 16994562866

15 Aug 2025 04:35PM UTC coverage: 55.684%. First build
16994562866

Pull #1942

github

web-flow
Merge 4e96373b1 into 2cbd20f00
Pull Request #1942: Adding additional updates to PR#1847

4 of 81 new or added lines in 2 files covered. (4.94%)

12349 of 22177 relevant lines covered (55.68%)

257949.62 hits per line

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

45.32
/trick_source/sim_services/DataRecord/DataRecordDispatcher.cpp
1
/*
2
   PURPOSE: (Copy data out of structures into data recording memory.)
3
   PROGRAMMERS:
4
     (((Robert W. Bailey) (LinCom Corp) (3/96) (SES upgrades))
5
      ((Alex Lin) (NASA) (6/02) (DR_changes upgrade)))
6
 */
7

8
#include <iostream>
9
#include <sstream>
10
#include <stdlib.h>
11
#include <unistd.h>
12
#include <algorithm>
13

14
#include <signal.h>
15
#if __linux__
16
#include <sys/syscall.h>
17
#endif
18

19
#include "trick/DataRecordDispatcher.hh"
20
#include "trick/exec_proto.h"
21
#include "trick/exec_proto.hh"
22
#include "trick/message_proto.h"
23
#include "trick/message_type.h"
24
#include "trick/command_line_protos.h"
25

26
Trick::DataRecordDispatcher * the_drd = NULL ;
27

28
Trick::DRDMutexes::DRDMutexes() {
182✔
29
    pthread_cond_init(&dr_go_cv, NULL);
182✔
30
    pthread_mutex_init(&dr_go_mutex, NULL);
182✔
31
    pthread_cond_init(&init_complete_cv, NULL);
182✔
32
    pthread_mutex_init(&init_complete_mutex, NULL);
182✔
33
    cancelled = false;
182✔
34
}
182✔
35

36
Trick::DRDWriterThread::DRDWriterThread(DRDMutexes & in_mutexes, std::vector <Trick::DataRecordGroup *> & in_groups) :
182✔
37
 SysThread("DR_Writer"),
38
 drd_mutexes(in_mutexes) ,
39
 groups(in_groups) {}
182✔
40

41
void * Trick::DRDWriterThread::thread_body() {
150✔
42
    pthread_mutex_lock(&(drd_mutexes.dr_go_mutex));
150✔
43

44
    /* tell the main thread that the writer is ready to go */
45
    pthread_mutex_lock(&(drd_mutexes.init_complete_mutex));
150✔
46
    pthread_cond_signal(&(drd_mutexes.init_complete_cv));
150✔
47
    pthread_mutex_unlock(&(drd_mutexes.init_complete_mutex));
150✔
48

49
    /* from now until death, wait for the condition variable,
50
       then call the write_data method for all of the groups */
51
    while(1) {
52
        pthread_cond_wait(&(drd_mutexes.dr_go_cv), &(drd_mutexes.dr_go_mutex));
47,441✔
53
        if (drd_mutexes.cancelled) {
47,441✔
54
            pthread_mutex_unlock(&(drd_mutexes.dr_go_mutex));
150✔
55
            pthread_exit(0);
150✔
56
        }
57
        for ( unsigned int ii = 0 ; ii < groups.size() ; ii++ ) {
179,160✔
58
            if ( groups[ii]->buffer_type == Trick::DR_Buffer ) {
131,869✔
59
                groups[ii]->write_data(true) ;
45,896✔
60
            }
61
        }
62
    }
47,291✔
63
    pthread_mutex_unlock(&(drd_mutexes.dr_go_mutex));
64
    return NULL ;
65
}
66

67
void Trick::DRDWriterThread::dump( std::ostream & oss ) {
×
68
    oss << "Trick::DRDWriterThread (" << name << ")" << std::endl ;
×
69
    oss << "    number of data record groups = " << groups.size() << std::endl ;
×
70
    Trick::ThreadBase::dump(oss) ;
×
71
}
×
72

73
Trick::DataRecordDispatcher::DataRecordDispatcher()
182✔
74
    : drd_writer_thread(drd_mutexes, groups),
182✔
75
      verify_log_vars(true),
76
      warning_level(1)
182✔
77
{
78
    the_drd = this;
182✔
79
}
182✔
80

81
Trick::DataRecordDispatcher::~DataRecordDispatcher() {
182✔
82
}
182✔
83

84
int Trick::DataRecordDispatcher::remove_files() {
159✔
85

86
    std::string command;
159✔
87
    command = std::string("/bin/rm -rf ") + command_line_args_get_output_dir() + std::string("/log_*") ;
159✔
88
    system(command.c_str());
159✔
89
    return 0 ;
318✔
90
}
91

92
/**
93
@details
94
-# Initialize thread mutex and condition variable
95
-# Create a new thread calling the DataRecordThreaded Writer routine.
96
-# Wait for the data record thread to initialize before continuing.
97
*/
98
int Trick::DataRecordDispatcher::init() {
150✔
99

100
    pthread_mutex_lock(&drd_mutexes.init_complete_mutex);
150✔
101
    drd_writer_thread.create_thread() ;
150✔
102
    pthread_cond_wait(&drd_mutexes.init_complete_cv, &drd_mutexes.init_complete_mutex);
150✔
103
    pthread_mutex_unlock(&drd_mutexes.init_complete_mutex);
150✔
104

105
    return(0) ;
150✔
106
}
107

108
/**
109
add_sim_object is called by the executive when a new sim_object is added to the sim.
110
@details
111
-# Test if the incoming object is a DataRecordGroup.
112
 -# If it is add it to the list of groups we save
113
*/
114
int Trick::DataRecordDispatcher::add_sim_object(Trick::SimObject * in_object ) {
4,392✔
115
    Trick::DataRecordGroup * drg = dynamic_cast< Trick::DataRecordGroup * >(in_object) ;
4,392✔
116
    if ( drg != NULL ) {
4,392✔
117
        groups.push_back(drg) ;
50✔
118
    }
119
    return 0 ;
4,392✔
120
}
121

122
/** @brief set verification check on/off */
NEW
123
void Trick::DataRecordDispatcher::set_verif_onoff(bool state)
×
124
{
NEW
125
    verify_log_vars = state;
×
NEW
126
}
×
127

128
/** @brief set verification warning level */
NEW
129
void Trick::DataRecordDispatcher::set_warning_level(int level)
×
130
{
NEW
131
    warning_level = level;
×
NEW
132
}
×
133

134
/**
135
@details
136
-# Test if the incoming data record group name has been used.
137
 -# If true return an error.
138
-# Set the group buffering type to the incoming type
139
-# Add the group to the executive.
140
*/
141
int Trick::DataRecordDispatcher::add_group(Trick::DataRecordGroup * in_group, Trick::DR_Buffering buffering) {
43✔
142

143
    unsigned int ii ;
144
    for (  ii = 0 ; ii < groups.size() ; ii++ ) {
66✔
145
        if ( !groups[ii]->group_name.compare(in_group->group_name) ) {
23✔
146
            message_publish(MSG_ERROR, "Data Record group with duplicate name %s.\n", in_group->group_name.c_str()) ;
×
147
            return -1 ;
×
148
        }
149
    }
150
    if ( buffering != Trick::DR_Not_Specified ) {
43✔
151
        in_group->set_buffer_type(buffering) ;
42✔
152
    }
153

154
    exec_add_sim_object(in_group , (char *)in_group->name.c_str()) ;
43✔
155

156
    return 0 ;
43✔
157
}
158

159

160
/**
161
@details
162
-# Remove the data recording group from the dispatcher's list of groups
163
-# Remove the group from the executive.
164
*/
165
int Trick::DataRecordDispatcher::remove_group(Trick::DataRecordGroup * in_group) {
27✔
166

167
    std::vector <Trick::DataRecordGroup *>::iterator drg_it ;
27✔
168

169

170
    // remove the group from the dispatcher vector of jobs.
171
    for ( drg_it = groups.begin() ; drg_it != groups.end() ; ) {
48✔
172
        if ( (*drg_it) == in_group ) {
21✔
173
            // erase the group from the dispatcher. Lock the mutex so we aren't in the
174
            // middle of writing data as we delete the group.
175
            pthread_mutex_lock(&drd_mutexes.dr_go_mutex) ;
×
176
            drg_it = groups.erase(drg_it) ;
×
177
            pthread_mutex_unlock(&drd_mutexes.dr_go_mutex) ;
×
178

179
            // call exec_remove_sim_object to remove the data recording jobs from the sim.
180
            exec_remove_sim_object(in_group) ;
×
181

182
            // shutdown recording for the group
183
            in_group->shutdown() ;
×
184
        } else {
185
            drg_it++ ;
21✔
186
        }
187
    }
188

189

190

191
    return 0 ;
27✔
192
}
193

194
void Trick::DataRecordDispatcher::remove_all_groups() {
×
195
    while (!groups.empty()) {
×
196
        remove_group(groups[0]);
×
197
    }
198
}
×
199

200
/**
201
 @details
202
 -# Gets the data recording group by its name
203
 */
204
Trick::DataRecordGroup * Trick::DataRecordDispatcher::get_group(std::string in_name) {
6✔
205
    std::vector <Trick::DataRecordGroup *>::iterator it ;
6✔
206
    for ( it = groups.begin() ; it != groups.end() ; ++it ) {
17✔
207
        if ( ! (*it)->get_group_name().compare(in_name) )
15✔
208
            return *it ;
4✔
209
    }
210
    return NULL ;
2✔
211
}
212

213
/**
214
 @details
215
 -# Gets the data recording group by its id number
216
 */
217
Trick::DataRecordGroup * Trick::DataRecordDispatcher::get_group(int in_idx) {
6✔
218
    if (!groups.empty() && in_idx > -1 && in_idx < groups.size()) {
6✔
219
        return groups[in_idx];
4✔
220
    }
221
    return NULL ;
2✔
222
}
223

224
/**
225
 @details
226
 -# Gets the size of all added data recroding groups
227
 */
228
int Trick::DataRecordDispatcher::get_groups_size() {
2✔
229
    return groups.size();
2✔
230
}
231

232
/**
233
@details
234
-# If the writer thread condition variable is unlocked
235
   -# Signal the thread to go
236
*/
237
int Trick::DataRecordDispatcher::signal_thread() {
106,242✔
238

239
    if (!pthread_mutex_trylock(&drd_mutexes.dr_go_mutex)) {
106,242✔
240
        pthread_cond_signal(&drd_mutexes.dr_go_cv);
90,219✔
241
        pthread_mutex_unlock(&drd_mutexes.dr_go_mutex);
90,219✔
242
    }
243

244
    return(0) ;
106,242✔
245
}
246

247
/**
248
@details
249
-# Close out current data record groups
250
-# Clears the data record groups we are tracking.  The checkpoint reload will
251
   repopluate this list.
252
*/
253
int Trick::DataRecordDispatcher::preload_checkpoint() {
9✔
254
    unsigned int ii ;
255
    // close out current data record groups
256
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
16✔
257
        groups[ii]->shutdown() ;
7✔
258
    }
259
    groups.clear() ;
9✔
260
    return 0 ;
9✔
261
}
262

263
/**
264
@details
265
-# If we have not called init yet (pthread_id == 0), call init.
266
-# Delete existing log files.
267
*/
268
int Trick::DataRecordDispatcher::restart() {
9✔
269
    // if we restarted from scratch without calling init jobs, need to call init
270
    if ( drd_writer_thread.get_pthread_id() == 0 ) {
9✔
271
        init() ;
1✔
272
    }
273
    // remove the current log files
274
    remove_files() ;
9✔
275
    return 0 ;
9✔
276
}
277

278
/**
279
@details
280
-# If the thread was started,
281
   -# Wait for the thread to be available
282
   -# Cancel the thread
283
*/
284
int Trick::DataRecordDispatcher::shutdown() {
150✔
285

286
    if ( drd_writer_thread.get_pthread_id() != 0 ) {
150✔
287
        pthread_mutex_lock( &drd_mutexes.dr_go_mutex);
150✔
288
        // pthread_cancel( drd_writer_thread.get_pthread_id()) ;
289
        drd_mutexes.cancelled = true;
150✔
290
        pthread_cond_signal(&drd_mutexes.dr_go_cv);
150✔
291
        pthread_mutex_unlock( &drd_mutexes.dr_go_mutex);
150✔
292
    }
293

294
    return(0) ;
150✔
295
}
296

297
int Trick::DataRecordDispatcher::enable( const char * in_name ) {
×
298
    unsigned int ii ;
299
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
300
        if ( in_name == NULL or !groups[ii]->get_group_name().compare(in_name) )
×
301
            groups[ii]->enable() ;
×
302
    }
303
    return 0 ;
×
304
}
305

306
int Trick::DataRecordDispatcher::disable( const char * in_name ) {
×
307
    unsigned int ii ;
308
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
309
        if ( in_name == NULL or !groups[ii]->get_group_name().compare(in_name) )
×
310
            groups[ii]->disable() ;
×
311
    }
312
    return 0 ;
×
313
}
314

315
int Trick::DataRecordDispatcher::record_now_group( const char * in_name ) {
×
316
    unsigned int ii ;
317
    if ( in_name != NULL ) {
×
318
        for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
319
            if ( !groups[ii]->get_group_name().compare(in_name) )
×
320
                groups[ii]->data_record(exec_get_sim_time()) ;
×
321
        }
322
    }
323
    return 0 ;
×
324
}
325

326
int Trick::DataRecordDispatcher::set_group_max_file_size(const char * in_name, uint64_t bytes){
×
327
    unsigned int ii ;
328
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
329
        if ( in_name == NULL or !groups[ii]->get_group_name().compare(in_name) )
×
330
            groups[ii]->set_max_file_size(bytes) ;
×
331
    }
332
    return 0 ;
×
333
}
334

335
int Trick::DataRecordDispatcher::set_max_file_size(uint64_t bytes) {
×
336
    unsigned int ii ;
337
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
338
        groups[ii]->set_max_file_size(bytes) ;
×
339
    }
340
    return 0 ;
×
341
}
342

343
/**
344
@details
345
-# Call every group's init job - only needed when restoring checkpoint
346
-# during initialization, and the user is responsible for calling this.
347
*/
348
int Trick::DataRecordDispatcher::init_groups() {
×
349
    unsigned int ii ;
350
    for ( ii = 0 ; ii < groups.size() ; ii++ ) {
×
351
        groups[ii]->init() ;
×
352
    }
353

NEW
354
    if(verify_log_vars)
×
355
    {
NEW
356
        processMultipleVarLoggedCheck();
×
357
    }
358

359
    return 0 ;
×
360
}
361

362
/**
363
@details
364
 * Checks the data logging configuration in Trick against certain error or warning conditions.
365
 * Current conditions for errors are:
366
 * -  A variable logged in two different DataRecordGroup instances at a different rate
367
 */
NEW
368
void Trick::DataRecordDispatcher::processMultipleVarLoggedCheck()
×
369
{
NEW
370
    bool isLoggedMultipleTimes = false;
×
371

372
    // Check that a variable isn't logged multiple times in a log file.
NEW
373
    checkMultiVarSingleLogGroup(isLoggedMultipleTimes);
×
374

375
    // Check that a variable isn't logged in multiple log files.
NEW
376
    checkMultiVarMultiLogGroups(isLoggedMultipleTimes);
×
377

NEW
378
    if(isLoggedMultipleTimes && warning_level > 0)
×
379
    {
NEW
380
        std::stringstream ss;
×
NEW
381
        ss << "Invalid or unsafe logging configuration. Exiting..." << std::endl;
×
NEW
382
        if (warning_level >= 2)
×
NEW
383
            exec_terminate_with_return(-1, __FILE__, __LINE__, ss.str().c_str());
×
384
    }
NEW
385
}
×
386

NEW
387
void Trick::DataRecordDispatcher::checkMultiVarSingleLogGroup(bool & isLoggedMultipleTimes)
×
388
{
389
    // Check that a variable isn't logged multiple times in a log file.
NEW
390
    for(size_t grpIdx = 0; grpIdx < groups.size(); ++grpIdx)
×
391
    {
NEW
392
        Trick::DataRecordGroup * drGroup = groups[grpIdx];
×
393
        // Start at index 1 to skip exec time.
NEW
394
        for(size_t varOneIdx = 1; varOneIdx < drGroup->rec_buffer.size(); ++varOneIdx)
×
395
        {
NEW
396
            for(size_t varTwoIdx = varOneIdx + 1; varTwoIdx < drGroup->rec_buffer.size(); ++varTwoIdx)
×
397
            {
NEW
398
                Trick::DataRecordBuffer * var1 = drGroup->rec_buffer[varOneIdx];
×
NEW
399
                Trick::DataRecordBuffer * var2 = drGroup->rec_buffer[varTwoIdx];
×
NEW
400
                const std::string & var1CmpStr = var1->alias.empty() ? var1->name : var1->alias;
×
NEW
401
                const std::string & var2CmpStr = var2->alias.empty() ? var2->name : var2->alias;
×
NEW
402
                if(var1CmpStr.compare(var2CmpStr) == 0)
×
403
                {
NEW
404
                    isLoggedMultipleTimes = true;
×
NEW
405
                    if (warning_level >= 1)
×
406
                    {
NEW
407
                        std::stringstream ss;
×
NEW
408
                        ss << "The variable \"";
×
NEW
409
                        if(var1->alias.empty())
×
410
                        {
NEW
411
                            ss << var1->name << "\"";
×
412
                        }
413
                        else
414
                        {
NEW
415
                            ss << var1->name << "\" (logged as alias \"" << var1->alias << "\")";
×
416
                        }
NEW
417
                        ss << " is being logged twice in the data recording group \"" << drGroup->group_name << "\" ."
×
NEW
418
                            << std::endl;
×
NEW
419
                        message_publish(MSG_ERROR, ss.str().c_str());
×
420
                    }
421
                }
422
            }
423
        }
424
    }
NEW
425
}
×
426

NEW
427
void Trick::DataRecordDispatcher::checkMultiVarMultiLogGroups(bool & isLoggedMultipleTimes)
×
428
{
NEW
429
    for(size_t grpOneIdx = 0; grpOneIdx < groups.size(); ++grpOneIdx)
×
430
    {
NEW
431
        Trick::DataRecordGroup * drGroupOne = groups[grpOneIdx];
×
NEW
432
        for(auto & var1 : drGroupOne->rec_buffer)
×
433
        {
NEW
434
            if(var1->name.compare("sys.exec.out.time") == 0)
×
435
            {
NEW
436
                continue;
×
437
            }
NEW
438
            for(size_t grpTwoIdx = grpOneIdx + 1; grpTwoIdx < groups.size(); ++grpTwoIdx)
×
439
            {
NEW
440
                Trick::DataRecordGroup * drGroupTwo = groups[grpTwoIdx];
×
441

NEW
442
                auto nameCompare = [var1](Trick::DataRecordBuffer * var2)
×
443
                {
NEW
444
                    const std::string & var1CmpStr = var1->alias.empty() ? var1->name : var1->alias;
×
NEW
445
                    const std::string & var2CmpStr = var2->alias.empty() ? var2->name : var2->alias;
×
NEW
446
                    return (var1CmpStr.compare(var2CmpStr) == 0);
×
NEW
447
                };
×
448

NEW
449
                auto result = std::find_if(drGroupTwo->rec_buffer.begin(), drGroupTwo->rec_buffer.end(), nameCompare);
×
NEW
450
                while(result != drGroupTwo->rec_buffer.end())
×
451
                {
NEW
452
                    isLoggedMultipleTimes = true;
×
NEW
453
                    if (warning_level >= 1)
×
454
                    {
NEW
455
                        std::stringstream ss;
×
NEW
456
                        ss << "The variable \"";
×
NEW
457
                        if(var1->alias.empty())
×
458
                        {
NEW
459
                            ss << var1->name << "\"";
×
460
                        }
461
                        else
462
                        {
NEW
463
                            ss << var1->name << "\" (logged as alias \"" << var1->alias << "\")";
×
464
                        }
NEW
465
                        ss << " is being logged in both \"" << drGroupOne->group_name << "\" and \""
×
NEW
466
                            << drGroupTwo->group_name << "\" data recording groups." << std::endl;
×
NEW
467
                        message_publish(MSG_ERROR, ss.str().c_str());
×
468
                    }
NEW
469
                    result = std::find_if(++result, drGroupTwo->rec_buffer.end(), nameCompare);
×
470
                }
471
            }
472
        }
473
    }
NEW
474
}
×
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