GCC Code Coverage Report


Directory: ./
File: pdserv/src/PThread.cpp
Date: 2026-05-10 04:09:05
Exec Total Coverage
Lines: 82 87 94.3%
Branches: 45 83 54.2%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright 2017 Richard Hacker (lerichi at gmx dot net)
4 *
5 * This file is part of the pdserv library.
6 *
7 * The pdserv library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation, either version 3 of the License, or (at
10 * your option) any later version.
11 *
12 * The pdserv library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with the pdserv library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22 #include "PThread.h"
23
24 #include "Main.h"
25
26 #include <time.h>
27 #include <errno.h>
28 #include <cstdio>
29
30 using namespace pthread;
31
32 ////////////////////////////////////////////////////////////////////////////
33 ////////////////////////////////////////////////////////////////////////////
34 1099 RWLock::RWLock()
35 {
36 1099 pthread_rwlockattr_t attr;
37
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1099 times.
1099 pthread_rwlockattr_init(&attr);
39
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1099 times.
1099 pthread_rwlock_init(&lock, &attr);
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1099 times.
1099 pthread_rwlockattr_destroy(&attr);
41 1099 }
42
43 ////////////////////////////////////////////////////////////////////////////
44 2198 RWLock::~RWLock()
45 {
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1099 times.
1099 pthread_rwlock_destroy(&lock);
47 1099 }
48
49 ////////////////////////////////////////////////////////////////////////////
50 ////////////////////////////////////////////////////////////////////////////
51 934 Mutex::Mutex()
52 {
53 934 pthread_mutexattr_t attr;
54
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
934 pthread_mutexattr_init(&attr);
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
934 pthread_mutex_init(&mutex, &attr);
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
934 pthread_mutexattr_destroy(&attr);
58 934 }
59
60 ////////////////////////////////////////////////////////////////////////////
61 1868 Mutex::~Mutex()
62 {
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
934 pthread_mutex_destroy(&mutex);
64 934 }
65
66 ////////////////////////////////////////////////////////////////////////////
67 ////////////////////////////////////////////////////////////////////////////
68 461 Thread::Thread(const std::string &name):
69 461 name(name)
70 {
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 461 times.
461 pthread_attr_init(&attr);
72 461 }
73
74 ////////////////////////////////////////////////////////////////////////////
75 922 Thread::~Thread()
76 {
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 461 times.
461 pthread_attr_destroy(&attr);
78 461 }
79
80 ////////////////////////////////////////////////////////////////////////////
81 150 void Thread::set_priority(int prio)
82 {
83
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 if (prio > priority_unset_value) {
84 150 rt_priority = prio;
85 }
86 else {
87 rt_priority = priority_unset_value;
88 }
89 150 }
90
91 ////////////////////////////////////////////////////////////////////////////
92 454 int Thread::start()
93 {
94
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 454 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 454 times.
454 if (was_started)
95 return 0;
96
97
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 454 times.
454 const int ans = pthread_create(&id, &attr, &start_routine, this);
98
1/2
✓ Branch 0 taken 454 times.
✗ Branch 1 not taken.
454 if (ans == 0) {
99 454 was_started = true;
100
101
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 454 times.
454 int ret = pthread_setname_np(id, name.c_str());
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
454 if (ret) {
103 fprintf(stderr, "Failed to set thread name to %s: %s\n",
104 name.c_str(),
105 strerror(ret));
106 }
107 }
108 454 return ans;
109 }
110
111 ////////////////////////////////////////////////////////////////////////////
112 149 int Thread::detach()
113 {
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
115 149 return start();
116 }
117
118 ////////////////////////////////////////////////////////////////////////////
119 312 void Thread::terminate() noexcept
120 {
121
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
✓ Branch 5 taken 305 times.
✓ Branch 6 taken 7 times.
312 if (was_started)
122 305 pthread_cancel(id);
123 312 }
124
125 ////////////////////////////////////////////////////////////////////////////
126 312 void *Thread::join() noexcept
127 {
128 // join() may be called in a dtor, so make sure to not throw
129 312 int cancel_state;
130 312 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
131 312 void *retval = nullptr;
132
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
✓ Branch 5 taken 305 times.
✓ Branch 6 taken 7 times.
312 if (was_started)
133 305 pthread_join(id, &retval);
134 312 pthread_setcancelstate(cancel_state, nullptr);
135 312 return retval;
136 }
137
138 ////////////////////////////////////////////////////////////////////////////
139 454 void *Thread::start_routine(void *arg)
140 {
141 454 Thread* self = reinterpret_cast<Thread*>(arg);
142
143
2/2
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 304 times.
454 if (self->rt_priority != priority_unset_value) {
144 150 struct sched_param param = {
145 150 .sched_priority = self->rt_priority
146 150 };
147 150 const int err = pthread_setschedparam(self->id, SCHED_FIFO, &param);
148
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 if (err) {
149
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 fprintf(stderr,
150 "Setting SCHED_FIFO with priority %i failed in pdserv"
151 " RT service task: %s\n",
152 param.sched_priority, strerror(err));
153 }
154 }
155
156 // RAII wrapper to run final() in case of pthread_cancel
157 struct ThreadFinalizer
158 {
159 Thread* thread_;
160 454 ThreadFinalizer(Thread* thread) : thread_(thread) {}
161 454 ~ThreadFinalizer()
162 454 {
163 // disable cancelation, because terminate() will
164 // otherwise lead to std::terminate
165 454 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
166 454 thread_->final();
167 454 int state;
168
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 454 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 454 times.
454 pthread_attr_getdetachstate(&thread_->attr, &state);
169
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 305 times.
454 if (state == PTHREAD_CREATE_DETACHED)
170
1/2
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
149 delete thread_;
171 454 }
172 908 } finalizer(self);
173
174 try {
175
2/2
✓ Branch 6 taken 450 times.
✓ Branch 7 taken 4 times.
454 self->initial();
176
2/2
✓ Branch 6 taken 150 times.
✓ Branch 7 taken 300 times.
450 self->run();
177 // don't terminate in case this exception has not been caught
178 } catch (PdServ::Main::RtProcessExited&) {
179
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 } catch (CancelThread const &) {
180 }
181
182
2/3
✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
308 return 0;
183 }
184
185 ////////////////////////////////////////////////////////////////////////////
186 40 void Thread::sleep(int msec)
187 {
188 40 struct timespec delay;
189
190 40 delay.tv_sec = msec / 1000;
191 40 delay.tv_nsec = (msec - delay.tv_sec * 1000) * 1000000;
192
193
3/8
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 40 times.
40 while (::nanosleep(&delay, &delay) and errno == EINTR)
194 ;
195 40 }
196