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

nasa / trick / 30672691247

31 Jul 2026 11:22PM UTC coverage: 56.743% (+0.07%) from 56.671%
30672691247

Pull #2173

github

web-flow
Merge fd95a7456 into 746816931
Pull Request #2173: Fix GIL shutdown hang.

46 of 55 new or added lines in 3 files covered. (83.64%)

14869 of 26204 relevant lines covered (56.74%)

463203.35 hits per line

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

70.78
/trick_source/sim_services/ThreadBase/ThreadBase.cpp
1
#include <csignal>
2
#include <cstdio>
3
#include <cstring>
4
#include <iostream>
5
#include <pthread.h>
6
#include <string>
7
#include <unistd.h>
8

9
#if __linux__
10
#include <sys/syscall.h>
11
#include <sys/types.h>
12
#include <sched.h>
13
#endif
14

15
#include "trick/ThreadBase.hh"
16
#include "trick/message_proto.h"
17
#include "trick/message_type.h"
18

19
Trick::ThreadBase::ThreadBase(std::string in_name) :
1,043✔
20
 name(in_name) ,
1,043✔
21
 pthread_id(0) ,
1,043✔
22
 pid(0) ,
1,043✔
23
 rt_priority(0),
1,043✔
24
 created(false),
1,043✔
25
 should_shutdown(false),
1,043✔
26
 cancellable(true)
1,043✔
27
{
28
    pthread_mutex_init(&shutdown_mutex, NULL);
1,043✔
29
#if __linux__
30
    max_cpu = sysconf( _SC_NPROCESSORS_ONLN ) ;
1,043✔
31
#ifdef CPU_ALLOC
32
    cpus = CPU_ALLOC(max_cpu) ;
1,043✔
33
    CPU_ZERO_S(CPU_ALLOC_SIZE(max_cpu), cpus) ;
1,043✔
34
#else
35
    cpus = (cpu_set_t *)calloc(1, sizeof(cpu_set_t)) ;
36
#endif
37
#endif
38
#if __APPLE__
39
    max_cpu = 0 ;
40
#endif
41
}
1,043✔
42

43
Trick::ThreadBase::~ThreadBase() {
1,027✔
44
#if __linux__
45
#ifdef CPU_FREE
46
    CPU_FREE(cpus) ;
1,027✔
47
#endif
48
#endif
49
}
1,027✔
50

51
std::string Trick::ThreadBase::get_name() {
×
52
    return name ;
×
53
}
54

55
void Trick::ThreadBase::set_name(std::string in_name) {
×
56
    name = in_name ;
×
57
}
×
58

59
pthread_t Trick::ThreadBase::get_pthread_id() {
7,075✔
60
    return pthread_id ;
7,075✔
61
}
62

63
pid_t Trick::ThreadBase::get_pid() {
×
64
    return pid ;
×
65
}
66

67
void Trick::ThreadBase::set_pid() {
665✔
68
#if __linux__
69
    pid = syscall( __NR_gettid ) ;
665✔
70
#else
71
    pid = getpid() ;
72
#endif
73
}
665✔
74

75
int Trick::ThreadBase::cpu_set(unsigned int cpu __attribute__((unused))) {
2✔
76
    int ret =  0 ;
2✔
77
#if __linux__
78
    if ( cpu < max_cpu ) {
2✔
79
#ifdef CPU_SET_S
80
        CPU_SET_S(cpu, CPU_ALLOC_SIZE(max_cpu), cpus) ;
2✔
81
#else
82
        CPU_SET(cpu, cpus) ;
83
#endif
84
    } else {
85
        message_publish(MSG_WARNING, "CPU value %d is out of range (0 through %d)", cpu, max_cpu - 1) ;
×
86
        ret = -1 ;
×
87
    }
88
#endif
89
#if __APPLE__
90
    message_publish(MSG_WARNING, "Warning: Trick on Darwin does not yet support processor assignment.\n");
91
#endif
92
    return ret ;
2✔
93
}
94

95
int Trick::ThreadBase::cpu_clr(unsigned int cpu __attribute__((unused))) {
×
96
    int ret =  0 ;
×
97
#if __linux__
98
    if ( cpu < max_cpu ) {
×
99
#ifdef CPU_CLR_S
100
        CPU_CLR_S(cpu, CPU_ALLOC_SIZE(max_cpu), cpus) ;
×
101
#else
102
        CPU_CLR(cpu, cpus) ;
103
#endif
104
    } else {
105
        message_publish(MSG_WARNING, "CPU value %d is out of range (0 through %d)", cpu, max_cpu - 1) ;
×
106
        ret = -1 ;
×
107
    }
108
#endif
109
#if __APPLE__
110
    message_publish(MSG_WARNING, "Warning: Trick on Darwin does not yet support processor assignment.\n");
111
#endif
112
    return ret ;
×
113
}
114

