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

nasa / trick / 17772917031

16 Sep 2025 04:46PM UTC coverage: 55.866% (-0.005%) from 55.871%
17772917031

Pull #1958

github

web-flow
Merge d8200bf04 into ed8b1979f
Pull Request #1958: Resolves potential-for-fpe-in-run_ratio-sample-calcs

10 of 12 new or added lines in 1 file covered. (83.33%)

5 existing lines in 3 files now uncovered.

12352 of 22110 relevant lines covered (55.87%)

267838.56 hits per line

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

58.02
/trick_source/sim_services/Executive/Threads_child.cpp
1
/*
2
   PURPOSE: (The Trick simulation child executive processing.)
3

4
   REFERENCE: ((None))
5

6
   ASSUMPTIONS AND LIMITATIONS: ((this is executive only from the child process forked by the executive))
7

8
   PROGRAMMERS:
9
      (((Robert W. Bailey) (LinCom) (October 1993) (--) (Realtime))
10
       ((Eddie J. Paddock) (MDSSC) (April 1992) (--) (Realtime)))
11
 */
12

13
#include <iostream>
14
#include <stdlib.h>
15
#include <errno.h>
16
#include <signal.h>
17
#include <sys/syscall.h>
18

19
#ifdef __linux__
20
#include <cxxabi.h>
21
#endif
22

23
#include "trick/Threads.hh"
24
#include "trick/release.h"
25
#include "trick/ExecutiveException.hh"
26
#include "trick/exec_proto.h"
27
#include "trick/TrickConstant.hh"
28
#include "trick/message_proto.h"
29

30

31
/**
32
@details
33
-# Wait for all job dependencies to complete.  Requirement  [@ref r_exec_thread_6]
34
-# Call the job.  Requirement  [@ref r_exec_periodic_0]
35
-# If the job is a system job, check to see if the next job call time is the lowest next time by
36
   calling Trick::ScheduledJobQueue::test_next_job_call_time(Trick::JobData *, long long)
37
-# Set the job complete flag
38
*/
39
static int call_next_job(Trick::JobData * curr_job, Trick::ScheduledJobQueue & job_queue, bool rt_nap, long long curr_time_tics) {
554✔
40

41
    Trick::JobData * depend_job ;
42
    unsigned int ii ;
43
    int ret = 0 ;
554✔
44

45
    //cout << "time = " << curr_time_tics << " " << curr_job->name << " job next = "
46
    //  << curr_job->next_tics << " id = " << curr_job->id << endl ;
47

48
    /* Wait for all jobs that the current job depends on to complete. */
49
    for ( ii = 0 ; ii < curr_job->depends.size() ; ii++ ) {
792✔
50
        depend_job = curr_job->depends[ii] ;
238✔
51
        while (! depend_job->complete) {
238✔
UNCOV
52
            if (rt_nap == true) {
×
UNCOV
53
                RELEASE();
×
54
            }
55
        }
56
    }
57

58
    /* Call the current scheduled job. */
59
    ret = curr_job->call() ;
555✔
60

61
    if ( ret != 0 ) {
556✔
62
        exec_terminate_with_return(ret , curr_job->name.c_str() , 0 , "scheduled job did not return 0") ;
×
63
    }
64

65
    /* System jobs next call time are not set until after they run. We test their next job call time here. */
66
    if ( curr_job->system_job_class ) {
556✔
67
        job_queue.test_next_job_call_time(curr_job , curr_time_tics) ;
5✔
68
    }
69

70
    curr_job->complete = true ;
556✔
71

72
    return 0 ;
556✔
73
}
74

