GCC Code Coverage Report


Directory: ./
File: pdserv/src/PThread.cpp
Date: 2024-12-15 04:08:34
Exec Total Coverage
Lines: 79 82 96.3%
Branches: 44 75 58.7%

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