115
#if __linux__
116
cpu_set_t * Trick::ThreadBase::get_cpus() {
11✔
117
    return cpus ;
11✔
118
}
119

120
void Trick::ThreadBase::copy_cpus(cpu_set_t * in_cpus) {
11✔
121
#ifdef CPU_OR_S
122
    CPU_ZERO_S(CPU_ALLOC_SIZE(max_cpu), cpus) ;
11✔
123
    CPU_OR_S(CPU_ALLOC_SIZE(max_cpu), cpus, cpus, in_cpus) ;
22✔
124
#else
125
    *cpus = *in_cpus ;
126
#endif
127
}
11✔
128
#endif
129
#if __APPLE__
130
void * Trick::ThreadBase::get_cpus() {
131
    return NULL ;
132
}
133

134
void Trick::ThreadBase::copy_cpus(void * in_cpus __attribute__((unused))) {
135
}
136
#endif
137

138
int Trick::ThreadBase::execute_cpu_affinity() {
665✔
139
#if __linux__
140
#ifdef CPU_ALLOC_SIZE
141
    sched_setaffinity(pid, CPU_ALLOC_SIZE(max_cpu), cpus) ;
665✔
142
#else
143
    sched_setaffinity(pid, sizeof(cpu_set_t), cpus) ;
144
#endif
145
#endif
146
    return(0) ;
665✔
147
}
148

149
int Trick::ThreadBase::set_priority(unsigned int req_priority) {
2✔
150
    rt_priority = req_priority ;
2✔
151
    return 0 ;
2✔
152
}
153

154
#if __linux__
155

156
#include <sched.h>
157
#include <errno.h>
158

159
int Trick::ThreadBase::execute_priority() {
665✔
160

161
    int max_priority;
162
    int min_priority;
163
    int proc_priority;
164
    struct sched_param sparams;
165
    int sched_policy = SCHED_FIFO;
665✔
166

167
    if ( rt_priority > 0 ) {
665✔
168
        if (sched_getparam((pid_t) 0, &sparams)) {
×
169
            message_publish(MSG_ERROR, "Failed to get process scheduling parameters: %s\n", std::strerror(errno));
×
170
        } else {
171

172
            /* Get maximum and minimum RT priority */
173
            max_priority = sched_get_priority_max(SCHED_FIFO);
×
174
            min_priority = sched_get_priority_min(SCHED_FIFO);
×
175

176
            /* Since Trick's max priority starts at 1 and moves to lower priorties as the number goes up and Linux's
177
               priorities goes up as the number goes up and maxes out at "max_priority", we need to offset as follows:
178
             */
179
            proc_priority = max_priority - (rt_priority - 1);
×
180

181
            /* Make sure priority is in bounds. */
182
            if (proc_priority < min_priority) {
×
183

184
                message_publish(MSG_WARNING, "Warning: Linux process %d priority at %d is too low.  Minimum Trick \npriority is %d.\n",
×
185
                         pid, rt_priority, (max_priority - min_priority) + 2);
×
186

187
                proc_priority = min_priority;
×
188
            }
189

190
            if (pthread_getschedparam(pthread_self(), &sched_policy, &sparams)) {
×
191

192
                message_publish(MSG_ERROR, "Failed to get process scheduling parameters: %s\n", std::strerror(errno));
×
193
            }
194

195
            /* Set the process priority. */
196
            sparams.sched_priority = proc_priority;
×
197
            if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparams)) {
×
198
                message_publish(MSG_ERROR, "Failed to set thread priority: %s\n", std::strerror(errno));
×
199
            }
200
        }
201
    }
202

203
    return(0) ;
665✔
204

205
}
206
#endif
207

208
#if __APPLE__
209

210
#include <sched.h>
211
#include <errno.h>
212

