<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, &param),<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>