GCC Code Coverage Report


Directory: src/gate/
File: src/gate/threading.hpp
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 3 3 100.0%
Functions: 1 1 100.0%
Branches: 4 8 50.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, 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 /** @file
30 * @brief Threads and Thread-related objects
31 * @ingroup gatecore_cpp
32 */
33
34
35 #ifndef GATE_THREADING_HPP_INCLUDED
36 #define GATE_THREADING_HPP_INCLUDED
37
38 #include "gate/gate_core_api.hpp"
39 #include "gate/gatetypes.hpp"
40 #include "gate/exceptions.hpp"
41 #include "gate/memalloc.hpp"
42 #include "gate/threading.h"
43 #include "gate/wrappers.hpp"
44 #include "gate/runnables.hpp"
45
46
47 namespace gate
48 {
49
50 class GATE_CORE_CPP_API ThisThread
51 {
52 public:
53 typedef ::gate_thread_id_t id_t;
54 typedef ::gate_thread_t handle_t;
55
56 static handle_t self(id_t* ptr_id = 0);
57 static void sleep(uint32_t milliseconds);
58 static void yield();
59 static void yieldIfPreemptive();
60
61 enum ModelEnum
62 {
63 Model_None = GATE_THREAD_MODEL_NONE,
64 Model_Manual = GATE_THREAD_MODEL_MANUAL,
65 Model_Native = GATE_THREAD_MODEL_NATIVE
66 };
67 static ModelEnum supportedModel();
68 };
69
70
71 /// @brief
72 class GATE_CORE_CPP_API Thread : private NonCopyable
73 {
74 public:
75 typedef ::gate_thread_t handle_t;
76 typedef ::gate_thread_id_t id_t;
77
78 Thread();
79 ~Thread() noexcept;
80
81 id_t start(gate_runnable_t* executor);
82 id_t start(IRunnable& code);
83 id_t start(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param);
84
85 Result<id_t> tryStart(gate_runnable_t* executor) noexcept;
86 Result<id_t> tryStart(IRunnable& code) noexcept;
87 Result<id_t> tryStart(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param) noexcept;
88
89 void release() noexcept;
90 result_t join();
91 Result<result_t> tryJoin() noexcept;
92
93 private:
94 handle_t* ptrhandle;
95 handle_t handle;
96
97 id_t startDispatcher(IRunnableBuilder* methodRunnerPtr);
98
99 public: /* type-generic thread starters */
100 template<class F>
101 struct FunctorDispatcher
102 {
103 private:
104 F functor;
105
106 static result_t f_dispatcher(void* ptr_f)
107 {
108 F& ref_functor = *static_cast<F*>(ptr_f);
109 ref_functor();
110 return results::Ok;
111 }
112 public:
113 typedef FunctorDispatcher<F> self_t;
114
115 FunctorDispatcher(F func)
116 : functor(func)
117 {
118 }
119
120 FunctorDispatcher(self_t const& src)
121 : functor(src.functor)
122 {
123 }
124
125 static gate_result_t dispatch_functor(void* data_ptr)
126 {
127 gate_result_t ret = GATE_RESULT_FAILED;
128 self_t* ptr_dispatcher = static_cast<self_t*>(data_ptr);
129 if (ptr_dispatcher)
130 {
131 gate_exception_info_t xinfo = gate::catchException(&f_dispatcher, &ptr_dispatcher->functor);
132 ret = xinfo.result_code;
133 delete ptr_dispatcher;
134 }
135 else
136 {
137 ret = GATE_RESULT_NULLPOINTER;
138 }
139 return ret;
140 }
141 };
142
143 template<class F>
144 id_t startFunc(F functor)
145 {
146 id_t thread_id = id_t();
147 typedef FunctorDispatcher<F> dispatcher_t;
148 Ptr<dispatcher_t> dispatcher(new dispatcher_t(functor));
149 gate_runnable_t* ptr_runnable = gate_runnable_create(
150 &dispatcher_t::dispatch_functor, dispatcher.get(),
151 sizeof(dispatcher_t), &dispatcher_t::create, dispatcher_t::release);
152
153 if (NULL == ptr_runnable)
154 {
155 GATEXX_RAISE_ERROR(results::OutOfMemory);
156 }
157 else
158 {
159 Runnable runner(ptr_runnable);
160 thread_id = this->start(ptr_runnable);
161 // thread is started, otherwise an exception/error is thrown
162
163 gate_object_retain(ptr_runnable); // another reference is now assigned as a dispatcher parameter
164 dispatcher.release(); // the dispatcher was moved into the runnable, it can be released here
165 }
166
167 return thread_id;
168 }
169
170 template<class F, class A1>
171 2 id_t startFunc(F func, A1 a1)
172 {
173
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Delegate1<A1> d(func);
174
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 return this->startDispatcher(new RunnableDispatcher1<A1>(d, a1));
175 }
176
177 template<class F, class A1, class A2>
178 id_t startFunc(F func, A1 a1, A2 a2)
179 {
180 Delegate2<A1, A2> d(func);
181 return this->startDispatcher(new RunnableDispatcher2<A1, A2>(d, a1, a2));
182 }
183
184 template<class F, class A1, class A2, class A3>
185 id_t startFunc(F func, A1 a1, A2 a2, A3 a3)
186 {
187 Delegate3<A1, A2, A3> d(func);
188 return this->startDispatcher(new RunnableDispatcher3<A1, A2, A3>(d, a1, a2, a3));
189 }
190
191 template<class F, class A1, class A2, class A3, class A4>
192 id_t startFunc(F func, A1 a1, A2 a2, A3 a3, A4 a4)
193 {
194 Delegate4<A1, A2, A3, A4> d(func);
195 return this->startDispatcher(new RunnableDispatcher4<A1, A2, A3, A4>(d, a1, a2, a3, a4));
196 }
197
198
199
200 template<class CLS>
201 id_t startMethod(CLS* obj, void(CLS::* method)(void))
202 {
203 Delegate0 d(obj, method);
204 return this->startDispatcher(new RunnableDispatcher0(d));
205 }
206
207 template<class CLS, class A1>
208 id_t startMethod(CLS* obj, void(CLS::* method)(A1), A1 a1)
209 {
210 Delegate1<A1> d(obj, method);
211 return this->startDispatcher(new RunnableDispatcher1<A1>(d, a1));
212 }
213
214 template<class CLS, class A1, class A2>
215 id_t startMethod(CLS* obj, void(CLS::* method)(A1, A2), A1 a1, A2 a2)
216 {
217 Delegate2<A1, A2> d(obj, method);
218 return this->startDispatcher(new RunnableDispatcher2<A1, A2>(d, a1, a2));
219 }
220
221 template<class CLS, class A1, class A2, class A3>
222 id_t startMethod(CLS* obj, void(CLS::* method)(A1, A2, A3), A1 a1, A2 a2, A3 a3)
223 {
224 Delegate3<A1, A2, A3> d(obj, method);
225 return this->startDispatcher(new RunnableDispatcher3<A1, A2, A3>(d, a1, a2, a3));
226 }
227
228 template<class CLS, class A1, class A2, class A3, class A4>
229 id_t startMethod(CLS* obj, void(CLS::* method)(A1, A2, A3, A4), A1 a1, A2 a2, A3 a3, A4 a4)
230 {
231 Delegate4<A1, A2, A3, A4> d(obj, method);
232 return this->startDispatcher(new RunnableDispatcher4<A1, A2, A3, A4>(d, a1, a2, a3, a4));
233 }
234 };
235
236
237 /// @brief
238 class GATE_CORE_CPP_API ThreadStorage : private NonCopyable
239 {
240 public:
241 ThreadStorage();
242 ~ThreadStorage() noexcept;
243
244 Result<void*> tryGet() const noexcept;
245 Result<Void> trySet(void* data) noexcept;
246 void* get() const;
247 void set(void* data);
248
249 private:
250 gate_thread_storage_t impl;
251 };
252
253
254 /// @brief
255 /// @tparam T
256 template<class T>
257 class ThreadVar : private NonCopyable
258 {
259 private:
260 ThreadStorage& thread_store;
261
262 void destroy_type(void* ptr_data)
263 {
264 if (ptr_data)
265 {
266 var_type_t* ptr = static_cast<var_type_t*>(ptr_data);
267 gate::destructType(ptr);
268 gate_mem_dealloc(ptr);
269 }
270 }
271
272 public:
273 typedef T var_type_t;
274
275 ThreadVar(ThreadStorage& storage)
276 : thread_store(storage)
277 {
278
279 }
280 ~ThreadVar() noexcept
281 {
282 }
283
284 bool_t empty() const
285 {
286 void* data = this->thread_store.get();
287 return data != NULL;
288 }
289
290 bool_t operator!() const
291 {
292 return this->empty();
293 }
294
295 var_type_t* get()
296 {
297 void* data = this->thread_store.get();
298 if (data)
299 {
300 return static_cast<var_type_t*>(data);
301 }
302 return NULL;
303 }
304
305 var_type_t const* get() const
306 {
307 void* data = this->thread_store.get();
308 if (data)
309 {
310 return static_cast<var_type_t const*>(data);
311 }
312 return NULL;
313 }
314
315 var_type_t& operator*()
316 {
317 var_type_t* ptr = this->get();
318 if (!ptr)
319 {
320 GATEXX_RAISE_ERROR(results::NullPointer);
321 }
322 return *ptr;
323 }
324 var_type_t const& operator*() const
325 {
326 var_type_t const* ptr = this->get();
327 if (!ptr)
328 {
329 GATEXX_RAISE_ERROR(results::NullPointer);
330 }
331 return *ptr;
332 }
333 var_type_t* operator->()
334 {
335 var_type_t* ptr = this->get();
336 if (!ptr)
337 {
338 GATEXX_RAISE_ERROR(results::NullPointer);
339 }
340 return ptr;
341 }
342 var_type_t const* operator->() const
343 {
344 var_type_t const* ptr = this->get();
345 if (!ptr)
346 {
347 GATEXX_RAISE_ERROR(results::NullPointer);
348 }
349 return ptr;
350 }
351
352
353 void create()
354 {
355 var_type_t* ptr = gate_mem_alloc(sizeof(var_type_t));
356 if (ptr == NULL)
357 {
358 GATEXX_RAISE_ERROR(results::OutOfMemory);
359 }
360
361 void* previous_data = this->thread_store.get();
362 try
363 {
364 gate::constructType(ptr);
365 try
366 {
367 this->thread_store.set(ptr);
368 }
369 catch (...)
370 {
371 gate::destructType(ptr);
372 throw;
373 }
374 }
375 catch (...)
376 {
377 gate_mem_dealloc(ptr);
378 throw;
379 }
380 destroy_type(previous_data);
381 }
382
383 void create(var_type_t const& src)
384 {
385 var_type_t* ptr = gate_mem_alloc(sizeof(var_type_t));
386 if (ptr == NULL)
387 {
388 GATEXX_RAISE_ERROR(results::OutOfMemory);
389 }
390
391 void* previous_data = this->thread_store.get();
392 try
393 {
394 gate::copyConstructType(ptr, src);
395 try
396 {
397 this->thread_store.set(ptr);
398 }
399 catch (...)
400 {
401 gate::destructType(ptr);
402 throw;
403 }
404 }
405 catch (...)
406 {
407 gate_mem_dealloc(ptr);
408 throw;
409 }
410 destroy_type(previous_data);
411 }
412
413 void destroy()
414 {
415 void* data = this->thread_store.get();
416 destroy_type(data);
417 this->thread_store.set(NULL);
418 }
419
420 };
421
422 } // end of namespace gate
423
424 #endif
425