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