GCC Code Coverage Report


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