<div dir="auto"><div>Will this show up in documentation somewhere? <div dir="auto"><br></div><div dir="auto">It does seem like we should say something about C++ threads and this. </div><div dir="auto"><br></div><div dir="auto">What about C11 threads?</div><div dir="auto"><br></div><div dir="auto">Test doesn't appear to cover much. </div><div dir="auto"><br></div><div dir="auto">More interspersed</div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Oct 3, 2020, 1:23 AM <<a href="mailto:chrisj@rtems.org">chrisj@rtems.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Chris Johns <<a href="mailto:chrisj@rtems.org" target="_blank" rel="noreferrer">chrisj@rtems.org</a>><br>
<br>
---<br>
cpukit/include/rtems/c++/error | 65 +++<br>
cpukit/include/rtems/c++/thread | 469 ++++++++++++++++++++++<br>
cpukit/librtemscxx/error.cc | 76 ++++<br>
cpukit/librtemscxx/thread.cc | 416 +++++++++++++++++++<br>
spec/build/cpukit/grp.yml | 2 +<br>
spec/build/cpukit/librtemscxx.yml | 21 +<br>
spec/build/testsuites/libtests/grp.yml | 2 +<br>
spec/build/testsuites/libtests/rcxx01.yml | 22 +<br>
testsuites/libtests/rcxx01/init.c | 69 ++++<br>
testsuites/libtests/rcxx01/rcxx01.doc | 16 +<br>
testsuites/libtests/rcxx01/rcxx01.scn | 13 +<br>
testsuites/libtests/rcxx01/thread.cc | 90 +++++<br>
12 files changed, 1261 insertions(+)<br>
create mode 100644 cpukit/include/rtems/c++/error<br>
create mode 100644 cpukit/include/rtems/c++/thread<br>
create mode 100644 cpukit/librtemscxx/error.cc<br>
create mode 100644 cpukit/librtemscxx/thread.cc<br>
create mode 100644 spec/build/cpukit/librtemscxx.yml<br>
create mode 100644 spec/build/testsuites/libtests/rcxx01.yml<br>
create mode 100644 testsuites/libtests/rcxx01/init.c<br>
create mode 100644 testsuites/libtests/rcxx01/rcxx01.doc<br>
create mode 100644 testsuites/libtests/rcxx01/rcxx01.scn<br>
create mode 100644 testsuites/libtests/rcxx01/thread.cc<br>
<br>
diff --git a/cpukit/include/rtems/c++/error b/cpukit/include/rtems/c++/error<br>
new file mode 100644<br>
index 0000000000..8b9d875e0f<br>
--- /dev/null<br>
+++ b/cpukit/include/rtems/c++/error<br>
@@ -0,0 +1,65 @@<br>
+/* -*- C++ -*-<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ * notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ * notice, this list of conditions and the following disclaimer in the<br>
+ * documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+/**<br>
+ * @file<br>
+ *<br>
+ * @ingroup RTEMSC++<br>
+ *<br>
+ * RTEMS Error exception.<br>
+ */<br>
+<br>
+#if !defined(RTEMS_CXX_ERROR)<br>
+#define RTEMS_CXX_ERROR</blockquote></div></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+#include <stdexcept><br>
+#include <string><br>
+<br>
+#include <rtems.h><br>
+<br>
+namespace rtems<br>
+{<br>
+ class runtime_error :<br>
+ public std::runtime_error<br>
+ {<br>
+ const rtems_status_code sc;<br>
+ public:<br>
+ runtime_error (const rtems_status_code sc);<br>
+ runtime_error (const rtems_status_code sc, const std::string& what);<br>
+ runtime_error (const rtems_status_code sc, const char* what);<br>
+ ~runtime_error ();<br>
+ };<br>
+<br>
+ /**<br>
+ * Throw a rtems::runtime_error exception if the RTEMS status code is<br>
+ * not RTEMS_SUCCESSFUL.<br>
+ */<br>
+ void runtime_error_check (const rtems_status_code sc);<br>
+ void runtime_error_check (const rtems_status_code sc, const std::string& what);<br>
+ void runtime_error_check (const rtems_status_code sc, const char* what);<br>
+};<br>
+<br>
+#endif<br>
diff --git a/cpukit/include/rtems/c++/thread b/cpukit/include/rtems/c++/thread<br>
new file mode 100644<br>
index 0000000000..c3f18ab3cf<br>
--- /dev/null<br>
+++ b/cpukit/include/rtems/c++/thread<br>
@@ -0,0 +1,469 @@<br>
+/* -*- C++ -*-<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ * notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ * notice, this list of conditions and the following disclaimer in the<br>
+ * documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+/**<br>
+ * @file<br>
+ *<br>
+ * @ingroup RTEMSC++<br>
+ *<br>
+ * The C++ standard thread support with thread attribute control.<br>
+ *<br>
+ * The code requires the `-std=c++17` option to access `std::invoke()`.<br>
+ */<br>
+<br>
+#if !defined(RTEMS_CXX_THREAD)<br>
+#define RTEMS_CXX_THREAD<br>
+<br>
+#include <functional><br>
+#include <iostream><br>
+#include <string><br>
+#include <thread><br>
+#include <utility><br>
+<br>
+namespace rtems<br>
+{<br>
+ namespace thread<br>
+ {<br>
+ /**<br>
+ * @brief Manage the attributes of a thread.<br>
+ */<br>
+ class attributes<br>
+ {<br>
+ public:<br>
+ /**<br>
+ * The schedular modes.<br>
+ */<br>
+ enum sched_mode {<br>
+ sched_inherit, /**< Inhert the scheduler */<br>
+ sched_explicit /**< Explicitly set the scheduler */<br>
+ };<br>
+<br>
+ /**<br>
+ * The schedular policies.<br>
+ */<br>
+ enum sched_policy {<br>
+ sched_other, /**< Other scheduler policy */<br>
+ sched_fifo, /**< FIFO scheduler policy */<br>
+ sched_roundrobin, /**< Roundrobin scheduler policy */<br>
+ sched_sporadic /**< Sporadic scheduler policy */<br>
+ };<br>
+<br>
+ /**<br>
+ * Construct a thread attributes object with the current settings of the<br>
+ * executing thread. The stack size is set to the configured minimum<br>
+ * stack size.<br>
+ */<br>
+ attributes ();<br>
+<br>
+ /*<br>
+ * Copy construct the thread attributes.<br>
+ *<br>
+ * @param attr The attributes to copy.<br>
+ */<br>
+ attributes (const attributes& attr);<br>
+<br>
+ /**<br>
+ * Set the name of the thread. The thread is a classic API thread and<br>
+ * the name is only 4 characters.</blockquote></div></div><div dir="auto"><br></div><div dir="auto">The thread appears to be a POSIX thread. </div><div dir="auto"><br></div><div dir="auto"></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ *<br>
+ * @param name The name as a string.<br>
+ */<br>
+ void set_name (const std::string& name);<br>
+<br>
+ /**<br>
+ * Set the name of the thread. The thread is a classic API thread and<br>
+ * the name is only 4 characters.<br>
+ *<br>
+ * @param name The name as a string.<br>
+ */<br>
+ void set_name (const char* name);<br>
+<br>
+ /**<br>
+ * Get the name of the thread.<br>
+ *<br>
+ * @retval const std::string& The name of the thread.<br>
+ */<br>
+ const std::string& get_name () const;<br>
+<br>
+ /**<br>
+ * Set the priority of the thread.<br>
+ *<br>
+ * @param priority The POSIX API priority of the thread.<br>
+ */<br>
+ void set_priority (int priority);<br>
+<br>
+ /**<br>
+ * Get the POSIX API priority of the thread.<br>
+ *<br>
+ * @retval int The POSIX API thread priority.<br>
+ */<br>
+ int get_priority () const;<br>
+<br>
+ /**<br>
+ * Set the stack size. If the size is less than the configured minimum<br>
+ * the minimum value is used.<br>
+ *<br>
+ * @param size The stack size in bytes.<br>
+ */<br>
+ void set_stack_size (size_t size);<br>
+<br>
+ /**<br>
+ * Get the stack size.<br>
+ *<br>
+ * @retval size_t The stack size in bytes.<br>
+ */<br>
+ size_t get_stack_size () const;<br>
+<br>
+ /**<br>
+ * Set the scheduler name. If not set no scheduler is set.<br>
+ *<br>
+ * @parrm scheduler The name of the scheduler.<br>
+ */<br>
+ void set_scheduler (const std::string& scheduler);<br>
+<br>
+ /**<br>
+ * Set the scheduler name. If not set no scheduler is set.<br>
+ */<br>
+ void set_scheduler (const char* scheduler);<br>
+<br>
+ /**<br>
+ * Get scheduler name.<br>
+ */<br>
+ const std::string& get_scheduler ();<br>
+<br>
+ /**<br>
+ * Get the attrobutes' scheduler mode for the thread.<br>
+ *<br>
+ * @return sched_mode The attributes; scheduler mode<br>
+ */<br>
+ sched_mode get_scheduler_mode () const;<br>
+<br>
+ /**<br>
+ * Set the scheduler policy for the thread. This call sets the<br>
+ * schedular mode to @ref sched_explicit.<br>
+ *<br>
+ * @param policy The scheduler policy.<br>
+ */<br>
+ void set_scheduler_policy (sched_policy policyr);<br>
+<br>
+ /**<br>
+ * Get the scheduler policy for the thread.<br>
+ */<br>
+ sched_policy get_scheduler_policy () const;<br>
+<br>
+ /**<br>
+ * Commit any changes to the executing thread. @note only the priority<br>
+ * and modes of a thread can be changedTheeeeee name and stack size are</blockquote></div></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ * ignored.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Is there a line break missing before the note?</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ */<br>
+ void commit ();<br>
+<br>
+ /**<br>
+ * Update the attribute values from the executing thread. The attributes<br>
+ * are updated from the current thread when constructed and the values<br>
+ * returned are those held since then. If another thread changes the<br>
+ * attributes of the current thread those changes will not be seen until<br>
+ * this method is called. Except for the name and stack size any local<br>
+ * changes made will lost then the update call is made.<br>
+ */<br>
+ void update ();<br>
+<br>
+ /**<br>
+ * Copy operator.<br>
+ */<br>
+ attributes& operator= (const attributes& attr);<br>
+<br>
+ /**<br>
+ * The comparision operator does not check the name or stack size<br>
+ * of a thread.<br>
+ */<br>
+ bool operator== (const attributes& attr) const;<br>
+<br>
+ private:<br>
+ std::string name; /**< Name of the thread */<br>
+ int priority; /**< POSIX API priority */<br>
+ size_t stack_size; /**< Stack size in bytes */<br>
+ std::string scheduler; /**< Name of the scheduler */<br>
+ sched_mode mode; /**< Scheduler's mode */<br>
+ sched_policy policy; /**< Scheduler's policy */<br>
+ /* affinity, cpu set size is? */<br>
+ };<br>
+<br>
+ /**<br>
+ * @brief Create a thread with thread attributes.<br>
+ *<br>
+ * Create a thread optionally with thread attributes. The usage of this<br>
+ * class follows the C++ standard for std::thread. The standard support<br>
+ * for creating a thread does not let you control the attributes of a<br>
+ * thread and control is important in embedded real-time<br>
+ * applications. This class lets you control a thread attributes and use<br>
+ * the extensive an excellent thread support the C++ standard provides.<br>
+ *<br>
+ * There is no indication attribute support for threads will be added to<br>
+ * the C++ standard and what it will look like. The support provided here<br>
+ * is designed to make as little impact on a code base as possible. While<br>
+ * the attributes supported are specific to RTEMS they are common to all<br>
+ * embedded operating systems.<br>
+ *<br>
+ * The support provided here is specific to GCC due to the use of some<br>
+ * non-standard interfaces to get the indices of the template argument<br>
+ * pack in new thread's context. A standards only solution would be<br>
+ * preferred.<br>
+ */<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Since we have clang on some targets, any idea what it does and if this will work? Should it disable itself for not GCC?</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ class thread<br>
+ {<br>
+ friend void* thread_generic_entry (void* arg);<br>
+<br>
+ /**<br>
+ * Base state class to interface to derived template of the thread<br>
+ * state from the generic entry point for the thread.<br>
+ */<br>
+ struct state_base<br>
+ {<br>
+ virtual ~state_base ();<br>
+ virtual const attributes get_attributes () = 0;<br>
+ virtual void run () = 0;<br>
+ };<br>
+<br>
+ /**<br>
+ * The state is passed to the new thread context as a unique<br>
+ * pointer. This handles the hand over and clean up.<br>
+ */<br>
+ using state_ptr = std::unique_ptr<state_base>;<br>
+<br>
+ public:<br>
+<br>
+ /**<br>
+ * Template check to see if the first argument of a thread is a set of<br>
+ * attributes.<br>
+ */<br>
+ template <typename A, class DecayA = typename std::decay<A>::type><br>
+ using enable_if_attributes = typename std::enable_if<br>
+ <std::is_same<DecayA, attributes>::value>::type;<br>
+<br>
+ /**<br>
+ * We need our own id type so the thread class can access the pthread<br>
+ * handle to initialise it.<br>
+ */<br>
+ class id {<br>
+ public:<br>
+ id () noexcept : id_ (0) { }<br>
+ explicit id (pthread_t id_) : id_ (id_) { }<br>
+ private:<br>
+ pthread_t id_;<br>
+<br>
+ friend class thread;<br>
+ friend bool operator== (thread::id l, thread::id r) noexcept;<br>
+<br>
+ template<class CharT, class Traits><br>
+ friend std::basic_ostream<CharT, Traits>&<br>
+ operator<< (std::basic_ostream<CharT, Traits>& out, thread::id id_);<br>
+ };<br>
+<br>
+ /**<br>
+ * The default thread constructions.<br>
+ */<br>
+ thread () noexcept = default;<br>
+<br>
+ /**<br>
+ * The std::thread equivilant constructor. The attributes will be the<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Equivalent</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ * same as the executing thread with a default thread name and the<br>
+ * configured minimum stack size.<br>
+ */<br>
+ template<typename F, typename... Args><br>
+ explicit thread (F&& func, Args&&... args);<br>
+<br>
+ /**<br>
+ * Create a thread with the provided attributes. The entry point and<br>
+ * optional arguments are the same as std::thread.<br>
+ */<br>
+ template <typename A, typename F, typename ...Args,<br>
+ class = enable_if_attributes<A>><br>
+ explicit thread (A&& attr, F&& func, Args&&... args);<br>
+<br>
+ /**<br>
+ * Move the thread id to this instance.<br>
+ */<br>
+ thread& operator= (thread&& thread_);<br>
+<br>
+ void swap(thread& thread_) noexcept;<br>
+<br>
+ bool joinable() const noexcept;<br>
+<br>
+ /*<br>
+ * Constrain use. These are not available.<br>
+ */<br>
+ thread (thread&) = delete;<br>
+ thread (const thread&) = delete;<br>
+ thread (const thread&&) = delete;<br>
+ thread& operator= (const thread&) = delete;<br>
+<br>
+ std::thread::id get_id() const noexcept;<br>
+<br>
+ private:<br>
+<br>
+ id id_;<br>
+<br>
+ /**<br>
+ * Invoke the thread's entry point with the parameter pack in the new<br>
+ * thread's context. This object holds the parameters copied onto the<br>
+ * new thread's stack making them available to entry point routine.<br>
+ */<br>
+ template<typename Parms><br>
+ struct invoker {<br>
+ Parms p;<br>
+<br>
+ template<size_t Index><br>
+ static std::__tuple_element_t<Index, Parms>&& declval ();<br>
+<br>
+ template<size_t... Ind><br>
+ auto invoke (std::_Index_tuple<Ind...>)<br>
+ noexcept (noexcept (std::invoke (declval<Ind>()...)))<br>
+ -> decltype (std::invoke (declval<Ind> ()...)) {<br>
+ return std::invoke (std::get<Ind> (std::move (p))...);<br>
+ }<br>
+<br>
+ using indices =<br>
+ typename std::_Build_index_tuple<std::tuple_size<Parms>::value>::__type;<br>
+<br>
+ void run () {<br>
+ invoke (indices ());<br>
+ }<br>
+ };<br>
+<br>
+ /**<br>
+ * The state holds the invoker with the parameters. The generic entry<br>
+ * point calls the virtual methods to get the attributes and to run the<br>
+ * new thread in the new thread's context..<br>
+ */<br>
+ template<typename Invoker><br>
+ struct state : state_base {<br>
+ const attributes attr;<br>
+ Invoker i;<br>
+<br>
+ state (const attributes& attr, Invoker&& i)<br>
+ : attr (attr),<br>
+ i (std::forward<Invoker> (i)) {<br>
+ }<br>
+<br>
+ const attributes get_attributes () override {<br>
+ return attr;<br>
+ }<br>
+<br>
+ void run () override {<br>
+ i.run ();<br>
+ }<br>
+ };<br>
+<br>
+ /**<br>
+ * Make the state. This dynamic memory is managed by the unique pointer<br>
+ * and is passed to the generic thread entry point.<br>
+ */<br>
+ template<typename Invoker><br>
+ static state_ptr<br>
+ make_state (const attributes& attr, Invoker&& i) {<br>
+ using state_impl = state<Invoker>;<br>
+ return state_ptr{ new state_impl (attr, std::forward<Invoker> (i)) };<br>
+ }<br>
+<br>
+ /**<br>
+ * Decay the parameters so they can be correctly packed into the<br>
+ * parameter tuple.<br>
+ */<br>
+ template<typename... T><br>
+ using decayed_tuple = std::tuple<typename std::decay<T>::type...>;<br>
+<br>
+ /**<br>
+ * Make the invoker with the parameters.<br>
+ */<br>
+ template<typename F, typename... Args><br>
+ static invoker<decayed_tuple<F, Args...>><br>
+ make_invoker (F&& func, Args&&... args)<br>
+ {<br>
+ return {<br>
+ decayed_tuple<F, Args...> {<br>
+ std::forward<F> (func), std::forward<Args> (args)...<br>
+ }<br>
+ };<br>
+ }<br>
+<br>
+ /**<br>
+ * Create and start the thread.<br>
+ */<br>
+ void start_thread (state_ptr s);<br>
+ };<br>
+<br>
+ template <class T><br>
+ inline typename std::decay<T>::type<br>
+ decay_copy (T&& t) {<br>
+ return std::forward<T> (t);<br>
+ }<br>
+<br>
+ template<typename F, typename... Args><br>
+ thread::thread (F&& func, Args&&... args)<br>
+ : id_ (0) {<br>
+ attributes attr;<br>
+ start_thread (<br>
+ make_state (attr,<br>
+ make_invoker (decay_copy (std::forward<F> (func)),<br>
+ decay_copy (std::forward<Args> (args))...))<br>
+ );<br>
+ }<br>
+<br>
+ template<typename A, typename F, typename... Args,<br>
+ class = thread::enable_if_attributes<A>><br>
+ thread::thread (A&& attr, F&& func, Args&&... args)<br>
+ : id_ (0) {<br>
+ start_thread (<br>
+ make_state (attr,<br>
+ make_invoker (decay_copy (std::forward<F> (func)),<br>
+ decay_copy (std::forward<Args> (args))...))<br>
+ );<br>
+ }<br>
+<br>
+ inline std::thread::id thread::get_id() const noexcept {<br>
+ return std::thread::id (id_.id_);<br>
+ }<br>
+<br>
+ inline bool<br>
+ operator== (thread::id l, thread::id r) noexcept {<br>
+ return l.id_ == r.id_;<br>
+ }<br>
+<br>
+ inline bool<br>
+ operator!= (thread::id l, thread::id r) noexcept {<br>
+ return !(l == r);<br>
+ }<br>
+<br>
+ template<class C, class T><br>
+ inline std::basic_ostream<C, T>&<br>
+ operator<< (std::basic_ostream<C, T>& out, thread::id id_) {<br>
+ return out << std::thread::id (id_.id_);<br>
+ }<br>
+ };<br>
+};<br>
+<br>
+#endif<br>
diff --git a/cpukit/librtemscxx/error.cc b/cpukit/librtemscxx/error.cc<br>
new file mode 100644<br>
index 0000000000..c7b749803f<br>
--- /dev/null<br>
+++ b/cpukit/librtemscxx/error.cc<br>
@@ -0,0 +1,76 @@<br>
+/*<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ * notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ * notice, this list of conditions and the following disclaimer in the<br>
+ * documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+#include <rtems/c++/error><br>
+<br>
+namespace rtems<br>
+{<br>
+ runtime_error::runtime_error (const rtems_status_code sc)<br>
+ : std::runtime_error (::rtems_status_text (sc)),<br>
+ sc (sc)<br>
+ {<br>
+ }<br>
+<br>
+ runtime_error::runtime_error (const rtems_status_code sc,<br>
+ const std::string& what)<br>
+ : std::runtime_error (what + ": " + ::rtems_status_text (sc)),<br>
+ sc (sc)<br>
+ {<br>
+ }<br>
+<br>
+ runtime_error::runtime_error (const rtems_status_code sc,<br>
+ const char* what)<br>
+ : std::runtime_error (std::string (what) + ": " + ::rtems_status_text (sc)),<br>
+ sc (sc)<br>
+ {<br>
+ }<br>
+<br>
+ runtime_error::~runtime_error()<br>
+ {<br>
+ }<br>
+<br>
+ void<br>
+ runtime_error_check (const rtems_status_code sc)<br>
+ {<br>
+ if (sc != RTEMS_SUCCESSFUL)<br>
+ throw runtime_error (sc);<br>
+ }<br>
+<br>
+ void<br>
+ runtime_error_check (const rtems_status_code sc, const std::string& what)<br>
+ {<br>
+ if (sc != RTEMS_SUCCESSFUL)<br>
+ throw runtime_error (sc, what);<br>
+ }<br>
+<br>
+ void<br>
+ runtime_error_check (const rtems_status_code sc, const char* what)<br>
+ {<br>
+ if (sc != RTEMS_SUCCESSFUL)<br>
+ throw runtime_error (sc, what);<br>
+ }<br>
+};<br>
diff --git a/cpukit/librtemscxx/thread.cc b/cpukit/librtemscxx/thread.cc<br>
new file mode 100644<br>
index 0000000000..79375a713c<br>
--- /dev/null<br>
+++ b/cpukit/librtemscxx/thread.cc<br>
@@ -0,0 +1,416 @@<br>
+/*<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ * notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ * notice, this list of conditions and the following disclaimer in the<br>
+ * documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+#if !defined(_GNU_SOURCE)<br>
+#define _GNU_SOURCE<br>
+#endif<br>
+<br>
+#include <system_error><br>
+<br>
+#include <rtems/c++/error><br>
+#include <rtems/c++/thread><br>
+<br>
+#include <pthread.h><br>
+<br>
+#include <rtems.h><br>
+<br>
+#if HAVE_GET_SCHEDULER_NAME<br>
+extern "C" bool get_scheduler_name (rtems_id sid, char* name);<br>
+#endif<br>
+<br>
+#if HAVE_GET_SCHEDULER_NAME<br>
+bool get_scheduler_name (rtems_id sid, char* name)<br>
+{<br>
+ name[0] = 'N';<br>
+ name[1] = 'O';<br>
+ name[2] = 'P';<br>
+ name[3] = '\0';<br>
+ return true;<br>
+}<br>
+#endif<br>
+<br>
+namespace rtems<br>
+{<br>
+ namespace thread<br>
+ {<br>
+ void<br>
+ system_error_check (int ec, const char* what)<br>
+ {<br>
+ if (ec != 0)<br>
+ throw std::system_error (ec, std::system_category(), what);<br>
+ }<br>
+<br>
+ attributes::attributes ()<br>
+ : priority (-1),<br>
+ stack_size (RTEMS_MINIMUM_STACK_SIZE),<br>
+ mode (sched_inherit),<br>
+ policy (sched_fifo)<br>
+ {<br>
+ update ();<br>
+ }<br>
+<br>
+ attributes::attributes (const attributes& attr)<br>
+ : name (<a href="http://attr.name" rel="noreferrer noreferrer" target="_blank">attr.name</a>),<br>
+ priority (attr.priority),<br>
+ stack_size (attr.stack_size),<br>
+ scheduler (attr.scheduler),<br>
+ mode (attr.mode),<br>
+ policy (attr.policy)<br>
+ {<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_name (const std::string& name_)<br>
+ {<br>
+ name = name_;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_name (const char* name_)<br>
+ {<br>
+ name = name_;<br>
+ }<br>
+<br>
+ const std::string&<br>
+ attributes::get_name () const<br>
+ {<br>
+ return name;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_priority (int priority_)<br>
+ {<br>
+ priority = priority_;<br>
+ }<br>
+<br>
+ int<br>
+ attributes::get_priority () const<br>
+ {<br>
+ return priority;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_stack_size(size_t size)<br>
+ {<br>
+ stack_size = size;<br>
+ }<br>
+<br>
+ size_t<br>
+ attributes::get_stack_size () const<br>
+ {<br>
+ return stack_size;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_scheduler (const std::string& scheduler_)<br>
+ {<br>
+ scheduler = scheduler_;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_scheduler (const char* scheduler_)<br>
+ {<br>
+ scheduler = scheduler_;<br>
+ }<br>
+<br>
+ const std::string&<br>
+ attributes::get_scheduler ()<br>
+ {<br>
+ return scheduler;<br>
+ }<br>
+<br>
+ attributes::sched_mode<br>
+ attributes::get_scheduler_mode () const<br>
+ {<br>
+ return mode;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::set_scheduler_policy (sched_policy policy_)<br>
+ {<br>
+ mode = sched_explicit;<br>
+ policy = policy_;<br>
+ }<br>
+<br>
+ attributes::sched_policy<br>
+ attributes::get_scheduler_policy () const<br>
+ {<br>
+ return policy;<br>
+ }<br>
+<br>
+ void<br>
+ attributes::commit ()<br>
+ {<br>
+ pthread_t pid = ::pthread_self ();<br>
+<br>
+ system_error_check (::pthread_setname_np (pid, name.c_str ()),<br>
+ "getting name");<br>
+<br>
+ int spolicy;<br>
+ struct sched_param sched_param;<br>
+<br>
+ system_error_check (::pthread_getschedparam (::pthread_self (),<br>
+ &spolicy,<br>
+ &sched_param),<br>
+ "getting scheduler parameters");<br>
+<br>
+ switch (policy) {<br>
+ case sched_other:<br>
+ spolicy = SCHED_OTHER;<br>
+ break;<br>
+ case sched_fifo:<br>
+ spolicy = SCHED_FIFO;<br>
+ break;<br>
+ case sched_roundrobin:<br>
+ spolicy = SCHED_RR;<br>
+ break;<br>
+ case sched_sporadic:<br>
+ spolicy = SCHED_SPORADIC;<br>
+ break;<br>
+ default:<br>
+ system_error_check (EINVAL, "get scheduler policy");<br>
+ break;<br>
+ }<br>
+<br>
+ sched_param.sched_priority = priority;<br>
+<br>
+ system_error_check (::pthread_setschedparam (::pthread_self (),<br>
+ spolicy,<br>
+ &sched_param),<br>
+ "getting scheduler parameters");<br>
+<br>
+ if (!scheduler.empty ()) {<br>
+ char sname[4] = { ' ', ' ', ' ', ' ' };<br>
+ for (size_t c = 0; c < sizeof (sname); ++c) {<br>
+ if (c >= scheduler.length ())<br>
+ break;<br>
+ sname[c] = scheduler[c];<br>
+ }<br>
+ rtems_name scheduler_name = rtems_build_name (sname[0],<br>
+ sname[1],<br>
+ sname[2],<br>
+ sname[3]);<br>
+ rtems_id scheduler_id;<br>
+ runtime_error_check (::rtems_scheduler_ident (scheduler_name,<br>
+ &scheduler_id),<br>
+ "get scheduler id");<br>
+ // runtime_error_check (::rtems_task_set_scheduler (RTEMS_SELF,<br>
+ // scheduler_id,<br>
+ // 1),<br>
+ // "set scheduler id");<br>
+ }<br>
+ }<br>
+<br>
+ void<br>
+ attributes::update ()<br>
+ {<br>
+ char buf[32];<br>
+ system_error_check (::pthread_getname_np (::pthread_self (),<br>
+ buf,<br>
+ sizeof (buf)),<br>
+ "getting name");<br>
+ name = buf;<br>
+<br>
+ int spolicy;<br>
+ struct sched_param sched_param;<br>
+ system_error_check (::pthread_getschedparam (::pthread_self (),<br>
+ &spolicy,<br>
+ &sched_param),<br>
+ "getting scheduler parameters");<br>
+<br>
+ switch (spolicy) {<br>
+ case SCHED_OTHER:<br>
+ policy = sched_other;<br>
+ break;<br>
+ case SCHED_FIFO:<br>
+ policy = sched_fifo;<br>
+ break;<br>
+ case SCHED_RR:<br>
+ policy = sched_roundrobin;<br>
+ break;<br>
+ case SCHED_SPORADIC:<br>
+ policy = sched_sporadic;<br>
+ break;<br>
+ default:<br>
+ system_error_check (EINVAL, "get scheduler policy");<br>
+ break;<br>
+ }<br>
+ priority = sched_param.sched_priority;<br>
+<br>
+ pthread_attr_t attr;<br>
+ system_error_check (::pthread_getattr_np (::pthread_self (), &attr),<br>
+ "getting thread attributes");<br>
+ system_error_check (::pthread_attr_getstacksize (&attr, &stack_size),<br>
+ "getting stack size");<br>
+ int inheritsched = 0;<br>
+ system_error_check (::pthread_attr_getinheritsched (&attr, &inheritsched),<br>
+ "getting inherited sheduler mode");<br>
+ switch (inheritsched) {<br>
+ case PTHREAD_INHERIT_SCHED:<br>
+ mode = sched_inherit;<br>
+ break;<br>
+ case PTHREAD_EXPLICIT_SCHED:<br>
+ mode = sched_explicit;<br>
+ break;<br>
+ default:<br>
+ system_error_check (EINVAL, "get scheduler mode");<br>
+ break;<br>
+ }<br>
+<br>
+ rtems_id scheduler_id;<br>
+ runtime_error_check (::rtems_task_get_scheduler (RTEMS_SELF, &scheduler_id));<br>
+#if HAVE_GET_SCHEDULER_NAME<br>
+ char name[5];<br>
+ if (!get_scheduler_name (scheduler_id, &name[0]))<br>
+ system_error_check (ENOENT, "get scheduler name");<br>
+ scheduler = name;<br>
+#endif<br>
+ }<br>
+<br>
+ attributes&<br>
+ attributes::operator= (const attributes& attr)<br>
+ {<br>
+ name = <a href="http://attr.name" rel="noreferrer noreferrer" target="_blank">attr.name</a>;<br>
+ priority = attr.priority;<br>
+ stack_size = attr.stack_size;<br>
+ mode = attr.mode;<br>
+ policy = attr.policy;<br>
+ return *this;<br>
+ }<br>
+<br>
+ bool<br>
+ attributes::operator== (const attributes& attr) const<br>
+ {<br>
+ return<br>
+ name == <a href="http://attr.name" rel="noreferrer noreferrer" target="_blank">attr.name</a> &&<br>
+ priority == attr.priority &&<br>
+ stack_size == attr.stack_size &&<br>
+ mode == attr.mode &&<br>
+ policy == attr.policy;<br>
+ }<br>
+<br>
+ void*<br>
+ thread_generic_entry (void* arg)<br>
+ {<br>
+ thread::state_ptr s{ static_cast<thread::state_base*> (arg) };<br>
+ try {<br>
+ s->run ();<br>
+ } catch (...) {<br>
+ std::terminate ();<br>
+ }<br>
+ return nullptr;<br>
+ }<br>
+<br>
+ thread&<br>
+ thread::operator= (thread&& thread_)<br>
+ {<br>
+ if (joinable ())<br>
+ std::terminate ();<br>
+ swap(thread_);<br>
+ return *this;<br>
+ }<br>
+<br>
+ void<br>
+ thread::swap(thread& thread_) noexcept<br>
+ {<br>
+ std::swap(id_, thread_.id_);<br>
+ }<br>
+<br>
+ bool<br>
+ thread::joinable() const noexcept<br>
+ {<br>
+ return !(id_ == id());<br>
+ }<br>
+<br>
+ thread::state_base::~state_base () = default;<br>
+<br>
+ void<br>
+ thread::start_thread (thread::state_ptr s)<br>
+ {<br>
+ const attributes attr = s->get_attributes ();<br>
+<br>
+ pthread_attr_t pattr;<br>
+<br>
+ system_error_check (::pthread_attr_init (&pattr),<br>
+ "attribute init");<br>
+<br>
+ system_error_check (::pthread_attr_setdetachstate (&pattr,<br>
+ PTHREAD_CREATE_DETACHED),<br>
+ "set detached state");<br>
+<br>
+ struct sched_param param;<br>
+ param.sched_priority = attr.get_priority ();<br>
+ system_error_check (::pthread_attr_setschedparam (&pattr, ¶m),<br>
+ "set ");<br>
+<br>
+ int spolicy;<br>
+ switch (attr.get_scheduler_policy ()) {<br>
+ case attributes::sched_other:<br>
+ spolicy = SCHED_OTHER;<br>
+ break;<br>
+ case attributes::sched_roundrobin:<br>
+ spolicy = SCHED_RR;<br>
+ break;<br>
+ case attributes::sched_sporadic:<br>
+ spolicy = SCHED_SPORADIC;<br>
+ break;<br>
+ default:<br>
+ spolicy = SCHED_FIFO;<br>
+ break;<br>
+ }<br>
+ system_error_check (::pthread_attr_setschedpolicy (&pattr, spolicy),<br>
+ "set scheduler policy");<br>
+<br>
+ if (attr.get_scheduler_mode () == attributes::sched_inherit)<br>
+ ::pthread_attr_setinheritsched (&pattr, PTHREAD_INHERIT_SCHED);<br>
+ else<br>
+ ::pthread_attr_setinheritsched (&pattr, PTHREAD_EXPLICIT_SCHED);<br>
+<br>
+ system_error_check (::pthread_attr_setstacksize(&pattr,<br>
+ attr.get_stack_size ()),<br>
+ "set stack size");<br>
+<br>
+ /*<br>
+ * Hold the new thread in the state's run handler until the rest<br>
+ * of the thread is set up after the create call.<br>
+ */<br>
+ system_error_check (::pthread_create (&id_.id_,<br>
+ &pattr,<br>
+ thread_generic_entry,<br>
+ s.get ()),<br>
+ "create thread");<br>
+<br>
+ system_error_check (::pthread_setname_np (id_.id_,<br>
+ attr.get_name ().c_str ()),<br>
+ "setting thread name");<br>
+<br>
+ ::pthread_attr_destroy (&pattr);<br>
+<br>
+ s.release ();<br>
+ };<br>
+ };<br>
+};<br>
diff --git a/spec/build/cpukit/grp.yml b/spec/build/cpukit/grp.yml<br>
index 3a285d03fc..91fa2d9625 100644<br>
--- a/spec/build/cpukit/grp.yml<br>
+++ b/spec/build/cpukit/grp.yml<br>
@@ -27,6 +27,8 @@ links:<br>
uid: libpppd<br>
- role: build-dependency<br>
uid: librtemscpu<br>
+- role: build-dependency<br>
+ uid: librtemscxx<br>
- role: build-dependency<br>
uid: librtemsdfltcfg<br>
- role: build-dependency<br>
diff --git a/spec/build/cpukit/librtemscxx.yml b/spec/build/cpukit/librtemscxx.yml<br>
new file mode 100644<br>
index 0000000000..769e5a7498<br>
--- /dev/null<br>
+++ b/spec/build/cpukit/librtemscxx.yml<br>
@@ -0,0 +1,21 @@<br>
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause<br>
+build-type: library<br>
+cflags: []<br>
+copyrights:<br>
+- Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+cppflags: []<br>
+cxxflags: [-std=c++17]<br>
+enabled-by: true<br>
+includes: []<br>
+install:<br>
+- destination: ${BSP_INCLUDEDIR}<br>
+ source:<br>
+ - cpukit/include/rtems/c++/error<br>
+ - cpukit/include/rtems/c++/thread<br>
+install-path: ${BSP_LIBDIR}<br>
+links: []<br>
+source:<br>
+- cpukit/librtemscxx/error.cc<br>
+- cpukit/librtemscxx/thread.cc<br>
+target: rtemscxx<br>
+type: build<br>
diff --git a/spec/build/testsuites/libtests/grp.yml b/spec/build/testsuites/libtests/grp.yml<br>
index 2b1f2727cf..b9ca014b0d 100644<br>
--- a/spec/build/testsuites/libtests/grp.yml<br>
+++ b/spec/build/testsuites/libtests/grp.yml<br>
@@ -214,6 +214,8 @@ links:<br>
uid: pwdgrp02<br>
- role: build-dependency<br>
uid: rbheap01<br>
+- role: build-dependency<br>
+ uid: rcxx01<br>
- role: build-dependency<br>
uid: read<br>
- role: build-dependency<br>
diff --git a/spec/build/testsuites/libtests/rcxx01.yml b/spec/build/testsuites/libtests/rcxx01.yml<br>
new file mode 100644<br>
index 0000000000..6d69feeb83<br>
--- /dev/null<br>
+++ b/spec/build/testsuites/libtests/rcxx01.yml<br>
@@ -0,0 +1,22 @@<br>
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause<br>
+build-type: test-program<br>
+cflags: []<br>
+copyrights:<br>
+- Copyright (C) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+cppflags: []<br>
+cxxflags: [-std=c++17]<br>
+enabled-by: true<br>
+features: c cxx cxxprogram<br>
+includes: []<br>
+ldflags: []<br>
+links: []<br>
+source:<br>
+- testsuites/libtests/rcxx01/init.c<br>
+- testsuites/libtests/rcxx01/thread.cc<br>
+stlib: []<br>
+target: testsuites/libtests/rcxx01.exe<br>
+type: build<br>
+use-after: []<br>
+use-before:<br>
+- rtemsdefaultconfig<br>
+- rtemscxx<br>
diff --git a/testsuites/libtests/rcxx01/init.c b/testsuites/libtests/rcxx01/init.c<br>
new file mode 100644<br>
index 0000000000..b3dfa9f0c1<br>
--- /dev/null<br>
+++ b/testsuites/libtests/rcxx01/init.c<br>
@@ -0,0 +1,69 @@<br>
+/*<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (c) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ * All rights reserved.<br>
+ */<br>
+<br>
+#ifdef HAVE_CONFIG_H<br>
+#include "config.h"<br>
+#endif<br>
+<br>
+#include <bsp.h><br>
+<br>
+#include <stdlib.h><br>
+#include <stdio.h><br>
+<br>
+#include <sys/types.h><br>
+#include <sys/stat.h><br>
+#include <fcntl.h><br>
+#include <sys/ioctl.h><br>
+#include <unistd.h><br>
+#include "tmacros.h"<br>
+<br>
+const char rtems_test_name[] = "RCXX 1";<br>
+<br>
+/* forward declarations to avoid warnings */<br>
+rtems_task Init(rtems_task_argument argument);<br>
+<br>
+void rcxx_run_test(void);<br>
+<br>
+rtems_task Init(<br>
+ rtems_task_argument ignored<br>
+)<br>
+{<br>
+ TEST_BEGIN();<br>
+<br>
+ rcxx_run_test();<br>
+<br>
+ TEST_END();<br>
+ rtems_test_exit( 0 );<br>
+}<br>
+<br>
+/* configuration information */<br>
+<br>
+#include <rtems/serial_mouse.h><br>
+<br>
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER<br>
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER<br>
+<br>
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5<br>
+<br>
+#define CONFIGURE_MEMORY_OVERHEAD (2024)<br>
+<br>
+#define CONFIGURE_MAXIMUM_TASKS 1<br>
+#define CONFIGURE_MAXIMUM_POSIX_THREADS 2<br>
+<br>
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION<br>
+<br>
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE<br>
+<br>
+#define CONFIGURE_INIT_TASK_STACK_SIZE (10U * 1024U)<br>
+<br>
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT<br>
+<br>
+#define CONFIGURE_INIT<br>
+<br>
+#include <rtems/confdefs.h><br>
+<br>
+/* end of file */<br>
diff --git a/testsuites/libtests/rcxx01/rcxx01.doc b/testsuites/libtests/rcxx01/rcxx01.doc<br>
new file mode 100644<br>
index 0000000000..3fd41b029b<br>
--- /dev/null<br>
+++ b/testsuites/libtests/rcxx01/rcxx01.doc<br>
@@ -0,0 +1,16 @@<br>
+# Copyright (c) 2019 Chris Johns <<a href="mailto:chrisj@rtems.org" target="_blank" rel="noreferrer">chrisj@rtems.org</a>><br>
+#<br>
+<br>
+This file describes the directives and concepts tested by this test set.<br>
+<br>
+test set name: rcxx01<br>
+<br>
+directives:<br>
+<br>
+ rtems::thread::thread<br>
+ rtems::thread::attributes<br>
+<br>
+concepts:<br>
+<br>
++ Create a thread using the default method, ie like std::thread.<br>
+* Create a thread with changed attributes.<br>
diff --git a/testsuites/libtests/rcxx01/rcxx01.scn b/testsuites/libtests/rcxx01/rcxx01.scn<br>
new file mode 100644<br>
index 0000000000..37bf2d3f7a<br>
--- /dev/null<br>
+++ b/testsuites/libtests/rcxx01/rcxx01.scn<br>
@@ -0,0 +1,13 @@<br>
+*** BEGIN OF TEST RCXX 1 ***<br>
+*** TEST VERSION: 5.0.0.7ba04a62227286dcd3da20ea7319d9c64b8f5fd1<br>
+*** TEST STATE: EXPECTED-PASS<br>
+*** TEST BUILD:<br>
+*** TEST TOOLS: 7.5.0 20191114 (RTEMS 5, RSB ceb811fa19ddcfdd449a8da8f1107e6e592727b6, Newlib d14714c69)<br>
+Thread: start: default<br>
+ 1 D<br>
+Thread: start: attr<br>
+ 2 R<br>
+Thread: end: default<br>
+Thread: end: attr<br>
+<br>
+*** END OF TEST RCXX 1 ***<br>
diff --git a/testsuites/libtests/rcxx01/thread.cc b/testsuites/libtests/rcxx01/thread.cc<br>
new file mode 100644<br>
index 0000000000..7cb64cea5a<br>
--- /dev/null<br>
+++ b/testsuites/libtests/rcxx01/thread.cc<br>
@@ -0,0 +1,90 @@<br>
+/*<br>
+ * SPDX-License-Identifier: BSD-2-Clause<br>
+ *<br>
+ * Copyright (c) 2020 Chris Johns (<a href="http://contemporary.software" rel="noreferrer noreferrer" target="_blank">http://contemporary.software</a>)<br>
+ * All rights reserved.<br>
+ */<br>
+<br>
+#include <chrono><br>
+#include <iostream><br>
+#include <thread><br>
+#include <mutex><br>
+<br>
+#include <rtems/c++/thread><br>
+<br>
+using namespace std::chrono_literals;<br>
+<br>
+extern "C" void rcxx_run_test(void);<br>
+<br>
+struct test_thread<br>
+{<br>
+ test_thread();<br>
+<br>
+ void start();<br>
+ bool running();<br>
+ void body(const char* title, int i, char c);<br>
+<br>
+ rtems::thread::thread thread_default;<br>
+ rtems::thread::thread thread_attr;<br>
+<br>
+ std::mutex mutex;<br>
+<br>
+ bool finished;<br>
+};<br>
+<br>
+test_thread::test_thread()<br>
+ : finished(false)<br>
+{<br>
+}<br>
+<br>
+void test_thread::start()<br>
+{<br>
+ thread_default = rtems::thread::thread(&test_thread::body, this,<br>
+ "default", 1, 'D');<br>
+<br>
+ rtems::thread::attributes attr;<br>
+<br>
+ attr.set_name("RTHREAD");<br>
+ attr.set_priority(5);<br>
+ attr.set_stack_size(32 * 1024);<br>
+<br>
+ thread_attr = rtems::thread::thread(attr, &test_thread::body, this,<br>
+ "attr", 2, 'R');<br>
+}<br>
+<br>
+void test_thread::body(const char* title, int i, char c)<br>
+{<br>
+ std::cout << "Thread: start: " << title << std::endl<br>
+ << ' ' << i << ' ' << c << std::endl;<br>
+<br>
+ size_t count = 5;<br>
+<br>
+ while (count--) {<br>
+ std::this_thread::sleep_for(1s);<br>
+ }<br>
+<br>
+ std::cout << "Thread: end: " << title << std::endl;<br>
+<br>
+ std::lock_guard<std::mutex> lock(mutex);<br>
+<br>
+ finished = true;<br>
+}<br>
+<br>
+bool test_thread::running()<br>
+{<br>
+ std::lock_guard<std::mutex> lock(mutex);<br>
+ return finished == false;<br>
+}<br>
+<br>
+void rcxx_run_test(void)<br>
+{<br>
+ try {<br>
+ test_thread tt;<br>
+ tt.start();<br>
+ while (tt.running())<br>
+ std::this_thread::sleep_for(1s);<br>
+ } catch (...) {<br>
+ std::cout << "Thread: ouch" << std::endl;<br>
+ throw;<br>
+ }<br>
+}<br>
-- <br>
2.24.1<br>
<br>
_______________________________________________<br>
devel mailing list<br>
<a href="mailto:devel@rtems.org" target="_blank" rel="noreferrer">devel@rtems.org</a><br>
<a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div></div></div>