213
int Trick::ThreadBase::execute_priority() {
214

215
    int ret;
216

217
    /* Declare scheduling paramters. */
218
    int max_priority;
219
    int min_priority;
220
    int prev_priority;
221
    int proc_priority;
222
    int sched_policy = SCHED_FIFO;
223
    struct sched_param param;
224

225
    if ( rt_priority > 0 ) {
226
        /* Get maximum and minimum RT priority, and current parameters. */
227
        max_priority = sched_get_priority_max(sched_policy);
228
        min_priority = sched_get_priority_min(sched_policy);
229
        pthread_getschedparam(pthread_self(), &sched_policy, &param);
230
        prev_priority = param.sched_priority;
231

232
        /* Trick's max priority starts at 1 and moves to lower priorities as the number goes up.  Darwin's thread
233
           priorities range between 15 to 47 (observed). The default priority is 31 (observed); higher priorities
234
           cause more favorable scheduling. */
235
        proc_priority = max_priority - (rt_priority - 1);
236

237
        /* Make sure priority is in bounds. */
238
        if (proc_priority < min_priority) {
239

240
            message_publish(MSG_WARNING, "Warning: Trick CPU priority at %d is too low.\n", rt_priority);
241
            message_publish(MSG_WARNING, "This corresponds to a Darwin thread priority of %d.\n", proc_priority);
242
            message_publish(MSG_WARNING, "The Darwin thread priority range is %d:%d (min:max).\n", min_priority, max_priority);
243
            message_publish(MSG_WARNING, "The corresponding minimum Trick priority is %d.\n", (max_priority - min_priority) + 1);
244
            message_publish(MSG_WARNING, "Setting Trick priority to minimum!\n");
245
            proc_priority = min_priority;
246

247
        } else if (proc_priority > max_priority) {
248

249
            message_publish(MSG_WARNING, "Warning: Trick CPU priority at %d is too high.\n", rt_priority);
250
            message_publish(MSG_WARNING, "This corresponds to a Darwin thread priority of %d.\n", proc_priority);
251
            message_publish(MSG_WARNING, "The Darwin thread priority range is %d:%d (min:max).\n", min_priority, max_priority);
252
            message_publish(MSG_WARNING, "The maximum Trick priority is 1. Setting to maximum!\n");
253
            proc_priority = max_priority;
254
        }
255

256
        /* Set the process priority. */
257
        param.sched_priority = proc_priority;
258

259
        ret = pthread_setschedparam(pthread_self(), sched_policy, &param);
260
        if (ret != 0) {
261

262
            message_publish(MSG_ERROR, "Failed to set Darwin thread priority to %d: %s\n", param.sched_priority, std::strerror(errno));
263
            message_publish(MSG_ERROR, "This should correspond to a Trick CPU priority of %d.\n", (max_priority - proc_priority) + 1);
264
            message_publish(MSG_ERROR, "The current Darwin thread priority is %d.\n", prev_priority);
265
            message_publish(MSG_ERROR, "The Darwin thread priority range is %d:%d (min:max).\n", min_priority, max_priority);
266

267
        } else {
268

269
            message_publish(MSG_INFO, "Info: Trick CPU priority set to %d.\n", (max_priority - proc_priority) + 1);
270
            message_publish(MSG_INFO, "This corresponds to a Darwin thread priority of %d.\n", param.sched_priority);
271
            message_publish(MSG_INFO, "The previous Darwin thread priority was %d.\n", prev_priority);
272
            message_publish(MSG_INFO, "The Darwin thread priority range is %d:%d (min:max).\n", min_priority, max_priority);
273
        }
274
    }
275

276
    return(0) ;
277

278
}
279

280
#endif
281

282
int Trick::ThreadBase::create_thread() {
499✔
283

284
    if (created) {
499✔
285
        message_publish(MSG_ERROR, "create_thread called on thread %s (%p) which has already been started.\n", name.c_str(), this);
×
286
        return 0;
×
287
    }
288

289
    pthread_attr_t attr;
290

291
    pthread_attr_init(&attr);
499✔
292
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
499✔
293
    pthread_create(&pthread_id, &attr, Trick::ThreadBase::thread_helper , (void *)this);
499✔
294
    created = true;
499✔
295

296
#if __linux__
297
#ifdef __GNUC__
298
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2
299
    if ( ! name.empty() ) {
499✔
300
       std::string short_str = name.substr(0,15) ;
499✔
301
       pthread_setname_np(pthread_id, short_str.c_str()) ;
499✔
302
    }
499✔
303
#endif
304
#endif
305
#endif
306
    return(0) ;
499✔
307
}
308

309
int Trick::ThreadBase::cancel_thread() {
1,081✔
310
    pthread_mutex_lock(&shutdown_mutex);
1,081✔
311
    should_shutdown = true;
1,081✔
312
    pthread_mutex_unlock(&shutdown_mutex);
1,081✔
313

314
    if ( pthread_id != 0 ) {
1,081✔
315
        if (cancellable)
795✔
316
            pthread_cancel(pthread_id) ;
470✔
317
    }
318
    return(0) ;
1,081✔
319
}
320

