GCC Code Coverage Report


Directory: ./
File: pdserv/src/PThread.cpp
Date: 2023-11-12 04:06:57
Exec Total Coverage
Lines: 79 82 96.3%
Branches: 43 75 57.3%

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 931 RWLock::RWLock()
37 {
38 931 pthread_rwlockattr_t attr;
39
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 931 times.
931 pthread_rwlockattr_init(&attr);
41
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 931 times.
931 pthread_rwlock_init(&lock, &attr);
42
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 931 times.
931 pthread_rwlockattr_destroy(&attr);
43 931 }
44
45 ////////////////////////////////////////////////////////////////////////////
46 1862 RWLock::~RWLock()
47 {
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 931 times.
931 pthread_rwlock_destroy(&lock);
49 931 }
50
51 ////////////////////////////////////////////////////////////////////////////
52 ////////////////////////////////////////////////////////////////////////////
53 789 Mutex::Mutex()
54 {
55 789 pthread_mutexattr_t attr;
56
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 789 times.
789 pthread_mutexattr_init(&attr);
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 789 times.
789 pthread_mutex_init(&mutex, &attr);
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 789 times.
789 pthread_mutexattr_destroy(&attr);
60 789 }
61
62 ////////////////////////////////////////////////////////////////////////////
63 1578 Mutex::~Mutex()
64 {
65
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 789 times.
789 pthread_mutex_destroy(&mutex);
66 789 }
67
68 ////////////////////////////////////////////////////////////////////////////
69 ////////////////////////////////////////////////////////////////////////////
70 387 Thread::Thread()
71 {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
387 pthread_attr_init(&attr);
73 387 }
74
75 ////////////////////////////////////////////////////////////////////////////
76 774 Thread::~Thread()
77 {
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
387 pthread_attr_destroy(&attr);
79 387 }
80
81 ////////////////////////////////////////////////////////////////////////////
82 126 void Thread::set_priority(int prio)
83 {
84
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 if (prio > priority_unset_value) {
85 126 rt_priority = prio;
86 }
87 else {
88 rt_priority = priority_unset_value;
89 }
90 126 }
91
92 ////////////////////////////////////////////////////////////////////////////
93 380 int Thread::start()
94 {
95
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 380 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 380 times.
380 if (was_started)
96 return 0;
97
98
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 380 times.
380 const int ans = pthread_create(&id, &attr, &start_routine, this);
99
1/2
✓ Branch 0 taken 380 times.
✗ Branch 1 not taken.
380 if (ans == 0)
100 380 was_started = true;
101 380 return ans;
102 }
103
104 ////////////////////////////////////////////////////////////////////////////
105 124 int Thread::detach()
106 {
107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
108 124 return start();
109 }
110
111 ////////////////////////////////////////////////////////////////////////////
112 263 void Thread::terminate() noexcept
113 {
114
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 263 times.
✓ Branch 5 taken 256 times.
✓ Branch 6 taken 7 times.
263 if (was_started)
115 256 pthread_cancel(id);
116 263 }
117
118 ////////////////////////////////////////////////////////////////////////////
119 263 void *Thread::join() noexcept
120 {
121 // join() may be called in a dtor, so make sure to not throw
122 263 int cancel_state;
123 263 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
124 263 void *retval = nullptr;
125
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 263 times.
✓ Branch 5 taken 256 times.
✓ Branch 6 taken 7 times.
263 if (was_started)
126 256 pthread_join(id, &retval);
127 263 pthread_setcancelstate(cancel_state, nullptr);
128 263 return retval;
129 }
130
131 ////////////////////////////////////////////////////////////////////////////
132 380 void *Thread::start_routine(void *arg)
133 {
134 380 Thread* self = reinterpret_cast<Thread*>(arg);
135
136
2/2
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 254 times.
380 if (self->rt_priority != priority_unset_value) {
137 126 struct sched_param param = {
138 126 .sched_priority = self->rt_priority
139 126 };
140 126 const int err = pthread_setschedparam(self->id, SCHED_FIFO, &param);
141
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 if (err) {
142
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
126 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 380 ThreadFinalizer(Thread* thread) : thread_(thread) {}
154 380 ~ThreadFinalizer()
155 380 {
156 // disable cancelation, because terminate() will
157 // otherwise lead to std::terminate
158 380 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
159 380 thread_->final();
160 380 int state;
161
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 380 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 380 times.
380 pthread_attr_getdetachstate(&thread_->attr, &state);
162
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 256 times.
380 if (state == PTHREAD_CREATE_DETACHED)
163
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 delete thread_;
164 380 }
165 760 } finalizer(self);
166
167 try {
168
2/2
✓ Branch 6 taken 376 times.
✓ Branch 7 taken 4 times.
380 self->initial();
169
2/2
✓ Branch 6 taken 125 times.
✓ Branch 7 taken 251 times.
376 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 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
258 return 0;
176 }
177
178 ////////////////////////////////////////////////////////////////////////////
179 28 void Thread::sleep(int msec)
180 {
181 28 struct timespec delay;
182
183 28 delay.tv_sec = msec / 1000;
184 28 delay.tv_nsec = (msec - delay.tv_sec * 1000) * 1000000;
185
186
3/8
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 28 times.
28 while (::nanosleep(&delay, &delay) and errno == EINTR)
187 ;
188 28 }
189