From cf95826089f36a42a69a1b12691e453428c0b2af Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 3 Oct 2020 16:13:24 +1000 Subject: cpukit/librcxx: Add a C++ thread interface with attributes --- cpukit/librtemscxx/error.cpp | 76 ++++++++ cpukit/librtemscxx/thread.cpp | 416 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 492 insertions(+) create mode 100644 cpukit/librtemscxx/error.cpp create mode 100644 cpukit/librtemscxx/thread.cpp (limited to 'cpukit/librtemscxx') diff --git a/cpukit/librtemscxx/error.cpp b/cpukit/librtemscxx/error.cpp new file mode 100644 index 0000000000..ba46a8c2a5 --- /dev/null +++ b/cpukit/librtemscxx/error.cpp @@ -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 + +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.cpp b/cpukit/librtemscxx/thread.cpp new file mode 100644 index 0000000000..11bf3df230 --- /dev/null +++ b/cpukit/librtemscxx/thread.cpp @@ -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 + +#include +#include + +#include + +#include + +#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), + attr (sched_inherit), + policy (sched_fifo) + { + update (); + } + + attributes::attributes (const attributes& attr) + : name (attr.name), + priority (attr.priority), + stack_size (attr.stack_size), + scheduler (attr.scheduler), + attr (attr.attr), + 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_attr + attributes::get_scheduler_attr () const + { + return attr; + } + + void + attributes::set_scheduler_policy (sched_policy policy_) + { + attr = 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 pattr; + system_error_check (::pthread_getattr_np (::pthread_self (), &pattr), + "getting thread attributes"); + system_error_check (::pthread_attr_getstacksize (&pattr, &stack_size), + "getting stack size"); + int inheritsched = 0; + system_error_check (::pthread_attr_getinheritsched (&pattr, &inheritsched), + "getting inherited sheduler attribute"); + switch (inheritsched) { + case PTHREAD_INHERIT_SCHED: + attr = sched_inherit; + break; + case PTHREAD_EXPLICIT_SCHED: + attr = sched_explicit; + break; + default: + system_error_check (EINVAL, "get scheduler attribute"); + 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& other) + { + name = other.name; + priority = other.priority; + stack_size = other.stack_size; + attr = other.attr; + policy = other.policy; + return *this; + } + + bool + attributes::operator== (const attributes& other) const + { + return + name == other.name && + priority == other.priority && + stack_size == other.stack_size && + attr == other.attr && + policy == other.policy; + } + + void* + thread_generic_entry (void* arg) + { + thread::state_ptr s{ static_cast (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_attr () == 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 (); + }; + }; +}; -- cgit v1.2.3