GCC Code Coverage Report


Directory: src/gate/
File: src/gate/cxx_runnables.cpp
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 109 258 42.2%
Functions: 24 49 49.0%
Branches: 20 79 25.3%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/runnables.hpp"
30
31 namespace gate
32 {
33
34
35
36 10 IRunnableBuilder::~IRunnableBuilder() noexcept
37 {
38 10 }
39
40 5 result_t IRunnableBuilder::runnable_run(void* this_ptr)
41 {
42 5 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
43 5 IRunnableBuilder* obj = getInterface<IRunnableBuilder>(dispatcher);
44 try
45 {
46
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 obj->run();
47 5 return results::Ok;
48 }
49 catch (Throwable const& xcpt)
50 {
51 return xcpt.getResult();
52 }
53 catch (...)
54 {
55 return results::UnknownError;
56 }
57 }
58
59 2 IRunnableBuilder::VtblRunnable::VtblRunnable()
60 {
61 2 obj_vtbl_t* this_ptr = reinterpret_cast<obj_vtbl_t*>(this);
62 2 this_ptr->run = &IRunnableBuilder::runnable_run;
63 2 }
64
65 IRunnableBuilder::VtblRunnable IRunnableBuilder::cpp_vtbl_runnable;
66
67 IRunnableBuilder::IRunnableBuilder(obj_vtbl_t const* vtbl_ptr, char const* name)
68 : object_builder_t(vtbl_ptr, name)
69 {
70 }
71
72 5 IRunnableBuilder::IRunnableBuilder()
73
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 : object_builder_t(&cpp_vtbl_runnable, GATE_INTERFACE_NAME_RUNNABLE)
74 {
75 5 }
76
77
78
79 16 Runnable::~Runnable() noexcept
80 {
81 16 }
82 1 void Runnable::run()
83 {
84
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (this->empty())
85 {
86 GATEXX_RAISE_ERROR(results::NullPointer);
87 }
88 1 gate_result_t result = gate_runnable_run(this->c_impl());
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATEXX_CHECK_EXCEPTION(result);
90 1 }
91
92 5 Runnable::Runnable(gate_runnable_t* ptr_runnable)
93 5 : object_impl_t(ptr_runnable)
94 {
95 5 }
96
97 3 Runnable::Runnable(Runnable const& src)
98 3 : object_impl_t(src)
99 {
100 3 }
101
102 Runnable& Runnable::operator=(Runnable const& src)
103 {
104 object_impl_t::operator=(src);
105 return *this;
106 }
107
108
109
110 2 Task::~Task() noexcept
111 {
112 2 }
113 1 void Task::run()
114 {
115 1 result_t result = gate_task_run(this->c_impl());
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATEXX_CHECK_EXCEPTION(result);
117 1 }
118
119 void Task::cancel()
120 {
121 result_t result = gate_task_cancel(this->c_impl());
122 GATEXX_CHECK_EXCEPTION(result);
123 }
124
125 1 Task::Task(gate_task_t* ptr_task)
126 1 : object_impl_t(ptr_task)
127 {
128 1 }
129 Task::Task(Task const& src)
130 : object_impl_t(src)
131 {
132
133 }
134 Task& Task::operator=(Task const& src)
135 {
136 object_impl_t::operator=(src);
137 return *this;
138 }
139
140 Task::StatusEnum Task::status()
141 {
142 return static_cast<Task::StatusEnum>(gate_task_get_status(this->c_impl()));
143 }
144
145 bool_t Task::completed()
146 {
147 return gate_task_completed(this->c_impl());
148 }
149
150 1 void const* Task::getResult()
151 {
152 1 void const* ptrTaskData = NULL;
153 1 result_t taskResult = results::Failed;
154
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 result_t result = gate_task_get_result(this->c_impl(), &taskResult, &ptrTaskData);
155
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 GATEXX_CHECK_EXCEPTION(result);
156
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 GATEXX_CHECK_EXCEPTION(taskResult);
157 1 return ptrTaskData;
158 }
159
160 void Task::wait()
161 {
162 result_t result = gate_task_wait(this->c_impl());
163 GATEXX_CHECK_EXCEPTION(result);
164 }
165
166 bool Task::waitFor(uint32_t timeoutMs)
167 {
168 result_t result = gate_task_timed_wait(this->c_impl(), timeoutMs);
169 if (GATE_FAILED(result))
170 {
171 if (result == GATE_RESULT_TIMEOUT)
172 {
173 return false;
174 }
175 else
176 {
177 GATEXX_RAISE_EXCEPTION(result, NULL, 0);
178 }
179 }
180 return true;
181 }
182
183
184
185
186 2 ITaskBuilder::~ITaskBuilder() noexcept
187 {
188
189 2 }
190
191 1 result_t ITaskBuilder::task_run(void* this_ptr)
192 {
193 1 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
194 1 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
195 try
196 {
197
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 obj->run();
198 1 return results::Ok;
199 }
200 catch (Throwable const& xcpt)
201 {
202 return xcpt.getResult();
203 }
204 catch (...)
205 {
206 return results::UnknownError;
207 }
208 }
209 result_t ITaskBuilder::task_cancel(void* this_ptr)
210 {
211 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
212 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
213 try
214 {
215 obj->cancel();
216 return results::Ok;
217 }
218 catch (Throwable const& xcpt)
219 {
220 return xcpt.getResult();
221 }
222 catch (...)
223 {
224 return results::UnknownError;
225 }
226 }
227 int ITaskBuilder::task_get_status(void* this_ptr)
228 {
229 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
230 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
231 return static_cast<int>(obj->status());
232 }
233 gate_bool_t ITaskBuilder::task_completed(void* this_ptr)
234 {
235 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
236 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
237 return static_cast<int>(obj->completed());
238
239 }
240 1 gate_result_t ITaskBuilder::task_get_result(void* this_ptr, gate_result_t* ptr_task_result, void const** ptr_task_data)
241 {
242 1 result_t ret = results::Ok;
243 1 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
244 1 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
245
246 1 result_t taskResult = results::Failed;
247 1 void const* taskData = NULL;
248
249 1 Task::StatusEnum status = obj->status();
250
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (status)
251 {
252 case Task::Status_Prepared:
253 case Task::Status_Running:
254 {
255 taskResult = results::InvalidState;
256 break;
257 }
258 1 case Task::Status_Completed:
259 {
260 try
261 {
262
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 taskData = obj->getResult();
263 1 taskResult = results::Ok;
264 }
265 catch (Throwable const& xcpt)
266 {
267 taskResult = xcpt.getResult();
268 }
269 catch (...)
270 {
271 taskResult = results::UnknownError;
272 }
273 1 ret = results::Ok;
274 1 break;
275 }
276 case Task::Status_Canceled:
277 {
278 taskResult = results::Canceled;
279 ret = results::Ok;
280 break;
281 }
282 case Task::Status_Failed:
283 {
284 taskResult = results::Failed;
285 ret = results::Ok;
286 break;
287 }
288 }
289
290
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_task_result)
291 {
292 1 *ptr_task_result = taskResult;
293 }
294
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_task_data)
295 {
296 1 *ptr_task_data = taskData;
297 }
298
299 1 return ret;
300 }
301 gate_result_t ITaskBuilder::task_wait(void* this_ptr)
302 {
303 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
304 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
305 try
306 {
307 obj->wait();
308 return results::Ok;
309 }
310 catch (Throwable const& xcpt)
311 {
312 return xcpt.getResult();
313 }
314 catch (...)
315 {
316 return results::UnknownError;
317 }
318 }
319 gate_result_t ITaskBuilder::task_timed_wait(void* this_ptr, gate_uint32_t timeout_ms)
320 {
321 cpp_object* dispatcher = static_cast<cpp_object*>(this_ptr);
322 ITaskBuilder* obj = getInterface<ITaskBuilder>(dispatcher);
323 try
324 {
325 bool_t signaled = obj->waitFor(timeout_ms);
326 if (signaled)
327 {
328 return results::Ok;
329 }
330 else
331 {
332 return results::Timeout;
333 }
334 }
335 catch (Throwable const& xcpt)
336 {
337 return xcpt.getResult();
338 }
339 catch (...)
340 {
341 return results::UnknownError;
342 }
343 }
344
345 2 ITaskBuilder::VtblTask::VtblTask()
346 {
347 2 obj_vtbl_t* this_ptr = reinterpret_cast<obj_vtbl_t*>(this);
348 2 this_ptr->run = &ITaskBuilder::task_run;
349 2 this_ptr->cancel = ITaskBuilder::task_cancel;
350 2 this_ptr->get_status = ITaskBuilder::task_get_status;
351 2 this_ptr->completed = ITaskBuilder::task_completed;
352 2 this_ptr->get_result = ITaskBuilder::task_get_result;
353 2 this_ptr->wait = ITaskBuilder::task_wait;
354 2 this_ptr->timed_wait = ITaskBuilder::task_timed_wait;
355 2 }
356
357 ITaskBuilder::VtblTask ITaskBuilder::cpp_vtbl_task;
358
359 ITaskBuilder::ITaskBuilder(obj_vtbl_t const* vtbl_ptr, char const* name)
360 : object_builder_t(vtbl_ptr, name)
361 {
362 }
363 1 ITaskBuilder::ITaskBuilder()
364
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 : object_builder_t(&cpp_vtbl_task, GATE_INTERFACE_NAME_TASK)
365 {
366 1 }
367
368
369
370
371 1 ITaskBase::ITaskBase()
372 : statusvalue(static_cast<int32_t>(Task::Status_Prepared)),
373 completionsignal(false),
374 taskResult(results::Ok),
375
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 taskData(NULL)
376 {
377 1 }
378
379 2 ITaskBase::~ITaskBase() noexcept
380 {
381 2 }
382
383 void ITaskBase::runImpl()
384 {
385 }
386 void ITaskBase::cancelImpl()
387 {
388 }
389
390 2 static bool_t updateTaskStatus(AtomicInt& status, Task::StatusEnum fromStatus, Task::StatusEnum toStatus)
391 {
392 2 int32_t oldStatus = status.changeIf(static_cast<int32_t>(fromStatus), static_cast<int32_t>(toStatus));
393 2 return oldStatus == static_cast<int32_t>(fromStatus);
394 }
395
396 1 void ITaskBase::run()
397 {
398
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!updateTaskStatus(this->statusvalue, Task::Status_Prepared, Task::Status_Running))
399 {
400 GATEXX_RAISE_EXCEPTION(results::InvalidState, "Cannot start task", 0);
401 }
402
403 1 Task::StatusEnum nextStatus = Task::Status_Completed;
404 1 result_t nextTaskResult = results::Ok;
405
406 try
407 {
408
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 this->runImpl();
409 }
410 catch (Throwable const& xcpt)
411 {
412 nextStatus = Task::Status_Failed;
413 nextTaskResult = xcpt.getResult();
414 }
415 catch (...)
416 {
417 nextStatus = Task::Status_Failed;
418 nextTaskResult = results::UnknownException;
419 }
420
421
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (updateTaskStatus(this->statusvalue, Task::Status_Running, nextStatus))
422 {
423 1 this->taskResult = nextTaskResult;
424 1 this->completionsignal.set();
425 }
426 1 }
427
428 1 void ITaskBase::setTaskData(void const* data)
429 {
430 1 this->taskData = data;
431 1 }
432
433
434 void ITaskBase::cancel()
435 {
436 if (updateTaskStatus(this->statusvalue, Task::Status_Prepared, Task::Status_Canceled))
437 {
438 this->completionsignal.set();
439 }
440 else if (updateTaskStatus(this->statusvalue, Task::Status_Running, Task::Status_Canceled))
441 {
442 try
443 {
444 this->cancelImpl();
445 }
446 catch (...) {}
447 this->completionsignal.set();
448 }
449 else
450 {
451 GATEXX_RAISE_EXCEPTION(results::InvalidState, "Cannot cancel task", 0);
452 }
453 }
454 1 Task::StatusEnum ITaskBase::status()
455 {
456 1 return static_cast<Task::StatusEnum>(this->statusvalue.get());
457 }
458 bool_t ITaskBase::completed()
459 {
460 Task::StatusEnum state = static_cast<Task::StatusEnum>(this->statusvalue.get());
461 switch (state)
462 {
463 case Task::Status_Completed:
464 case Task::Status_Canceled:
465 case Task::Status_Failed:
466 {
467 return true;
468 }
469 default:
470 {
471 break;
472 }
473 }
474 return false;
475 }
476 1 void const* ITaskBase::getResult()
477 {
478 1 Task::StatusEnum state = static_cast<Task::StatusEnum>(this->statusvalue.get());
479
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (state)
480 {
481 1 case Task::Status_Completed:
482 {
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(this->taskResult))
484 {
485 GATEXX_RAISE_EXCEPTION(this->taskResult, "Task execution failed", 0);
486 }
487 else
488 {
489 1 return this->taskData;
490 }
491 break;
492 }
493 case Task::Status_Canceled:
494 {
495 GATEXX_RAISE_EXCEPTION(results::Canceled, "Task canceled", 0);
496 break;
497 }
498 case Task::Status_Failed:
499 {
500 GATEXX_RAISE_EXCEPTION(this->taskResult, "Task execution failed", 0);
501 break;
502 }
503 default:
504 {
505 GATEXX_RAISE_EXCEPTION(results::InvalidState, "Task not completed", 0);
506 break;
507 }
508 }
509 return NULL;
510 }
511 void ITaskBase::wait()
512 {
513 this->completionsignal.wait();
514 }
515 bool ITaskBase::waitFor(uint32_t timeoutMs)
516 {
517 return this->completionsignal.waitFor(timeoutMs);
518 }
519
520
521
522 class GATE_API_LOCAL TaskRunnableDispatcher : public ITaskBase
523 {
524 private:
525 Runnable runner;
526
527 public:
528 TaskRunnableDispatcher(Runnable const& runnable) : runner(runnable)
529 {
530 }
531 virtual ~TaskRunnableDispatcher() noexcept {}
532 virtual void runImpl()
533 {
534 this->runner.run();
535 }
536 };
537
538 Task TaskBuilder::create(Runnable const& runnable)
539 {
540 ITaskBase* ptr_task = new TaskRunnableDispatcher(runnable);
541 return Task(ptr_task->c_impl());
542 }
543
544
545 } // end of namespace gate
546