<div dir="ltr">It's OK to commit. <div><br></div><div>riscv and sparc leon3 should work with clang. But I also wondered (didn't mentioned) if you had tried this as a native wrapper. It may be testable on FreeBSD or Linux as well. Ensuring that may give it a little more visibility. One of the things users seem to like is the high portability.</div><div><br></div><div>--joel</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Oct 4, 2020 at 3:49 AM Chris Johns <<a href="mailto:chrisj@rtems.org">chrisj@rtems.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 3/10/20 10:21 pm, Joel Sherrill wrote:<br>
> Will this show up in documentation somewhere? <br>
<br>
Yes this is what I am planing. I was thinking of adding a Languages section to<br>
the User manual and this would be part of the C++ section. We would need C and<br>
Ada added.<br>
<br>
> It does seem like we should say something about C++ threads and this. <br>
<br>
Yes I agree.<br>
<br>
> What about C11 threads?<br>
<br>
That is C? This is about c++17 support.<br>
<br>
> Test doesn't appear to cover much. <br>
<br>
It tests:<br>
<br>
- The standard C++ thread equivalent interface works:<br>
<br>
thread_default = rtems::thread::thread(&test_thread::body, this,<br>
"default", 1, 'D');<br>
<br>
This checks the right constructor is selected. This thread should have the same<br>
thread attributes and the standard library call.<br>
<br>
- Inherit the current thread attributes with this single line:<br>
<br>
rtems::thread::attributes attr;<br>
<br>
- Modify the attributes:<br>
<br>
attr.set_name("RTHREAD");<br>
attr.set_priority(5);<br>
attr.set_stack_size(32 * 1024);<br>
<br>
- Create a thread with these new attributes:<br>
<br>
thread_attr = rtems::thread::thread(attr, &test_thread::body, this,<br>
"attr", 2, 'R');<br>
<br>
Th test makes sure the hidden complexity needed to handle the variable template<br>
arguments, move those to a new thread context and then have them made available<br>
to thread body all work.<br>
<br>
- Some more of the attributes could be tested.<br>
<br>
> More interspersed<br>
> <br>
<br>
Great, comments with them. Thanks for the review.<br>
<br>
Chris<br>
<br>
> <br>
> On Sat, Oct 3, 2020, 1:23 AM <<a href="mailto:chrisj@rtems.org" target="_blank">chrisj@rtems.org</a> <mailto:<a href="mailto:chrisj@rtems.org" target="_blank">chrisj@rtems.org</a>>> wrote:<br>
> <br>
> From: Chris Johns <<a href="mailto:chrisj@rtems.org" target="_blank">chrisj@rtems.org</a> <mailto:<a href="mailto:chrisj@rtems.org" target="_blank">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" 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<br>
> <br>
> +<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&<br>
> 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" 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.<br>
> <br>
> <br>
> The thread appears to be a POSIX thread. <br>
> <br>
<br>
It uses `pthread_setname_np` to set the name.<br>
<br>
> + *<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<br>
> <br>
> + * ignored.<br>
> <br>
> Is there a line break missing before the note?<br>
<br>
I will fix this.<br>
<br>
> + */<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>
> <br>
> <br>
> Since we have clang on some targets, any idea what it does and if this will<br>
> work? Should it disable itself for not GCC?<br>
<br>
Are there clang tools available? I would have tested clang if I could but I have<br>
no idea how to build clang for RTEMS and which BSPs are supported?<br>
<br>
I would prefer we support clang be supported. It should be hard to make this<br>
happen if you are able to follow how these templates work. It does get involved.<br>
<br>
> + 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>
> <br>
> <br>
> Equivalent<br>
<br>
I have spell checked the patch and fixed the mistakes.<br>
<br>
> + * 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<br>
> 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" 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<br>
> (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" 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" target="_blank">attr.name</a> <<a href="http://attr.name" rel="noreferrer" target="_blank">http://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,<br>
> &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,<br>
> &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" target="_blank">attr.name</a> <<a href="http://attr.name" rel="noreferrer" target="_blank">http://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" target="_blank">attr.name</a> <<a href="http://attr.name" rel="noreferrer" target="_blank">http://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>
> + <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<br>
> 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" 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<br>
> 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<br>
> 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" 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<br>
> 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" 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<br>
> 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">chrisj@rtems.org</a> <mailto:<a href="mailto:chrisj@rtems.org" target="_blank">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<br>
> 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<br>
> 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<br>
> 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" 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">devel@rtems.org</a> <mailto:<a href="mailto:devel@rtems.org" target="_blank">devel@rtems.org</a>><br>
> <a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
> <br>
</blockquote></div>