321
int Trick::ThreadBase::request_shutdown()
4✔
322
{
323
    pthread_mutex_lock(&shutdown_mutex);
4✔
324
    should_shutdown = true;
4✔
325
    pthread_mutex_unlock(&shutdown_mutex);
4✔
326
    return (0);
4✔
327
}
328

NEW
329
int Trick::ThreadBase::abandon_thread()
×
330
{
NEW
331
    if (pthread_id != 0)
×
332
    {
NEW
333
        pthread_detach(pthread_id);
×
334
        // Clearing the id is what makes this safe: cancel_thread() and join_thread() are
335
        // both guarded by (pthread_id != 0), so nothing later in the shutdown sequence --
336
        // including SysThread::ensureAllShutdown() -- can block on this thread.
NEW
337
        pthread_id = 0;
×
338
    }
NEW
339
    return (0);
×
340
}
341

342
int Trick::ThreadBase::join_thread() {
778✔
343
    if ( pthread_id != 0 ) {
778✔
344
        if ((errno = pthread_join(pthread_id, NULL)) != 0) {
492✔
345
            std::string msg = "Thread " + name + " had an error in join";
×
346
            perror(msg.c_str());
×
347
        } else {
×
348
            pthread_id = 0;
492✔
349
        }
350
    }
351
    return(0) ;
778✔
352
}
353

354
void Trick::ThreadBase::test_shutdown() {
1,774,555✔
355
    test_shutdown (NULL, NULL);
1,774,555✔
356
}
1,774,392✔
357

358
void Trick::ThreadBase::test_shutdown(void (*exit_handler) (void *), void * exit_arg) {
1,775,330✔
359
    pthread_mutex_lock(&shutdown_mutex);
1,775,330✔
360
    if (should_shutdown) {
1,775,330✔
361
        pthread_mutex_unlock(&shutdown_mutex);
168✔
362

363
        thread_shutdown(exit_handler, exit_arg);
168✔
364
    }
365
    pthread_mutex_unlock(&shutdown_mutex);
1,775,162✔
366
}
1,775,162✔
367

368

369
void Trick::ThreadBase::thread_shutdown() {
2✔
370
    thread_shutdown (NULL, NULL);
2✔
371
}
×
372

373
void Trick::ThreadBase::thread_shutdown(void (*exit_handler) (void *), void * exit_arg) {
180✔
374
    if (exit_handler != NULL) {
180✔
375
        exit_handler(exit_arg);
15✔
376
    }
377

378
    pthread_exit(0);
180✔
379
}
380

381
void * Trick::ThreadBase::thread_helper( void * context ) {
499✔
382

383
    sigset_t sigs;
384
    Trick::ThreadBase * tb = (Trick::ThreadBase *)context ;
499✔
385

386
    /* block out all signals on this thread */
387
    sigfillset(&sigs);
499✔
388
    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
499✔
389

390
    /* Set the cancel type to deffered, the thread will be cancelled at next cancellation point */
391
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
499✔
392

393
    tb->set_pid() ;
499✔
394

395
    /* Set thread priority and CPU affinity */
396
    tb->execute_priority() ;
499✔
397
    tb->execute_cpu_affinity() ;
499✔
398

399
    return tb->thread_body() ;
499✔
400
}
401

402
void Trick::ThreadBase::dump( std::ostream & oss ) {
161✔
403
    oss << "    from Trick::ThreadBase\n";
161✔
404
    oss << "    pthread_id = " << pthread_id << "\n";
161✔
405
    oss << "    process_id = " << pid << "\n";
161✔
406
    oss << "    rt_priority = " << rt_priority << "\n";
161✔
407
#if __linux__
408
    oss << "    cpus = " ;
161✔
409
    bool first_print = true ;
161✔
410
    for ( unsigned int ii = 0 ; ii < max_cpu ; ii++ ) {
805✔
411
#ifdef CPU_ISSET_S
412
        if ( CPU_ISSET_S(ii, CPU_ALLOC_SIZE(max_cpu), cpus) ) {
644✔
413
#else
414
        if ( CPU_ISSET(ii, cpus) ) {
415
#endif
416
            if ( first_print == true ) {
×
417
                first_print = false ;
×
418
            } else {
419
                oss << "," ;
×
420
            }
421
            oss << ii ;
×
422
        }
423
    }
424
    if ( first_print ) {
161✔
425
        oss << "none assigned" ;
161✔
426
    }
427
    oss << std::endl ;
161✔
428
#endif
429
}
161✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc