Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:20

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2020 Chris Johns (http://contemporary.software)
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #if !defined(_GNU_SOURCE)
0029 #define _GNU_SOURCE
0030 #endif
0031 
0032 #include <system_error>
0033 
0034 #include <rtems/error.hpp>
0035 #include <rtems/thread.hpp>
0036 
0037 #include <pthread.h>
0038 
0039 #include <rtems.h>
0040 
0041 #if HAVE_GET_SCHEDULER_NAME
0042 extern "C" bool get_scheduler_name(rtems_id sid, char* name);
0043 #endif
0044 
0045 #if HAVE_GET_SCHEDULER_NAME
0046 bool get_scheduler_name(rtems_id sid, char* name)
0047 {
0048   name[0] = 'N';
0049   name[1] = 'O';
0050   name[2] = 'P';
0051   name[3] = '\0';
0052   return true;
0053 }
0054 #endif
0055 
0056 namespace rtems
0057 {
0058   namespace thread
0059   {
0060     void
0061     system_error_check(int ec, const char* what)
0062     {
0063       if (ec != 0) {
0064         throw std::system_error(ec, std::system_category(), what);
0065       }
0066     }
0067 
0068     attributes::attributes()
0069       : priority(-1),
0070         stack_size(RTEMS_MINIMUM_STACK_SIZE),
0071         attr(sched_inherit),
0072         policy(sched_fifo)
0073     {
0074       update();
0075     }
0076 
0077     attributes::attributes(const attributes& attr)
0078       : name(attr.name),
0079         priority(attr.priority),
0080         stack_size(attr.stack_size),
0081         scheduler(attr.scheduler),
0082         attr(attr.attr),
0083         policy(attr.policy)
0084     {
0085     }
0086 
0087     void
0088     attributes::set_name(const std::string& name_)
0089     {
0090       name = name_;
0091     }
0092 
0093     void
0094     attributes::set_name(const char* name_)
0095     {
0096       name = name_;
0097     }
0098 
0099     const std::string&
0100     attributes::get_name() const
0101     {
0102       return name;
0103     }
0104 
0105     void
0106     attributes::set_priority(int priority_)
0107     {
0108       priority = priority_;
0109     }
0110 
0111     int
0112     attributes::get_priority() const
0113     {
0114       return priority;
0115     }
0116 
0117     void
0118     attributes::set_stack_size(size_t size)
0119     {
0120       stack_size = size;
0121     }
0122 
0123     size_t
0124     attributes::get_stack_size() const
0125     {
0126       return stack_size;
0127     }
0128 
0129     void
0130     attributes::set_scheduler(const std::string& scheduler_)
0131     {
0132       scheduler = scheduler_;
0133     }
0134 
0135     void
0136     attributes::set_scheduler(const char* scheduler_)
0137     {
0138       scheduler = scheduler_;
0139     }
0140 
0141     const std::string&
0142     attributes::get_scheduler()
0143     {
0144       return scheduler;
0145     }
0146 
0147     attributes::sched_attr
0148     attributes::get_scheduler_attr() const
0149     {
0150       return attr;
0151     }
0152 
0153     void
0154     attributes::set_scheduler_policy(sched_policy policy_)
0155     {
0156       attr = sched_explicit;
0157       policy = policy_;
0158     }
0159 
0160     attributes::sched_policy
0161     attributes::get_scheduler_policy() const
0162     {
0163       return policy;
0164     }
0165 
0166     void
0167     attributes::commit()
0168     {
0169       pthread_t pid = ::pthread_self();
0170 
0171       system_error_check(::pthread_setname_np(pid, name.c_str()),
0172                          "getting name");
0173 
0174       int                spolicy;
0175       struct sched_param sched_param;
0176 
0177       system_error_check(::pthread_getschedparam(::pthread_self(),
0178                                                  &spolicy,
0179                                                  &sched_param),
0180                          "getting scheduler parameters");
0181 
0182       switch (policy) {
0183       case sched_other:
0184         spolicy = SCHED_OTHER;
0185         break;
0186       case sched_fifo:
0187         spolicy = SCHED_FIFO;
0188         break;
0189       case sched_roundrobin:
0190         spolicy = SCHED_RR;
0191         break;
0192       case sched_sporadic:
0193         spolicy = SCHED_SPORADIC;
0194         break;
0195       default:
0196         system_error_check(EINVAL, "get scheduler policy");
0197         break;
0198       }
0199 
0200       sched_param.sched_priority = priority;
0201 
0202       system_error_check(::pthread_setschedparam(::pthread_self(),
0203                                                  spolicy,
0204                                                  &sched_param),
0205                          "getting scheduler parameters");
0206 
0207       if (!scheduler.empty()) {
0208         char sname[4] = { ' ', ' ', ' ', ' ' };
0209         for (size_t c = 0; c < sizeof(sname); ++c) {
0210           if (c >= scheduler.length()) {
0211             break;
0212           }
0213           sname[c] = scheduler[c];
0214         }
0215         rtems_name scheduler_name = rtems_build_name(sname[0],
0216                                                      sname[1],
0217                                                      sname[2],
0218                                                      sname[3]);
0219         rtems_id scheduler_id;
0220         runtime_error_check(::rtems_scheduler_ident(scheduler_name,
0221                                                     &scheduler_id),
0222                             "get scheduler id");
0223         // runtime_error_check (::rtems_task_set_scheduler (RTEMS_SELF,
0224         //                                                  scheduler_id,
0225         //                                                  1),
0226         //                      "set scheduler id");
0227       }
0228     }
0229 
0230     void
0231     attributes::update()
0232     {
0233       char buf[32];
0234       system_error_check(::pthread_getname_np(::pthread_self(),
0235                                               buf,
0236                                               sizeof (buf)),
0237                          "getting name");
0238       name = buf;
0239 
0240       int                spolicy;
0241       struct sched_param sched_param;
0242       system_error_check(::pthread_getschedparam(::pthread_self(),
0243                                                  &spolicy,
0244                                                  &sched_param),
0245                          "getting scheduler parameters");
0246 
0247       switch (spolicy) {
0248       case SCHED_OTHER:
0249         policy = sched_other;
0250         break;
0251       case SCHED_FIFO:
0252         policy = sched_fifo;
0253         break;
0254       case SCHED_RR:
0255         policy = sched_roundrobin;
0256         break;
0257       case SCHED_SPORADIC:
0258         policy = sched_sporadic;
0259         break;
0260       default:
0261         system_error_check(EINVAL, "get scheduler policy");
0262         break;
0263       }
0264       priority = sched_param.sched_priority;
0265 
0266       pthread_attr_t pattr;
0267       system_error_check(::pthread_getattr_np(::pthread_self(), &pattr),
0268                          "getting thread attributes");
0269       system_error_check(::pthread_attr_getstacksize(&pattr, &stack_size),
0270                          "getting stack size");
0271       int inheritsched = 0;
0272       system_error_check(::pthread_attr_getinheritsched(&pattr, &inheritsched),
0273                          "getting inherited sheduler attribute");
0274       switch (inheritsched) {
0275       case PTHREAD_INHERIT_SCHED:
0276         attr = sched_inherit;
0277         break;
0278       case PTHREAD_EXPLICIT_SCHED:
0279         attr = sched_explicit;
0280         break;
0281       default:
0282         system_error_check(EINVAL, "get scheduler attribute");
0283         break;
0284       }
0285 
0286       rtems_id scheduler_id;
0287       runtime_error_check(::rtems_task_get_scheduler(RTEMS_SELF, &scheduler_id));
0288 #if HAVE_GET_SCHEDULER_NAME
0289       char name[5];
0290       if (!get_scheduler_name(scheduler_id, &name[0])) {
0291         system_error_check(ENOENT, "get scheduler name");
0292       }
0293       scheduler = name;
0294 #endif
0295     }
0296 
0297     attributes&
0298     attributes::operator=(const attributes& other)
0299     {
0300       name = other.name;
0301       priority = other.priority;
0302       stack_size = other.stack_size;
0303       attr = other.attr;
0304       policy = other.policy;
0305       return *this;
0306     }
0307 
0308     bool
0309     attributes::operator==(const attributes& other) const
0310     {
0311       return
0312         name == other.name &&
0313         priority == other.priority &&
0314         stack_size == other.stack_size &&
0315         attr == other.attr &&
0316         policy == other.policy;
0317     }
0318 
0319     void*
0320     thread_generic_entry(void* arg)
0321     {
0322       thread::state_ptr s{ static_cast<thread::state_base*>(arg) };
0323       try {
0324         s->run();
0325       } catch (...) {
0326         std::terminate();
0327       }
0328       return nullptr;
0329     }
0330 
0331     thread&
0332     thread::operator=(thread&& thread_)
0333     {
0334       if (joinable()) {
0335         std::terminate();
0336       }
0337       swap(thread_);
0338       return *this;
0339     }
0340 
0341     void
0342     thread::swap(thread& thread_) noexcept
0343     {
0344       std::swap(id_, thread_.id_);
0345     }
0346 
0347     bool
0348     thread::joinable() const noexcept
0349     {
0350       return !(id_ == id());
0351     }
0352 
0353     void
0354     thread::join()
0355     {
0356       if (!joinable()) {
0357         system_error_check(EINVAL, "join");
0358       }
0359       system_error_check(::pthread_join(id_.id_, nullptr), "join");
0360       id_ = id();
0361     }
0362 
0363     void
0364     thread::detach()
0365     {
0366       if (!joinable()) {
0367         system_error_check(EINVAL, "detach");
0368       }
0369       system_error_check(::pthread_detach(id_.id_), "detach");
0370       id_ = id();
0371     }
0372 
0373     thread::state_base::~state_base() = default;
0374 
0375     void
0376     thread::start_thread(thread::state_ptr s)
0377     {
0378       const attributes attr = s->get_attributes();
0379 
0380       pthread_attr_t pattr;
0381 
0382       system_error_check(::pthread_attr_init(&pattr),
0383                          "attribute init");
0384 
0385       struct sched_param param;
0386       param.sched_priority = attr.get_priority();
0387       system_error_check(::pthread_attr_setschedparam(&pattr, &param),
0388                          "set sched param");
0389 
0390       int spolicy;
0391       switch (attr.get_scheduler_policy()) {
0392       case attributes::sched_other:
0393         spolicy = SCHED_OTHER;
0394         break;
0395       case attributes::sched_roundrobin:
0396         spolicy = SCHED_RR;
0397         break;
0398       case attributes::sched_sporadic:
0399         spolicy = SCHED_SPORADIC;
0400         break;
0401       default:
0402         spolicy = SCHED_FIFO;
0403         break;
0404       }
0405       system_error_check(::pthread_attr_setschedpolicy(&pattr, spolicy),
0406                          "set scheduler policy");
0407 
0408       if (attr.get_scheduler_attr() == attributes::sched_inherit) {
0409         ::pthread_attr_setinheritsched(&pattr, PTHREAD_INHERIT_SCHED);
0410       }
0411       else {
0412         ::pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
0413       }
0414 
0415       system_error_check(::pthread_attr_setstacksize(&pattr,
0416                                                      attr.get_stack_size()),
0417                          "set stack size");
0418 
0419       /*
0420        * Hold the new thread in the state's run handler until the rest
0421        * of the thread is set up after the create call.
0422        */
0423       system_error_check(::pthread_create(&id_.id_,
0424                                           &pattr,
0425                                           thread_generic_entry,
0426                                           s.get()),
0427                          "create thread");
0428 
0429       system_error_check(::pthread_setname_np(id_.id_,
0430                                               attr.get_name().c_str()),
0431                          "setting thread name");
0432 
0433       ::pthread_attr_destroy(&pattr);
0434 
0435       s.release();
0436     };
0437   };
0438 };