GCC Code Coverage Report


Directory: ./
File: pdserv/src/PThread.cpp
Date: 2025-07-20 04:11:05
Exec Total Coverage
Lines: 82 87 94.3%
Branches: 46 83 55.4%

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 933 Mutex::Mutex()
52 {
53 933 pthread_mutexattr_t attr;
54
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 pthread_mutexattr_init(&attr);
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 pthread_mutex_init(&mutex, &attr);
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 pthread_mutexattr_destroy(&attr);
58 933 }
59
60 ////////////////////////////////////////////////////////////////////////////
61 1866 Mutex::~Mutex()
62 {
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 pthread_mutex_destroy(&mutex);
64 933 }
65
66 ////////////////////////////////////////////////////////////////////////////
67 ////////////////////////////////////////////////////////////////////////////
68 459 Thread::Thread(const std::string &name):
69 459 name(name)
70 {
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
459 pthread_attr_init(&attr);
72 459 }
73
74 ////////////////////////////////////////////////////////////////////////////
75 918 Thread::~Thread()
76 {
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
459 pthread_attr_destroy(&attr);
78 459 }
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 452 int Thread::start()
93 {
94
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 452 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 452 times.
452 if (was_started)
95 return 0;
96
97
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 452 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 452 times.
452 const int ans = pthread_create(&id, &attr, &start_routine, this);
98
1/2
✓ Branch 0 taken 452 times.
✗ Branch 1 not taken.
452 if (ans == 0) {
99 452 was_started = true;
100
101
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 452 times.
452 int ret = pthread_setname_np(id, name.c_str());
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 452 times.
452 if (ret) {
103 fprintf(stderr, "Failed to set thread name to %s: %s\n",
104 name.c_str(),
105 strerror(ret));
106 }
107 }
108 452 return ans;
109 }
110
111 ////////////////////////////////////////////////////////////////////////////
112 148 int Thread::detach()
113 {
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
115 148 return start();
116 }
117
118 ////////////////////////////////////////////////////////////////////////////
119 311 void Thread::terminate() noexcept
120 {
121
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 311 times.
✓ Branch 5 taken 304 times.
✓ Branch 6 taken 7 times.
311 if (was_started)
122 304 pthread_cancel(id);
123 311 }
124
125 ////////////////////////////////////////////////////////////////////////////
126 311 void *Thread::join() noexcept
127 {
128 // join() may be called in a dtor, so make sure to not throw
129 311 int cancel_state;
130 311 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
131 311 void *retval = nullptr;
132
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 311 times.
✓ Branch 5 taken 304 times.
✓ Branch 6 taken 7 times.
311 if (was_started)
133 304 pthread_join(id, &retval);
134 311 pthread_setcancelstate(cancel_state, nullptr);
135 311 return retval;
136 }
137
138 ////////////////////////////////////////////////////////////////////////////
139 452 void *Thread::start_routine(void *arg)
140 {
141 452 Thread* self = reinterpret_cast<Thread*>(arg);
142
143
2/2
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 302 times.
452 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
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 2 times.
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 450 ThreadFinalizer(Thread* thread) : thread_(thread) {}
161 450 ~ThreadFinalizer()
162 450 {
163 // disable cancelation, because terminate() will
164 // otherwise lead to std::terminate
165 450 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
166 450 thread_->final();
167 450 int state;
168
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 450 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 450 times.
450 pthread_attr_getdetachstate(&thread_->attr, &state);
169
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 302 times.
450 if (state == PTHREAD_CREATE_DETACHED)
170
1/2
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
148 delete thread_;
171 450 }
172 900 } finalizer(self);
173
174 try {
175
2/2
✓ Branch 6 taken 446 times.
✓ Branch 7 taken 4 times.
450 self->initial();
176
2/2
✓ Branch 6 taken 149 times.
✓ Branch 7 taken 297 times.
446 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 297 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
306 return 0;
183 }
184
185 ////////////////////////////////////////////////////////////////////////////
186 39 void Thread::sleep(int msec)
187 {
188 39 struct timespec delay;
189
190 39 delay.tv_sec = msec / 1000;
191 39 delay.tv_nsec = (msec - delay.tv_sec * 1000) * 1000000;
192
193
3/8
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 39 times.
39 while (::nanosleep(&delay, &delay) and errno == EINTR)
194 ;
195 39 }
196