GCC Code Coverage Report


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