EtcPal  0.3.0
ETC Platform Abstraction Layer (EtcPal)
View other versions:
thread.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2020 ETC Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************
16  * This file is a part of EtcPal. For more information, go to:
17  * https://github.com/ETCLabs/EtcPal
18  ******************************************************************************/
19 
22 
23 #ifndef ETCPAL_CPP_THREAD_H_
24 #define ETCPAL_CPP_THREAD_H_
25 
26 #include <algorithm>
27 #include <cassert>
28 #include <chrono>
29 #include <functional>
30 #include <limits>
31 #include <memory>
32 #include <string>
33 #include <system_error>
34 #include <type_traits>
35 #include <utility>
36 #include "etcpal/common.h"
37 #include "etcpal/thread.h"
38 #include "etcpal/cpp/common.h"
39 #include "etcpal/cpp/error.h"
40 
41 namespace etcpal
42 {
124 
142 class Thread
143 {
144 public:
146  Thread() = default;
147  template <class Function, class... Args>
148  Thread(Function&& func, Args&&... args);
149  virtual ~Thread();
150 
151  Thread(Thread&& other) noexcept;
152  Thread& operator=(Thread&& other) noexcept;
153 
155  Thread(const Thread& other) = delete;
157  Thread& operator=(const Thread& other) = delete;
158 
159  bool joinable() const noexcept;
160 
163  unsigned int priority() const noexcept;
164  unsigned int stack_size() const noexcept;
165  const char* name() const noexcept;
166  void* platform_data() const noexcept;
167  const EtcPalThreadParams& params() const noexcept;
169 
172  Thread& SetPriority(unsigned int priority) noexcept;
173  Thread& SetStackSize(unsigned int stack_size) noexcept;
174  Thread& SetName(const char* name) noexcept;
175  Thread& SetName(const std::string& name) noexcept;
176  Thread& SetPlatformData(void* platform_data) noexcept;
178 
179  template <class Function, class... Args>
180  Error Start(Function&& func, Args&&... args);
181  Error Join(int timeout_ms = ETCPAL_WAIT_FOREVER) noexcept;
182  Error Terminate() noexcept;
183 
184  static void Sleep(unsigned int ms) noexcept;
185  template <typename Rep, typename Period>
186  static void Sleep(const std::chrono::duration<Rep, Period>& sleep_duration) noexcept;
187 
189  using FunctionType = std::function<void()>;
191 
192 private:
193  std::unique_ptr<etcpal_thread_t> thread_;
195 };
196 
198 
199 extern "C" inline void CppThreadFn(void* arg)
200 {
201  std::unique_ptr<Thread::FunctionType> p_func(static_cast<Thread::FunctionType*>(arg));
202  // Tear the roof off the sucker
203  (*p_func)();
204 }
205 
207 
216 template <class Function, class... Args>
217 inline Thread::Thread(Function&& func, Args&&... args)
218 {
220  auto result = Start(std::forward<Function>(func), std::forward<Args>(args)...);
221  if (!result)
222  ETCPAL_THROW(result);
223 }
224 
230 {
231  if (thread_)
232  etcpal_thread_join(thread_.get());
233 }
234 
240 inline Thread::Thread(Thread&& other) noexcept
241 {
242  *this = std::move(other);
243 }
244 
250 inline Thread& Thread::operator=(Thread&& other) noexcept
251 {
252  thread_ = std::move(other.thread_);
253  params_ = other.params_;
254  ETCPAL_THREAD_SET_DEFAULT_PARAMS(&other.params_);
255  return *this;
256 }
257 
259 inline bool Thread::joinable() const noexcept
260 {
261  return (bool)thread_;
262 }
263 
265 inline unsigned int Thread::priority() const noexcept
266 {
267  return params_.priority;
268 }
269 
271 inline unsigned int Thread::stack_size() const noexcept
272 {
273  return params_.stack_size;
274 }
275 
277 inline const char* Thread::name() const noexcept
278 {
279  return params_.thread_name;
280 }
281 
283 inline void* Thread::platform_data() const noexcept
284 {
285  return params_.platform_data;
286 }
287 
289 inline const EtcPalThreadParams& Thread::params() const noexcept
290 {
291  return params_;
292 }
293 
301 inline Thread& Thread::SetPriority(unsigned int priority) noexcept
302 {
303  params_.priority = priority;
304  return *this;
305 }
306 
314 inline Thread& Thread::SetStackSize(unsigned int stack_size) noexcept
315 {
316  params_.stack_size = stack_size;
317  return *this;
318 }
319 
328 inline Thread& Thread::SetName(const char* name) noexcept
329 {
330  params_.thread_name = name;
331  return *this;
332 }
333 
342 inline Thread& Thread::SetName(const std::string& name) noexcept
343 {
344  params_.thread_name = name.c_str();
345  return *this;
346 }
347 
356 inline Thread& Thread::SetPlatformData(void* platform_data) noexcept
357 {
358  params_.platform_data = platform_data;
359  return *this;
360 }
361 
383 template <class Function, class... Args>
384 Error Thread::Start(Function&& func, Args&&... args)
385 {
386  if (thread_)
387  return kEtcPalErrInvalid;
388 
389  thread_.reset(new etcpal_thread_t);
390 
391  auto new_f = std::unique_ptr<FunctionType>(
392  new FunctionType(std::bind(std::forward<Function>(func), std::forward<Args>(args)...)));
393  Error create_res = etcpal_thread_create(thread_.get(), &params_, CppThreadFn, new_f.get());
394  if (create_res)
395  new_f.release();
396  else
397  thread_.reset();
398  return create_res;
399 }
400 
412 inline Error Thread::Join(int timeout_ms) noexcept
413 {
414  if (thread_)
415  {
416  Error join_res = etcpal_thread_timed_join(thread_.get(), timeout_ms);
417  if (join_res)
418  thread_.reset();
419  return join_res;
420  }
421  else
422  {
423  return kEtcPalErrInvalid;
424  }
425 }
426 
436 inline Error Thread::Terminate() noexcept
437 {
438  if (thread_)
439  {
440  Error terminate_res = etcpal_thread_terminate(thread_.get());
441  if (terminate_res)
442  thread_.reset();
443  return terminate_res;
444  }
445  else
446  {
447  return kEtcPalErrInvalid;
448  }
449 }
450 
452 inline void Thread::Sleep(unsigned int ms) noexcept
453 {
455 }
456 
460 template <typename Rep, typename Period>
461 void Thread::Sleep(const std::chrono::duration<Rep, Period>& sleep_duration) noexcept
462 {
463  // This implementation cannot sleep longer than UINT_MAX.
464  unsigned int sleep_ms_clamped = static_cast<unsigned int>(
465  std::min(std::chrono::milliseconds(sleep_duration).count(),
466  static_cast<std::chrono::milliseconds::rep>(std::numeric_limits<unsigned int>::max())));
467  Sleep(sleep_ms_clamped);
468 }
469 
470 }; // namespace etcpal
471 
472 #endif // ETCPAL_CPP_THREAD_H_
A wrapper class for the EtcPal error type.
Definition: error.h:94
A thread class, modeled after std::thread.
Definition: thread.h:143
Error Terminate() noexcept
Forcefully kill the thread.
Definition: thread.h:436
unsigned int stack_size() const noexcept
Get the stack size of this thread (not valid on all platforms).
Definition: thread.h:271
unsigned int priority() const noexcept
Get the priority of this thread (not valid on all platforms).
Definition: thread.h:265
Thread & SetPlatformData(void *platform_data) noexcept
Set the platform-specific parameter data.
Definition: thread.h:356
bool joinable() const noexcept
Whether the thread object identifies an active thread of execution.
Definition: thread.h:259
const char * name() const noexcept
Get the name of this thread.
Definition: thread.h:277
Thread & SetStackSize(unsigned int stack_size) noexcept
Set the stack size of this thread.
Definition: thread.h:314
Error Start(Function &&func, Args &&... args)
Associate this thread object with a new thread of execution.
Definition: thread.h:384
Thread & operator=(Thread &&other) noexcept
Move another thread into this thread.
Definition: thread.h:250
Thread(const Thread &other)=delete
Deleted copy constructor - threads are not copyable.
virtual ~Thread()
Destroy the thread object.
Definition: thread.h:229
const EtcPalThreadParams & params() const noexcept
Get a reference the parameters of this thread.
Definition: thread.h:289
static void Sleep(unsigned int ms) noexcept
Blocks the current thread for the specified number of milliseconds.
Definition: thread.h:452
Thread & operator=(const Thread &other)=delete
Deleted copy assignment operator - threads are not copyable.
void * platform_data() const noexcept
Get the platform-specific data of this thread.
Definition: thread.h:283
Thread & SetPriority(unsigned int priority) noexcept
Set the priority of this thread.
Definition: thread.h:301
Thread()=default
Create a new thread object which does not yet represent a thread.
Thread & SetName(const char *name) noexcept
Set the name of this thread.
Definition: thread.h:328
Error Join(int timeout_ms=ETCPAL_WAIT_FOREVER) noexcept
Wait for the thread to finish execution.
Definition: thread.h:412
Common definitions used by EtcPal C++ wrappers.
C++ wrapper and utilities for etcpal/error.h.
@ kEtcPalErrInvalid
An invalid argument was provided to an API function.
Definition: error.h:62
etcpal_error_t etcpal_thread_create(etcpal_thread_t *id, const EtcPalThreadParams *params, void(*thread_fn)(void *), void *thread_arg)
Create a new thread.
etcpal_error_t etcpal_thread_timed_join(etcpal_thread_t *id, int timeout_ms)
Wait for a thread to finish execution, giving up after a timeout.
PLATFORM_DEFINED etcpal_thread_t
The thread handle.
Definition: thread.dox:35
etcpal_error_t etcpal_thread_join(etcpal_thread_t *id)
Wait for a thread to finish execution.
etcpal_error_t etcpal_thread_terminate(etcpal_thread_t *id)
Forcefully kill a thread.
#define ETCPAL_THREAD_SET_DEFAULT_PARAMS(threadparamsptr)
Set the platform-default values for the EtcPalThreadParams struct.
Definition: thread.h:153
#define ETCPAL_THREAD_PARAMS_INIT_VALUES
The set of default values for an EtcPalThreadParamsStructure.
Definition: thread.h:170
void etcpal_thread_sleep(unsigned int sleep_ms)
Provides a platform-neutral sleep.
#define ETCPAL_WAIT_FOREVER
For etcpal_ functions that take a millisecond timeout, this means to wait indefinitely.
Definition: common.h:111
A set of parameters for an etcpal_thread.
Definition: thread.h:127
unsigned int priority
The priority of the thread.
Definition: thread.h:129
void * platform_data
Pointer to a platform-specific parameter structure.
Definition: thread.h:149
unsigned int stack_size
The stack size of the thread.
Definition: thread.h:131
const char * thread_name
A name for the thread, maximum length ETCPAL_THREAD_NAME_MAX_LENGTH.
Definition: thread.h:133