GCC Code Coverage Report


Directory: ./
File: pdserv-1.1.0/src/lib/Task.cpp
Date: 2024-12-01 04:08:21
Exec Total Coverage
Lines: 117 216 54.2%
Branches: 38 105 36.2%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright 2010 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 "../Debug.h"
25
26 #include <algorithm>
27 #include <numeric>
28
29 #include "ShmemDataStructures.h"
30 #include "SessionTaskData.h"
31 #include "../SessionTask.h"
32 #include "Task.h"
33 #include "Signal.h"
34 #include "Pointer.h"
35
36 /////////////////////////////////////////////////////////////////////////////
37 // Data structures used in Task
38 /////////////////////////////////////////////////////////////////////////////
39 struct CopyList {
40 const Signal *signal;
41 const char *src;
42 size_t len;
43 };
44
45 struct SignalList {
46 enum {Insert = 1, Remove} action;
47 unsigned int signalListId;
48 unsigned int signalPosition;
49 const Signal* signal;
50 };
51
52 struct PollData {
53 unsigned int request, reply;
54 bool active;
55 struct timespec time;
56 unsigned int count;
57 unsigned int length;
58 const char *addr;
59 struct Data {
60 void *dest;
61 const Signal *signal;
62 } data[];
63 };
64
65 /////////////////////////////////////////////////////////////////////////////
66 /////////////////////////////////////////////////////////////////////////////
67 20 Task::Task(Main *main, double ts, const char * /*name*/):
68
1/2
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
20 PdServ::Task(ts), main(main), mutex(1)
69 {
70 20 seqNo = 0;
71 20 signalMemSize = 0;
72 20 signalPosition = 0;
73 20 signalListId = 0;
74
1/2
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
20 std::fill_n(signalTypeCount, 4, 0);
75 20 signalCopyList[0] = 0;
76 20 copyList[0] = 0;
77 20 }
78
79 /////////////////////////////////////////////////////////////////////////////
80 Task::~Task()
81 {
82 delete copyList[0];
83 delete signalCopyList[0];
84 delete signalPosition;
85
86 for (Signals::iterator it = signals.begin(); it != signals.end(); ++it)
87 delete *it;
88 }
89
90 /////////////////////////////////////////////////////////////////////////////
91 20 size_t Task::getShmemSpace(double T) const
92 {
93 20 size_t n = signals.size();
94 20 size_t minPdoCount = (size_t)(T / sampleTime + 0.5);
95
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (minPdoCount < 10)
97 minPdoCount = 10;
98
99 return sizeof(*signalListRp) + sizeof(*signalListWp)
100 + sizeof(*poll) + n*sizeof(*poll->data)
101 + 2 * n * sizeof(*signalList)
102 20 + (sizeof(*txPdo) + signalMemSize) * minPdoCount;
103 }
104
105 /////////////////////////////////////////////////////////////////////////////
106 SessionTaskData* Task::newSession(PdServ::Session * /*session*/)
107 {
108 return 0; //new SessionTaskData(session, this, txMemBegin, txMemEnd);
109 }
110
111 /////////////////////////////////////////////////////////////////////////////
112 20 void Task::prepare(void *shmem, void *shmem_end)
113 {
114 log_debug("S(%p): shmem=%p shmem_end=%p", this, shmem, shmem_end);
115 20 size_t n = signals.size();
116
117 20 signalListRp = ptr_align<struct SignalList*>(shmem);
118 20 signalListWp = signalListRp + 1;
119 20 signalList = ptr_align<struct SignalList>(signalListWp + 1);
120 20 signalListEnd = signalList + (2*n);
121 20 *signalListRp = signalList;
122 20 *signalListWp = signalList;
123
124 20 poll = ptr_align<struct PollData>(signalListEnd);
125
126 20 txMemBegin = ptr_align<struct Pdo>(poll->data + n);
127 20 txMemEnd = shmem_end;
128 log_debug("S(%p): txMemBegin=%p", this, txMemBegin);
129 // cerr_debug() << "signallen=" << signalMemSize << " txpdosize="
130 // << sizeof(*txPdo) << " space="
131 // << ((const char*)txMemEnd - (const char *)txMemBegin);
132
133 20 txPdo = txMemBegin;
134 20 nextTxPdo = ptr_align<struct Pdo*>(shmem_end) - 2;
135 20 }
136
137 /////////////////////////////////////////////////////////////////////////////
138 20 void Task::rt_init()
139 {
140 20 signalMemSize = 0;
141
142
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 copyList[0] = new struct CopyList[signals.size() + 4];
143
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 20 times.
80 for (size_t i = 0; i < 3; i++)
144 60 copyList[i+1] = copyList[i] + signalTypeCount[i] + 1;
145
146
1/2
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
20 std::fill_n(signalTypeCount, 4, 0);
147
148 // Clear src field which is end-of-list marker
149
2/2
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 20 times.
160 for (size_t i = 0; i < signals.size() + 4; ++i)
150 140 copyList[0][i].src = 0;
151 20 }
152
153 /////////////////////////////////////////////////////////////////////////////
154 void Task::nrt_init()
155 {
156 signalVector.resize(signals.size());
157 for (Signals::const_iterator it = signals.begin();
158 it != signals.end(); ++it) {
159 const Signal *s = static_cast<const Signal*>(*it);
160 signalVector[s->index] = s;
161 }
162
163 signalPosition = new unsigned int[signals.size()];
164
165 signalCopyList[0] = new const Signal*[signals.size()];
166 for (size_t i = 0; i < 3; i++)
167 signalCopyList[i+1] = signalCopyList[i] + signalTypeCount[i];
168
169 std::fill_n(signalTypeCount, 4, 0);
170 }
171
172 /////////////////////////////////////////////////////////////////////////////
173 60 Signal* Task::addSignal( unsigned int decimation,
174 const char *path, const PdServ::DataType& datatype,
175 const void *addr, size_t n, const size_t *dim)
176 {
177 60 Signal *s = new Signal(this, signals.size(),
178
1/2
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
60 decimation, path, datatype, addr, n, dim);
179
180
1/2
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
60 signals.push_back(s);
181 60 signalTypeCount[s->dataTypeIndex[s->dtype.align()]]++;
182 60 signalMemSize += s->memSize;
183
184 60 return s;
185 }
186
187 /////////////////////////////////////////////////////////////////////////////
188 size_t Task::signalCount() const
189 {
190 return signals.size();
191 }
192
193 /////////////////////////////////////////////////////////////////////////////
194 void Task::getSignalList(const Signal **signalList, size_t *nelem,
195 unsigned int *signalListId) const
196 {
197 ost::SemaphoreLock lock(mutex);
198
199 for (unsigned int i = 0; i < 4; ++i)
200 for (unsigned int j = 0; j < signalTypeCount[i]; ++j)
201 *signalList++ = signalCopyList[i][j];
202 *nelem = std::accumulate(signalTypeCount, signalTypeCount + 4, 0);
203 *signalListId = (*signalListWp)->signalListId;
204 }
205
206 /////////////////////////////////////////////////////////////////////////////
207 void Task::subscribe(const Signal* s, bool insert) const
208 {
209 ost::SemaphoreLock lock(mutex);
210 struct SignalList *wp = *signalListWp;
211
212 if (++wp == signalListEnd)
213 wp = signalList;
214
215 while (wp == *signalListRp)
216 ost::Thread::sleep(static_cast<unsigned>(sampleTime * 1000 / 2 + 1));
217
218 //log_debug("%i %s", insert, s->path.c_str());
219
220 size_t w = s->dataTypeIndex[s->dtype.align()];
221 const Signal **scl = signalCopyList[w];
222
223 wp->signal = s;
224
225 if (insert) {
226
227 wp->action = SignalList::Insert;
228
229 size_t i = signalTypeCount[w]++;
230 scl[i] = s;
231 signalPosition[s->index] = i;
232
233 // log_debug("insert %s @ %zu[%zu]", s->path.c_str(), w, i);
234 // debug() << "insert" << s->path << w << i << (void*)signalCopyList[w];
235 }
236 else {
237 size_t pos = signalPosition[s->index];
238
239 // log_debug("erase %s @ %zu", s->path.c_str(), pos);
240
241 wp->action = SignalList::Remove;
242 wp->signalPosition = pos;
243
244 // Replace s with last signal on the list
245 s = scl[--signalTypeCount[w]];
246 scl[pos] = s;
247 signalPosition[s->index] = pos;
248
249 // debug() << "erase" << s->path << w << signalPosition[s->index]
250 // << "copy("
251 // << (void*)(signalCopyList[w])
252 // << signalPosition[s->index] + 1
253 // << signalTypeCount[w]
254 // << signalPosition[s->index];
255 }
256
257 wp->signalListId = ++signalListId;
258 // cout << __func__ << s->index << ' ' << insert
259 // << " pos=" << wp->signalPosition << endl;
260
261 *signalListWp = wp;
262 }
263
264 /////////////////////////////////////////////////////////////////////////////
265 void Task::pollPrepare( const Signal *signal, void *dest) const
266 {
267 poll->data[poll->count].dest = dest;
268 poll->data[poll->count].signal = signal;
269 poll->length += signal->memSize;
270 poll->count++;
271 }
272
273 /////////////////////////////////////////////////////////////////////////////
274 bool Task::pollFinished( const PdServ::Signal * const *, size_t /*nelem*/,
275 void * const *, struct timespec *t) const
276 {
277 if (!poll->count)
278 return true;
279
280 if (!poll->active) {
281 poll->active = true;
282 poll->request++;
283 return false;
284 }
285
286 if (poll->request != poll->reply)
287 return false;
288
289 const char *buf = poll->addr;
290 for (size_t i = 0; i < poll->count; ++i) {
291 const Signal *s = poll->data[i].signal;
292 std::copy(buf, buf + s->memSize,
293 reinterpret_cast<char*>(poll->data[i].dest));
294 buf += s->memSize;
295 }
296
297 poll->active = false;
298 poll->count = 0;
299 poll->length = 0;
300 if (t)
301 *t = poll->time;
302
303 return true;
304 }
305
306 /////////////////////////////////////////////////////////////////////////////
307 void Task::updateStatistics(
308 double exec_time, double cycle_time, unsigned int overrun)
309 {
310 taskStatistics.exec_time = exec_time;
311 taskStatistics.cycle_time = cycle_time;
312 taskStatistics.overrun = overrun;
313 }
314
315 /////////////////////////////////////////////////////////////////////////////
316 1309 void Task::update(const struct timespec *t)
317 {
318
2/2
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1305 times.
1309 if (poll->request != poll->reply) {
319
1/2
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
4 if (&txPdo->data + poll->length >= txMemEnd) {
320 txPdo = txMemBegin;
321 txPdo->type = Pdo::Empty;
322 txPdo->next = 0;
323 }
324
325 4 char *dst = &txPdo->data;
326
327
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (t)
328 4 poll->time = *t;
329 else
330 poll->time.tv_sec = poll->time.tv_nsec = 0;
331
332 4 poll->addr = dst;
333
334
2/2
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
8 for (size_t i = 0; i < poll->count; ++i) {
335 4 const Signal *s = poll->data[i].signal;
336 4 std::copy(s->addr, s->addr + s->memSize, dst);
337 4 dst += s->memSize;
338 }
339
340 4 txPdo = ptr_align<Pdo>(dst);
341
342
1/2
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
4 if (poll->addr == &txMemBegin->data) {
343 txPdo->next = 0;
344 txPdo->type = Pdo::Empty;
345 txMemBegin->next = txPdo;
346 }
347
348 4 poll->reply = poll->request;
349 //log_debug("S(%p): poll", this);
350 }
351
352 1309 struct SignalList *sp = 0;
353
354
2/2
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1309 times.
1317 while (*signalListRp != *signalListWp) {
355 4 sp = *signalListRp + 1;
356
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (sp == signalListEnd)
357 sp = signalList;
358
359 4 signalListId = sp->signalListId;
360 4 const Signal *signal = sp->signal;
361 4 size_t w = signal->dataTypeIndex[signal->dtype.align()];
362 struct CopyList *cl;
363 // cout << "Signal " << signal->index << " pos=" << sp->signalPosition;
364
365
3/5
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
4 switch (sp->action) {
366 3 case SignalList::Insert:
367 // Insert the signal at list end
368 // log_debug("RT insert %s @ %zu", signal->path.c_str(),
369 // signalTypeCount[w]);
370
371 3 cl = copyList[w] + signalTypeCount[w]++;
372
373 3 cl->src = signal->addr;
374 3 cl->len = signal->memSize;
375 3 cl->signal = signal;
376
377 3 signalMemSize += signal->memSize;
378
379
380 // cout << " added" << endl;
381 3 break;
382
383 1 case SignalList::Remove:
384 // Move signal at list end to the deleted position
385 1 cl = copyList[w] + --signalTypeCount[w];
386 1 copyList[w][sp->signalPosition] = *cl;
387 1 cl->src = 0; // End of copy list indicator
388
389 1 signalMemSize -= signal->memSize;
390
391 // log_debug("RT remove %s @ %zu", signal->path.c_str(),
392 // signalTypeCount[w]);
393
394 // cout << " removed" << endl;
395 1 break;
396 }
397
398 4 *signalListRp = sp;
399 }
400 // cout << sp << endl;
401
402
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1305 times.
1309 if (sp) {
403 4 size_t n = std::accumulate(signalTypeCount, signalTypeCount + 4, 0);
404 // cout << "New signals " << n << ' ' << "signalMemSize=" << signalMemSize;
405
406
1/2
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
4 if ((&txPdo->signalIdx + n) >= txMemEnd)
407 txPdo = txMemBegin;
408
409 4 txPdo->next = 0;
410 4 txPdo->type = Pdo::Empty;
411 4 txPdo->signalListId = signalListId;
412 4 txPdo->count = n;
413 4 size_t *sp = &txPdo->signalIdx;
414
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 for (int i = 0; i < 4; i++) {
415
2/2
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 16 times.
21 for (CopyList *cl = copyList[i]; cl->src; ++cl)
416 5 *sp++ = cl->signal->index;
417 }
418 4 txPdo->type = Pdo::SignalList;
419 // cout << endl;
420
421 4 *nextTxPdo = txPdo;
422
423 //log_debug("S(%p): TxPdo=%p (signalList)<- %p", this, txPdo, nextTxPdo);
424
425 4 nextTxPdo = &txPdo->next;
426 4 txPdo = ptr_align<Pdo>(sp);
427 }
428
429
2/2
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 1304 times.
1309 if ( &txPdo->data + signalMemSize >= txMemEnd) {
430 5 txPdo = txMemBegin;
431 // cout << "wrap" << endl;
432 }
433
434 1309 txPdo->next = 0;
435 1309 txPdo->type = Pdo::Empty;
436 1309 txPdo->signalListId = signalListId;
437 1309 txPdo->seqNo = seqNo++;
438
439 1309 txPdo->taskStatistics = taskStatistics;
440
441
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 if (t) {
442 1309 txPdo->time = *t;
443 }
444 else
445 txPdo->time.tv_sec = txPdo->time.tv_nsec = 0;
446
447 1309 char *p = &txPdo->data;
448
2/2
✓ Branch 0 taken 5236 times.
✓ Branch 1 taken 1309 times.
6545 for (int i = 0; i < 4; ++i) {
449 // cout << i << ": ";
450
2/2
✓ Branch 5 taken 1328 times.
✓ Branch 6 taken 5236 times.
6564 for (CopyList *cl = copyList[i]; cl->src; ++cl) {
451 1328 std::copy(cl->src, cl->src + cl->len, p);
452 1328 p += cl->len;
453 // cout << cl->signal->index << ' ' << cl->len << ' ';
454 }
455 }
456 1309 txPdo->type = Pdo::Data;
457 // cout << '=' << p - txPdo->data << endl;
458
459 1309 txPdo->count = p - &txPdo->data;
460 1309 *nextTxPdo = txPdo;
461
462 //log_debug("S(%p): TxPdo=%p<-%p", this, txPdo, nextTxPdo);
463 1309 nextTxPdo = &txPdo->next;
464 1309 txPdo = ptr_align<Pdo>(p);
465 1309 }
466
467 /////////////////////////////////////////////////////////////////////////////
468 void Task::prepare (PdServ::SessionTask *s) const
469 {
470 s->sessionTaskData =
471 new SessionTaskData(s, this, signalVector, txMemBegin, txMemEnd);
472 }
473
474 /////////////////////////////////////////////////////////////////////////////
475 void Task::cleanup (const PdServ::SessionTask *s) const
476 {
477 delete s->sessionTaskData;
478 }
479
480 /////////////////////////////////////////////////////////////////////////////
481 bool Task::rxPdo (PdServ::SessionTask *s, const struct timespec **time,
482 const PdServ::TaskStatistics **stat) const
483 {
484 return s->sessionTaskData->rxPdo(time, stat);
485 3 }
486