75
/**
76
@details
77
-# Block all signals to the child.
78
-# Set the thread cancel type to asynchronous to allow master to this child at any time.
79
-# Lock the go mutex so the master has to wait until this child is ready before staring execution.
80
-# Set thread priority and CPU affinity
81
-# The child enters an infinite loop
82
    -# Blocks on mutex or frame trigger until master signals to start processing
83
    -# Switch if the child is a synchronous thread
84
        -# For each scheduled jobs whose next call time is equal to the current simulation time [@ref ScheduledJobQueue]
85
            -# Call call_next_job(Trick::JobData * curr_job, Trick::ScheduledJobQueue & job_queue, bool rt_nap, long long curr_time_tics)
86
    -# Switch if the child is a asynchronous must finish thread
87
        -# Do while the job queue time is less than the time of the next AMF sync time.
88
            -# For each scheduled jobs whose next call time is equal to the current queue time
89
                -# Call call_next_job(Trick::JobData * curr_job, Trick::ScheduledJobQueue & job_queue, bool rt_nap, long long curr_time_tics)
90
    -# Switch if the child is a asynchronous thread
91
        -# For each scheduled jobs
92
            -# Call call_next_job(Trick::JobData * curr_job, Trick::ScheduledJobQueue & job_queue, bool rt_nap, long long curr_time_tics)
93
    -# Set the child complete flag
94
*/
95
void * Trick::Threads::thread_body() {
5✔
96

97
    /* Lock the go mutex so the master has to wait until this child is ready before staring execution. */
98
    trigger_container.getThreadTrigger()->init() ;
5✔
99

100
    /* signal the master that the child is ready and running */
101
    child_complete = true;
5✔
102
    running = true ;
5✔
103

104
    try {
105
        do {
106

107
            /* Block child on trigger until master signals. */
108
            trigger_container.getThreadTrigger()->wait() ;
1,432✔
109

110
            if ( enabled ) {
1,428✔
111

112
                switch ( process_type ) {
1,428✔
113
                    case PROCESS_TYPE_SCHEDULED:
1,001✔
114
                    /* Loop through all jobs currently scheduled to run at this simulation time step. */
115
                    job_queue.reset_curr_index() ;
1,001✔
116
                    job_queue.set_next_job_call_time(TRICK_MAX_LONG_LONG) ;
1,001✔
117
                    while ( (curr_job = job_queue.find_next_job( curr_time_tics )) != NULL ) {
1,114✔
118
                        call_next_job(curr_job, job_queue, rt_nap, curr_time_tics) ;
113✔
119
                    }
120
                    break ;
1,001✔
121

122
                    case PROCESS_TYPE_AMF_CHILD:
428✔
123
                    /* call the AMF top of frame jobs */
124
                    top_of_frame_queue.reset_curr_index() ;
428✔
125
                    while ( (curr_job = top_of_frame_queue.get_next_job()) != NULL ) {
1,277✔
126
                        int ret ;
127
                        ret = curr_job->call() ;
854✔
128
                        if ( ret != 0 ) {
849✔
129
                            exec_terminate_with_return(ret , curr_job->name.c_str() , 0 , " top_of_frame job did not return 0") ;
×
130
                        }
131
                    }
132

133
                    /* Loop through all jobs currently up to the point of the next AMF frame sync */
134
                    do {
×
135
                        job_queue.reset_curr_index() ;
421✔
136
                        job_queue.set_next_job_call_time(amf_next_tics) ;
423✔
137
                        while ( (curr_job = job_queue.find_next_job( curr_time_tics )) != NULL ) {
866✔
138
                            call_next_job(curr_job, job_queue, rt_nap, curr_time_tics) ;
440✔
139
                        }
140
                        curr_time_tics = job_queue.get_next_job_call_time() ;
428✔
141
                    } while ( curr_time_tics < amf_next_tics ) ;
428✔
142

143
                    /* call the AMF end of frame jobs */
144
                    end_of_frame_queue.reset_curr_index() ;
428✔
145
                    while ( (curr_job = end_of_frame_queue.get_next_job()) != NULL ) {
428✔
146
                        int ret ;
147
                        ret = curr_job->call() ;
×
148
                        if ( ret != 0 ) {
×
149
                            exec_terminate_with_return(ret , curr_job->name.c_str() , 0 , " end_of_frame job did not return 0") ;
×
150
                        }
151
                    }
152
                    break ;
428✔
153

154
                    case PROCESS_TYPE_ASYNC_CHILD:
1✔
155
                    /* Loop through all jobs once */
156
                    if ( amf_cycle_tics == 0 ) {
1✔
157
                        // Old behavior, run all jobs once and return.
158
                        job_queue.reset_curr_index() ;
1✔
159
                        job_queue.set_next_job_call_time(TRICK_MAX_LONG_LONG) ;
1✔
160
                        while ( (curr_job = job_queue.get_next_job()) != NULL ) {
2✔
161
                            call_next_job(curr_job, job_queue, rt_nap, curr_time_tics) ;
2✔
162
                        }
163
                    } else {
164

165
                        // catch up job next times to current frame.
166
                        job_queue.reset_curr_index() ;
×
167
                        while ( (curr_job = job_queue.get_next_job()) != NULL ) {
×
168
                            long long start_frame = amf_next_tics - amf_cycle_tics ;
×
169
                            while ( curr_job->next_tics < start_frame ) {
×
170
                                curr_job->next_tics += curr_job->cycle_tics ;
×
171
                            }
172
                        }
173

174
                        // New behavior, run a mini scheduler.
175
                        /* call the AMF top of frame jobs */
176
                        top_of_frame_queue.reset_curr_index() ;
×
177
                        while ( (curr_job = top_of_frame_queue.get_next_job()) != NULL ) {
×
178
                            int ret ;
179
                            ret = curr_job->call() ;
×
180
                            if ( ret != 0 ) {
×
181
                                exec_terminate_with_return(ret , curr_job->name.c_str() , 0 , " top_of_frame job did not return 0") ;
×
182
                            }
183
                        }
184

185
                        /* Loop through all jobs currently up to the point of the next AMF frame sync */
186
                        do {
×
187
                            job_queue.reset_curr_index() ;
×
188
                            job_queue.set_next_job_call_time(amf_next_tics) ;
×
189
                            while ( (curr_job = job_queue.find_next_job( curr_time_tics )) != NULL ) {
×
190
                                call_next_job(curr_job, job_queue, rt_nap, curr_time_tics) ;
×
191
                            }
192
                            curr_time_tics = job_queue.get_next_job_call_time() ;
×
193
                        } while ( curr_time_tics < amf_next_tics ) ;
×
194

195
                        /* call the AMF end of frame jobs */
196
                        end_of_frame_queue.reset_curr_index() ;
×
197
                        while ( (curr_job = end_of_frame_queue.get_next_job()) != NULL ) {
×
198
                            int ret ;
199
                            ret = curr_job->call() ;
×
200
                            if ( ret != 0 ) {
×
201
                                exec_terminate_with_return(ret , curr_job->name.c_str() , 0 , " end_of_frame job did not return 0") ;
×
202
                            }
203
                        }
204
                    }
205
                    break ;
×
206

207
                    default:
208
                    break ;
209
                }
210
            }
211

212
            /* After all jobs have completed, set the child_complete flag to true. */
213
            child_complete = true;
1,427✔
214

215
        } while (1);
216
    } catch (Trick::ExecutiveException & ex ) {
×
217
        fprintf(stderr, "\nCHILD THREAD %d TERMINATED with exec_terminate\n  ROUTINE: %s\n  DIAGNOSTIC: %s\n"
×
218
         "  THREAD STOP TIME: %f\n" ,
219
         thread_id, ex.file.c_str(), ex.message.c_str(), exec_get_sim_time()) ;
220
        exit(ex.ret_code) ;
×
221
#ifdef __linux__
222
    // for post gcc 4.1.2
223
    } catch (abi::__forced_unwind&) {
10✔
224
        //pthread_exit and pthread_cancel will cause an abi::__forced_unwind to be thrown. Rethrow it.
225
        throw;
5✔
226
#endif
227
    }
228

229
    pthread_exit(NULL) ;
230
    return 0 ;
231
}
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

© 2025 Coveralls, Inc