From c899b2746b3b499af1c26e85771fde2b8dd0d6dc Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Apr 2026 10:46:31 +0200 Subject: [PATCH 01/19] Cleanup: All starts with uspace --- src/rtapi/rtapi_pci.cc | 2 +- src/rtapi/uspace_common.h | 2 +- src/rtapi/uspace_rtai.cc | 2 +- src/rtapi/{rtapi_uspace.hh => uspace_rtapi.hh} | 0 src/rtapi/uspace_rtapi_app.cc | 2 +- src/rtapi/uspace_rtapi_parport.cc | 2 +- src/rtapi/uspace_xenomai.cc | 2 +- src/rtapi/uspace_xenomai_evl.cc | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename src/rtapi/{rtapi_uspace.hh => uspace_rtapi.hh} (100%) diff --git a/src/rtapi/rtapi_pci.cc b/src/rtapi/rtapi_pci.cc index f3e71844515..a490d906e9f 100644 --- a/src/rtapi/rtapi_pci.cc +++ b/src/rtapi/rtapi_pci.cc @@ -34,7 +34,7 @@ #include #include #include -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #include #include diff --git a/src/rtapi/uspace_common.h b/src/rtapi/uspace_common.h index 9c82c3a397e..6524aec2132 100644 --- a/src/rtapi/uspace_common.h +++ b/src/rtapi/uspace_common.h @@ -39,7 +39,7 @@ static msg_level_t msg_level = RTAPI_MSG_ERR; /* message printing level */ #include "config.h" #ifdef RTAPI -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #endif typedef struct { diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index ff5f9d784ed..27ff9be464b 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnarrowing" #include diff --git a/src/rtapi/rtapi_uspace.hh b/src/rtapi/uspace_rtapi.hh similarity index 100% rename from src/rtapi/rtapi_uspace.hh rename to src/rtapi/uspace_rtapi.hh diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index 30a159dc983..9e3d213d073 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -56,7 +56,7 @@ #include "rtapi.h" #include #include "hal/hal_priv.h" -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" std::atomic_int WithRoot::level; static uid_t euid, ruid; diff --git a/src/rtapi/uspace_rtapi_parport.cc b/src/rtapi/uspace_rtapi_parport.cc index f396837c71f..027ffe80ff5 100644 --- a/src/rtapi/uspace_rtapi_parport.cc +++ b/src/rtapi/uspace_rtapi_parport.cc @@ -19,7 +19,7 @@ #include #include #include -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #include #include #include diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index c3c6e432ea5..23fb4565eef 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #include #include #include diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index b4f65f2f4c2..7cb35990c4f 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "rtapi_uspace.hh" +#include "uspace_rtapi.hh" #include From 414fd3e757d508a119aff5a43d1d0fe2505aee47 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Apr 2026 11:11:24 +0200 Subject: [PATCH 02/19] Cleanup: Separate some classes --- src/rtapi/Submakefile | 1 + src/rtapi/uspace_rtapi.cc | 163 +++++++++++++++++++++++++++++++++ src/rtapi/uspace_rtapi.hh | 2 + src/rtapi/uspace_rtapi_app.cc | 165 +--------------------------------- 4 files changed, 168 insertions(+), 163 deletions(-) create mode 100644 src/rtapi/uspace_rtapi.cc diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index a51231dc1af..3a1f2d46908 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -32,6 +32,7 @@ $(patsubst ./rtapi/%,../include/%,$(RTAPIINCS)): ../include/%.h: ./rtapi/%.h ifeq ($(BUILD_SYS),uspace) RTAPI_APP_SRCS := \ + rtapi/uspace_rtapi.cc \ rtapi/uspace_rtapi_app.cc \ rtapi/uspace_rtapi_parport.cc \ rtapi/uspace_rtapi_string.c \ diff --git a/src/rtapi/uspace_rtapi.cc b/src/rtapi/uspace_rtapi.cc new file mode 100644 index 00000000000..649a562663c --- /dev/null +++ b/src/rtapi/uspace_rtapi.cc @@ -0,0 +1,163 @@ +#include "rtapi.h" +#include "uspace_rtapi.hh" + +std::atomic_int WithRoot::level; +uid_t euid, ruid; + +WithRoot::WithRoot() { + if(!level++) { +#ifdef __linux__ + setfsuid(euid); +#endif + } +} + +WithRoot::~WithRoot() { + if(!--level) { +#ifdef __linux__ + setfsuid(ruid); +#endif + } +} + +rtapi_task::rtapi_task() + : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, + period{}, nextstart{}, + ratio{}, pll_correction{}, pll_correction_limit{}, + arg{}, taskcode{} + +{} + +/* Priority functions. Uspace uses POSIX task priorities. */ + +int RtapiApp::prio_highest() const +{ + return sched_get_priority_max(policy); +} + +int RtapiApp::prio_lowest() const +{ + return sched_get_priority_min(policy); +} + +int RtapiApp::prio_higher_delta() const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + return 1; + } + return -1; +} + +int RtapiApp::prio_bound(int prio) const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + if (prio >= rtapi_prio_highest()) + return rtapi_prio_highest(); + if (prio < rtapi_prio_lowest()) + return rtapi_prio_lowest(); + } else { + if (prio <= rtapi_prio_highest()) + return rtapi_prio_highest(); + if (prio > rtapi_prio_lowest()) + return rtapi_prio_lowest(); + } + return prio; +} + +bool RtapiApp::prio_check(int prio) const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + return (prio <= rtapi_prio_highest()) && (prio >= rtapi_prio_lowest()); + } else { + return (prio <= rtapi_prio_lowest()) && (prio >= rtapi_prio_highest()); + } +} + +int RtapiApp::prio_next_higher(int prio) const +{ + prio = prio_bound(prio); + if(prio != rtapi_prio_highest()) + return prio + prio_higher_delta(); + return prio; +} + +int RtapiApp::prio_next_lower(int prio) const +{ + prio = prio_bound(prio); + if(prio != rtapi_prio_lowest()) + return prio - prio_higher_delta(); + return prio; +} + +int RtapiApp::allocate_task_id() +{ + for(int n=0; nid = n; + task->owner = owner; + task->uses_fp = uses_fp; + task->arg = arg; + task->stacksize = stacksize; + task->taskcode = taskcode; + task->prio = prio; + task->magic = TASK_MAGIC; + task_array[n] = task; + + /* and return handle to the caller */ + + return n; +} + +rtapi_task *RtapiApp::get_task(int task_id) { + if(task_id < 0 || task_id >= MAX_TASKS) return NULL; + /* validate task handle */ + rtapi_task *task = task_array[task_id]; + if(!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) + return NULL; + + return task; +} + +void RtapiApp::unexpected_realtime_delay(rtapi_task *task, int /*nperiod*/) { + static int printed = 0; + if(!printed) + { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unexpected realtime delay on task %d with period %ld\n" + "This Message will only display once per session.\n" + "Run the Latency Test and resolve before continuing.\n", + task->id, task->period); + printed = 1; + } +} + +long RtapiApp::clock_set_period(long nsecs) +{ + if(nsecs == 0) return period; + if(period != 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); + return -EINVAL; + } + period = nsecs; + return period; +} \ No newline at end of file diff --git a/src/rtapi/uspace_rtapi.hh b/src/rtapi/uspace_rtapi.hh index bc589c12536..863dc9266fe 100644 --- a/src/rtapi/uspace_rtapi.hh +++ b/src/rtapi/uspace_rtapi.hh @@ -115,5 +115,7 @@ int find_rt_cpu_number(); extern struct rtapi_task *task_array[MAX_TASKS]; +extern uid_t euid, ruid; //ToDo: Improve + #define WITH_ROOT WithRoot root #endif diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index 9e3d213d073..ae9f8b0b35f 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -56,28 +56,7 @@ #include "rtapi.h" #include #include "hal/hal_priv.h" -#include "uspace_rtapi.hh" - -std::atomic_int WithRoot::level; -static uid_t euid, ruid; - -#include "rtapi/uspace_common.h" - -WithRoot::WithRoot() { - if(!level++) { -#ifdef __linux__ - setfsuid(euid); -#endif - } -} - -WithRoot::~WithRoot() { - if(!--level) { -#ifdef __linux__ - setfsuid(ruid); -#endif - } -} +#include "uspace_common.h" namespace { @@ -625,14 +604,6 @@ struct rtapi_module { #define MAX_MODULES 64 #define MODULE_OFFSET 32768 -rtapi_task::rtapi_task() - : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, - period{}, nextstart{}, - ratio{}, pll_correction{}, pll_correction_limit{}, - arg{}, taskcode{} - -{} - namespace { struct PosixTask : rtapi_task @@ -887,129 +858,6 @@ RtapiApp &App() /* data for all tasks */ struct rtapi_task *task_array[MAX_TASKS]; -/* Priority functions. Uspace uses POSIX task priorities. */ - -int RtapiApp::prio_highest() const -{ - return sched_get_priority_max(policy); -} - -int RtapiApp::prio_lowest() const -{ - return sched_get_priority_min(policy); -} - -int RtapiApp::prio_higher_delta() const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - return 1; - } - return -1; -} - -int RtapiApp::prio_bound(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - if (prio >= rtapi_prio_highest()) - return rtapi_prio_highest(); - if (prio < rtapi_prio_lowest()) - return rtapi_prio_lowest(); - } else { - if (prio <= rtapi_prio_highest()) - return rtapi_prio_highest(); - if (prio > rtapi_prio_lowest()) - return rtapi_prio_lowest(); - } - return prio; -} - -bool RtapiApp::prio_check(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - return (prio <= rtapi_prio_highest()) && (prio >= rtapi_prio_lowest()); - } else { - return (prio <= rtapi_prio_lowest()) && (prio >= rtapi_prio_highest()); - } -} - -int RtapiApp::prio_next_higher(int prio) const -{ - prio = prio_bound(prio); - if(prio != rtapi_prio_highest()) - return prio + prio_higher_delta(); - return prio; -} - -int RtapiApp::prio_next_lower(int prio) const -{ - prio = prio_bound(prio); - if(prio != rtapi_prio_lowest()) - return prio - prio_higher_delta(); - return prio; -} - -int RtapiApp::allocate_task_id() -{ - for(int n=0; nid = n; - task->owner = owner; - task->uses_fp = uses_fp; - task->arg = arg; - task->stacksize = stacksize; - task->taskcode = taskcode; - task->prio = prio; - task->magic = TASK_MAGIC; - task_array[n] = task; - - /* and return handle to the caller */ - - return n; -} - -rtapi_task *RtapiApp::get_task(int task_id) { - if(task_id < 0 || task_id >= MAX_TASKS) return NULL; - /* validate task handle */ - rtapi_task *task = task_array[task_id]; - if(!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) - return NULL; - - return task; -} - -void RtapiApp::unexpected_realtime_delay(rtapi_task *task, int /*nperiod*/) { - static int printed = 0; - if(!printed) - { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unexpected realtime delay on task %d with period %ld\n" - "This Message will only display once per session.\n" - "Run the Latency Test and resolve before continuing.\n", - task->id, task->period); - printed = 1; - } -} - int Posix::task_delete(int id) { auto task = ::rtapi_get_task(id); @@ -1285,16 +1133,7 @@ long rtapi_clock_set_period(long nsecs) return App().clock_set_period(nsecs); } -long RtapiApp::clock_set_period(long nsecs) -{ - if(nsecs == 0) return period; - if(period != 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); - return -EINVAL; - } - period = nsecs; - return period; -} + int rtapi_task_new(void (*taskcode) (void*), void *arg, From 6ba453a9fba61132eb13862c9631ff2f46a30596 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Apr 2026 11:43:34 +0200 Subject: [PATCH 03/19] Cleanup: Split out posix --- src/rtapi/Submakefile | 1 + src/rtapi/uspace_common.h | 1 + src/rtapi/uspace_rtapi.cc | 94 +++++++++ src/rtapi/uspace_rtapi.hh | 1 + src/rtapi/uspace_rtapi_app.cc | 337 +------------------------------- src/rtapi/uspace_rtapi_posix.cc | 213 ++++++++++++++++++++ src/rtapi/uspace_rtapi_posix.hh | 40 ++++ 7 files changed, 351 insertions(+), 336 deletions(-) create mode 100644 src/rtapi/uspace_rtapi_posix.cc create mode 100644 src/rtapi/uspace_rtapi_posix.hh diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index 3a1f2d46908..a1699a7016d 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -34,6 +34,7 @@ ifeq ($(BUILD_SYS),uspace) RTAPI_APP_SRCS := \ rtapi/uspace_rtapi.cc \ rtapi/uspace_rtapi_app.cc \ + rtapi/uspace_rtapi_posix.cc \ rtapi/uspace_rtapi_parport.cc \ rtapi/uspace_rtapi_string.c \ rtapi/rtapi_pci.cc diff --git a/src/rtapi/uspace_common.h b/src/rtapi/uspace_common.h index 6524aec2132..636e72d665f 100644 --- a/src/rtapi/uspace_common.h +++ b/src/rtapi/uspace_common.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/src/rtapi/uspace_rtapi.cc b/src/rtapi/uspace_rtapi.cc index 649a562663c..b33f0512d9c 100644 --- a/src/rtapi/uspace_rtapi.cc +++ b/src/rtapi/uspace_rtapi.cc @@ -1,6 +1,10 @@ #include "rtapi.h" #include "uspace_rtapi.hh" +#include +#include +#include + std::atomic_int WithRoot::level; uid_t euid, ruid; @@ -160,4 +164,94 @@ long RtapiApp::clock_set_period(long nsecs) } period = nsecs; return period; +} + +//parse_cpu_list from https://gitlab.com/Xenomai/xenomai4/libevl/-/blob/11e6a1fb183a315ae861762e7650fd5e10d83ff5/tests/helpers.c +//License: MIT +static void parse_cpu_list(const char *path, cpu_set_t *cpuset) +{ + char *p, *range, *range_p = NULL, *id, *id_r; + int start, end, cpu; + char buf[BUFSIZ]; + FILE *fp; + + CPU_ZERO(cpuset); + + fp = fopen(path, "r"); + if (fp == NULL) + return; + + if (!fgets(buf, sizeof(buf), fp)) + goto out; + + p = buf; + while ((range = strtok_r(p, ",", &range_p)) != NULL) { + if (*range == '\0' || *range == '\n') + goto next; + end = -1; + id = strtok_r(range, "-", &id_r); + if (id) { + start = atoi(id); + id = strtok_r(NULL, "-", &id_r); + if (id) + end = atoi(id); + else if (end < 0) + end = start; + for (cpu = start; cpu <= end; cpu++) + CPU_SET(cpu, cpuset); + } + next: + p = NULL; + } +out: + fclose(fp); +} + +int find_rt_cpu_number() { + if(getenv("RTAPI_CPU_NUMBER")) return atoi(getenv("RTAPI_CPU_NUMBER")); + +#ifdef __linux__ + const char* isolated_file="/sys/devices/system/cpu/isolated"; + cpu_set_t cpuset; + + parse_cpu_list(isolated_file, &cpuset); + + //Print list + rtapi_print_msg(RTAPI_MSG_INFO, "cpuset isolated "); + for(int i=0; i #include "hal/hal_priv.h" #include "uspace_common.h" +#include "uspace_rtapi_posix.hh" -namespace -{ RtapiApp &App(); struct message_t { @@ -70,24 +69,6 @@ struct message_t { boost::lockfree::queue> rtapi_msg_queue; -static void set_namef(const char *fmt, ...) { - char *buf = NULL; - va_list ap; - - va_start(ap, fmt); - if (vasprintf(&buf, fmt, ap) < 0) { - va_end(ap); - return; - } - va_end(ap); - - int res = pthread_setname_np(pthread_self(), buf); - if (res) { - fprintf(stderr, "pthread_setname_np() failed for %s: %d\n", buf, res); - } - free(buf); -} - pthread_t queue_thread; void *queue_function(void * /*arg*/) { set_namef("rtapi_app:mesg"); @@ -106,7 +87,6 @@ void *queue_function(void * /*arg*/) { } return nullptr; } -} static int sim_rtapi_run_threads(int fd, int (*callback)(int fd)); @@ -604,62 +584,6 @@ struct rtapi_module { #define MAX_MODULES 64 #define MODULE_OFFSET 32768 -namespace -{ -struct PosixTask : rtapi_task -{ - PosixTask() : rtapi_task{}, thr{} - {} - - pthread_t thr; /* thread's context */ -}; - -struct Posix : RtapiApp -{ - Posix(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { - pthread_once(&key_once, init_key); - if(do_thread_lock) { - pthread_once(&lock_once, init_lock); - } - } - int task_delete(int id); - int task_start(int task_id, unsigned long period_nsec); - int task_pause(int task_id); - int task_resume(int task_id); - int task_self(); - long long task_pll_get_reference(void); - int task_pll_set_correction(long value); - void wait(); - struct rtapi_task *do_task_new() { - return new PosixTask; - } - unsigned char do_inb(unsigned int port); - void do_outb(unsigned char value, unsigned int port); - int run_threads(int fd, int (*callback)(int fd)); - static void *wrapper(void *arg); - bool do_thread_lock; - - static pthread_once_t key_once; - static pthread_key_t key; - static void init_key(void) { - pthread_key_create(&key, NULL); - } - - static pthread_once_t lock_once; - static pthread_mutex_t thread_lock; - static void init_lock(void) { - pthread_mutex_init(&thread_lock, NULL); - } - - long long do_get_time(void) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000LL + ts.tv_nsec; - } - - void do_delay(long ns); -}; - static void signal_handler(int sig, siginfo_t * /*si*/, void * /*uctx*/) { switch (sig) { @@ -854,260 +778,9 @@ RtapiApp &App() return *app; } -} /* data for all tasks */ struct rtapi_task *task_array[MAX_TASKS]; -int Posix::task_delete(int id) -{ - auto task = ::rtapi_get_task(id); - if(!task) return -EINVAL; - - pthread_cancel(task->thr); - pthread_join(task->thr, 0); - task->magic = 0; - task_array[id] = 0; - delete task; - return 0; -} - -//parse_cpu_list from https://gitlab.com/Xenomai/xenomai4/libevl/-/blob/11e6a1fb183a315ae861762e7650fd5e10d83ff5/tests/helpers.c -//License: MIT -static void parse_cpu_list(const char *path, cpu_set_t *cpuset) -{ - char *p, *range, *range_p = NULL, *id, *id_r; - int start, end, cpu; - char buf[BUFSIZ]; - FILE *fp; - - CPU_ZERO(cpuset); - - fp = fopen(path, "r"); - if (fp == NULL) - return; - - if (!fgets(buf, sizeof(buf), fp)) - goto out; - - p = buf; - while ((range = strtok_r(p, ",", &range_p)) != NULL) { - if (*range == '\0' || *range == '\n') - goto next; - end = -1; - id = strtok_r(range, "-", &id_r); - if (id) { - start = atoi(id); - id = strtok_r(NULL, "-", &id_r); - if (id) - end = atoi(id); - else if (end < 0) - end = start; - for (cpu = start; cpu <= end; cpu++) - CPU_SET(cpu, cpuset); - } - next: - p = NULL; - } -out: - fclose(fp); -} - -int find_rt_cpu_number() { - if(getenv("RTAPI_CPU_NUMBER")) return atoi(getenv("RTAPI_CPU_NUMBER")); - -#ifdef __linux__ - const char* isolated_file="/sys/devices/system/cpu/isolated"; - cpu_set_t cpuset; - - parse_cpu_list(isolated_file, &cpuset); - - //Print list - rtapi_print_msg(RTAPI_MSG_INFO, "cpuset isolated "); - for(int i=0; i(task_id); - if(!task) return -EINVAL; - - if(period_nsec < (unsigned long)period) period_nsec = (unsigned long)period; - task->period = period_nsec; - task->ratio = period_nsec / period; - - struct sched_param param; - memset(¶m, 0, sizeof(param)); - param.sched_priority = task->prio; - - // limit PLL correction values to +/-1% of cycle time - task->pll_correction_limit = period_nsec / 100; - task->pll_correction = 0; - - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); - - pthread_attr_t attr; - int ret; - if((ret = pthread_attr_init(&attr)) != 0) - return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) - return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) - return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) - return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) - return -ret; - if(nprocs > 1) { - const static int rt_cpu_number = find_rt_cpu_number(); - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); - if(rt_cpu_number != -1) { -#ifdef __FreeBSD__ - cpuset_t cpuset; -#else - cpu_set_t cpuset; -#endif - CPU_ZERO(&cpuset); - CPU_SET(rt_cpu_number, &cpuset); - if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) - return -ret; - } - } - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) - return -ret; - - return 0; -} - -#define RTAPI_CLOCK (CLOCK_MONOTONIC) - -pthread_once_t Posix::key_once = PTHREAD_ONCE_INIT; -pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; -pthread_key_t Posix::key; -pthread_mutex_t Posix::thread_lock; - -void *Posix::wrapper(void *arg) -{ - struct rtapi_task *task; - - /* use the argument to point to the task data */ - task = (struct rtapi_task*)arg; - long int period = App().period; - if(task->period < period) task->period = period; - task->ratio = task->period / period; - task->period = task->ratio * period; - rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %lu ratio=%u\n", - task, task->period, task->ratio); - - pthread_setspecific(key, arg); - set_namef("rtapi_app:T#%d", task->id); - - Posix &papp = reinterpret_cast(App()); - if(papp.do_thread_lock) - pthread_mutex_lock(&papp.thread_lock); - - struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); - rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); - - /* call the task function with the task argument */ - (task->taskcode) (task->arg); - - rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); - return NULL; -} - -long long Posix::task_pll_get_reference(void) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return 0; - return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; -} - -int Posix::task_pll_set_correction(long value) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - if (value > task->pll_correction_limit) value = task->pll_correction_limit; - if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); - task->pll_correction = value; - return 0; -} - -int Posix::task_pause(int) { - return -ENOSYS; -} - -int Posix::task_resume(int) { - return -ENOSYS; -} - -int Posix::task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - return task->id; -} - -void Posix::wait() { - if(do_thread_lock) - pthread_mutex_unlock(&thread_lock); - pthread_testcancel(); - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); - struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); - if(rtapi_timespec_less(task->nextstart, now)) - { - if(policy == SCHED_FIFO) - unexpected_realtime_delay(task); - } - else - { - int res = rtapi_clock_nanosleep(RTAPI_CLOCK, TIMER_ABSTIME, &task->nextstart, nullptr, &now); - if(res < 0) perror("clock_nanosleep"); - } - if(do_thread_lock) - pthread_mutex_lock(&thread_lock); -} - -unsigned char Posix::do_inb(unsigned int port) -{ -#ifdef HAVE_SYS_IO_H - return inb(port); -#else - (void)port; - return 0; -#endif -} - -void Posix::do_outb(unsigned char val, unsigned int port) -{ -#ifdef HAVE_SYS_IO_H - return outb(val, port); -#else - (void)val; - (void)port; -#endif -} - -void Posix::do_delay(long ns) { - struct timespec ts = {0, ns}; - rtapi_clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL, NULL); -} int rtapi_prio_highest(void) { return App().prio_highest(); @@ -1133,9 +806,6 @@ long rtapi_clock_set_period(long nsecs) return App().clock_set_period(nsecs); } - - - int rtapi_task_new(void (*taskcode) (void*), void *arg, int prio, int owner, unsigned long int stacksize, int uses_fp) { return App().task_new(taskcode, arg, prio, owner, stacksize, uses_fp); @@ -1199,11 +869,6 @@ long int simple_strtol(const char *nptr, char **endptr, int base) { return strtol(nptr, endptr, base); } -int Posix::run_threads(int fd, int(*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } - return 0; -} - int sim_rtapi_run_threads(int fd, int (*callback)(int fd)) { return App().run_threads(fd, callback); } diff --git a/src/rtapi/uspace_rtapi_posix.cc b/src/rtapi/uspace_rtapi_posix.cc new file mode 100644 index 00000000000..d7f2d5e9522 --- /dev/null +++ b/src/rtapi/uspace_rtapi_posix.cc @@ -0,0 +1,213 @@ +#include "uspace_rtapi_posix.hh" +#include "rtapi.h" +#include "uspace_common.h" + +#include +#include +#include +#ifdef HAVE_SYS_IO_H +#include +#endif + +struct PosixTask : rtapi_task +{ + PosixTask() : rtapi_task{}, thr{} + {} + + pthread_t thr; /* thread's context */ +}; + +Posix::Posix(int policy) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { + pthread_once(&key_once, init_key); + if(do_thread_lock) { + pthread_once(&lock_once, init_lock); + } +} + +int Posix::task_delete(int id) +{ + auto task = ::rtapi_get_task(id); + if(!task) return -EINVAL; + + pthread_cancel(task->thr); + pthread_join(task->thr, 0); + task->magic = 0; + task_array[id] = 0; + delete task; + return 0; +} + +int Posix::task_start(int task_id, unsigned long int period_nsec) +{ + auto task = ::rtapi_get_task(task_id); + if(!task) return -EINVAL; + + if(period_nsec < (unsigned long)period) period_nsec = (unsigned long)period; + task->period = period_nsec; + task->ratio = period_nsec / period; + + struct sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = task->prio; + + // limit PLL correction values to +/-1% of cycle time + task->pll_correction_limit = period_nsec / 100; + task->pll_correction = 0; + + int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); + + pthread_attr_t attr; + int ret; + if((ret = pthread_attr_init(&attr)) != 0) + return -ret; + if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + return -ret; + if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + return -ret; + if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + return -ret; + if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + return -ret; + if(nprocs > 1) { + const static int rt_cpu_number = find_rt_cpu_number(); + rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); + if(rt_cpu_number != -1) { +#ifdef __FreeBSD__ + cpuset_t cpuset; +#else + cpu_set_t cpuset; +#endif + CPU_ZERO(&cpuset); + CPU_SET(rt_cpu_number, &cpuset); + if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) + return -ret; + } + } + if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + return -ret; + + return 0; +} + +#define RTAPI_CLOCK (CLOCK_MONOTONIC) + +pthread_once_t Posix::key_once = PTHREAD_ONCE_INIT; +pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; +pthread_key_t Posix::key; +pthread_mutex_t Posix::thread_lock; + +void *Posix::wrapper(void *arg) +{ + struct rtapi_task *task; + + /* use the argument to point to the task data */ + task = (struct rtapi_task*)arg; + long int period = App().period; + if(task->period < period) task->period = period; + task->ratio = task->period / period; + task->period = task->ratio * period; + rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %lu ratio=%u\n", + task, task->period, task->ratio); + + pthread_setspecific(key, arg); + set_namef("rtapi_app:T#%d", task->id); + + Posix &papp = reinterpret_cast(App()); + if(papp.do_thread_lock) + pthread_mutex_lock(&papp.thread_lock); + + struct timespec now; + clock_gettime(RTAPI_CLOCK, &now); + rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); + + /* call the task function with the task argument */ + (task->taskcode) (task->arg); + + rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); + return NULL; +} + +long long Posix::task_pll_get_reference(void) { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return 0; + return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; +} + +int Posix::task_pll_set_correction(long value) { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return -EINVAL; + if (value > task->pll_correction_limit) value = task->pll_correction_limit; + if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); + task->pll_correction = value; + return 0; +} + +int Posix::task_pause(int) { + return -ENOSYS; +} + +int Posix::task_resume(int) { + return -ENOSYS; +} + +int Posix::task_self() { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return -EINVAL; + return task->id; +} + +void Posix::wait() { + if(do_thread_lock) + pthread_mutex_unlock(&thread_lock); + pthread_testcancel(); + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); + struct timespec now; + clock_gettime(RTAPI_CLOCK, &now); + if(rtapi_timespec_less(task->nextstart, now)) + { + if(policy == SCHED_FIFO) + unexpected_realtime_delay(task); + } + else + { + int res = rtapi_clock_nanosleep(RTAPI_CLOCK, TIMER_ABSTIME, &task->nextstart, nullptr, &now); + if(res < 0) perror("clock_nanosleep"); + } + if(do_thread_lock) + pthread_mutex_lock(&thread_lock); +} + +struct rtapi_task *Posix::do_task_new() { + return new PosixTask; +} + +unsigned char Posix::do_inb(unsigned int port) +{ +#ifdef HAVE_SYS_IO_H + return inb(port); +#else + (void)port; + return 0; +#endif +} + +void Posix::do_outb(unsigned char val, unsigned int port) +{ +#ifdef HAVE_SYS_IO_H + return outb(val, port); +#else + (void)val; + (void)port; +#endif +} + +void Posix::do_delay(long ns) { + struct timespec ts = {0, ns}; + rtapi_clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL, NULL); +} + +int Posix::run_threads(int fd, int(*callback)(int fd)) { + while(callback(fd)) { /* nothing */ } + return 0; +} \ No newline at end of file diff --git a/src/rtapi/uspace_rtapi_posix.hh b/src/rtapi/uspace_rtapi_posix.hh new file mode 100644 index 00000000000..c36b102fd3a --- /dev/null +++ b/src/rtapi/uspace_rtapi_posix.hh @@ -0,0 +1,40 @@ +#include "uspace_rtapi.hh" + +struct Posix : RtapiApp +{ + Posix(int policy = SCHED_FIFO); + int task_delete(int id); + int task_start(int task_id, unsigned long period_nsec); + int task_pause(int task_id); + int task_resume(int task_id); + int task_self(); + long long task_pll_get_reference(void); + int task_pll_set_correction(long value); + void wait(); + struct rtapi_task *do_task_new(); + unsigned char do_inb(unsigned int port); + void do_outb(unsigned char value, unsigned int port); + int run_threads(int fd, int (*callback)(int fd)); + static void *wrapper(void *arg); + bool do_thread_lock; + + static pthread_once_t key_once; + static pthread_key_t key; + static void init_key(void) { + pthread_key_create(&key, NULL); + } + + static pthread_once_t lock_once; + static pthread_mutex_t thread_lock; + static void init_lock(void) { + pthread_mutex_init(&thread_lock, NULL); + } + + long long do_get_time(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; + } + + void do_delay(long ns); +}; \ No newline at end of file From 0da86215dd35d22dbb135ca09f4ea4ae39e5e0ae Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Apr 2026 12:47:07 +0200 Subject: [PATCH 04/19] Cleanup: Fix build --- src/rtapi/uspace_rtapi_posix.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rtapi/uspace_rtapi_posix.cc b/src/rtapi/uspace_rtapi_posix.cc index d7f2d5e9522..16ed447dabc 100644 --- a/src/rtapi/uspace_rtapi_posix.cc +++ b/src/rtapi/uspace_rtapi_posix.cc @@ -1,6 +1,5 @@ #include "uspace_rtapi_posix.hh" #include "rtapi.h" -#include "uspace_common.h" #include #include @@ -96,6 +95,8 @@ pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; pthread_key_t Posix::key; pthread_mutex_t Posix::thread_lock; +extern RtapiApp &App(); //ToDo: Nicer + void *Posix::wrapper(void *arg) { struct rtapi_task *task; @@ -171,7 +172,7 @@ void Posix::wait() { } else { - int res = rtapi_clock_nanosleep(RTAPI_CLOCK, TIMER_ABSTIME, &task->nextstart, nullptr, &now); + int res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr); if(res < 0) perror("clock_nanosleep"); } if(do_thread_lock) @@ -204,7 +205,7 @@ void Posix::do_outb(unsigned char val, unsigned int port) void Posix::do_delay(long ns) { struct timespec ts = {0, ns}; - rtapi_clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL, NULL); + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); } int Posix::run_threads(int fd, int(*callback)(int fd)) { From 805ce64ddb3d2878241febd8f1ed32fb81f9034f Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 15:45:12 +0200 Subject: [PATCH 05/19] Cleanup: Handle posix the same way as others --- src/rtapi/Submakefile | 10 ++- ...{uspace_rtapi_posix.cc => uspace_posix.cc} | 90 +++++++++++++++---- src/rtapi/uspace_rtai.cc | 7 +- src/rtapi/uspace_rtapi_app.cc | 40 ++++----- src/rtapi/uspace_rtapi_posix.hh | 40 --------- src/rtapi/uspace_xenomai.cc | 7 +- src/rtapi/uspace_xenomai_evl.cc | 7 +- 7 files changed, 113 insertions(+), 88 deletions(-) rename src/rtapi/{uspace_rtapi_posix.cc => uspace_posix.cc} (72%) delete mode 100644 src/rtapi/uspace_rtapi_posix.hh diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index a1699a7016d..d89a6601d01 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -34,7 +34,6 @@ ifeq ($(BUILD_SYS),uspace) RTAPI_APP_SRCS := \ rtapi/uspace_rtapi.cc \ rtapi/uspace_rtapi_app.cc \ - rtapi/uspace_rtapi_posix.cc \ rtapi/uspace_rtapi_parport.cc \ rtapi/uspace_rtapi_string.c \ rtapi/rtapi_pci.cc @@ -49,6 +48,15 @@ $(call TOOBJSDEPS, $(RTAPI_APP_SRCS)): EXTRAFLAGS += -DSIM \ TARGETS += ../bin/rtapi_app endif +USPACE_POSIX_SRCS := rtapi/uspace_posix.cc +USERSRCS += $(USPACE_POSIX_SRCS) +$(call TOOBJSDEPS, $(USPACE_POSIX_SRCS)): EXTRAFLAGS += -pthread -fPIC +../lib/libuspace-posix.so.0: $(call TOOBJS, $(USPACE_POSIX_SRCS)) + $(ECHO) Linking $(notdir $@) + $(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ -Wl,-soname,$(notdir $@) +TARGETS += ../lib/libuspace-posix.so.0 +TARGETS += ../lib/libuspace-posix.so + ifeq ($(CONFIG_USPACE_RTAI),y) USPACE_RTAI_SRCS := rtapi/uspace_rtai.cc USERSRCS += $(USPACE_RTAI_SRCS) diff --git a/src/rtapi/uspace_rtapi_posix.cc b/src/rtapi/uspace_posix.cc similarity index 72% rename from src/rtapi/uspace_rtapi_posix.cc rename to src/rtapi/uspace_posix.cc index 16ed447dabc..a50a0fab877 100644 --- a/src/rtapi/uspace_rtapi_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -1,13 +1,16 @@ -#include "uspace_rtapi_posix.hh" +#include "config.h" #include "rtapi.h" - +#include "uspace_rtapi.hh" #include #include #include +#include #ifdef HAVE_SYS_IO_H #include #endif +namespace +{ struct PosixTask : rtapi_task { PosixTask() : rtapi_task{}, thr{} @@ -16,12 +19,59 @@ struct PosixTask : rtapi_task pthread_t thr; /* thread's context */ }; -Posix::Posix(int policy) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { - pthread_once(&key_once, init_key); - if(do_thread_lock) { - pthread_once(&lock_once, init_lock); +struct Posix : RtapiApp +{ + Posix(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { + if(instance != nullptr){ + throw std::invalid_argument("Only one instance allowed!"); + } + pthread_once(&key_once, init_key); + if(do_thread_lock) { + pthread_once(&lock_once, init_lock); + } + instance = this; + } + int task_delete(int id); + int task_start(int task_id, unsigned long period_nsec); + int task_pause(int task_id); + int task_resume(int task_id); + int task_self(); + long long task_pll_get_reference(void); + int task_pll_set_correction(long value); + void wait(); + struct rtapi_task *do_task_new(){ + return new PosixTask; + } + unsigned char do_inb(unsigned int port); + void do_outb(unsigned char value, unsigned int port); + int run_threads(int fd, int (*callback)(int fd)); + static void *wrapper(void *arg); + bool do_thread_lock; + + static pthread_once_t key_once; + static pthread_key_t key; + static void init_key(void) { + pthread_key_create(&key, NULL); } -} + + static pthread_once_t lock_once; + static pthread_mutex_t thread_lock; + static void init_lock(void) { + pthread_mutex_init(&thread_lock, NULL); + } + + long long do_get_time(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; + } + + void do_delay(long ns); + + static Posix* instance; +}; + +Posix* Posix::instance=nullptr; int Posix::task_delete(int id) { @@ -95,15 +145,14 @@ pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; pthread_key_t Posix::key; pthread_mutex_t Posix::thread_lock; -extern RtapiApp &App(); //ToDo: Nicer - void *Posix::wrapper(void *arg) { struct rtapi_task *task; /* use the argument to point to the task data */ task = (struct rtapi_task*)arg; - long int period = App().period; + + long int period = instance->period; if(task->period < period) task->period = period; task->ratio = task->period / period; task->period = task->ratio * period; @@ -113,9 +162,8 @@ void *Posix::wrapper(void *arg) pthread_setspecific(key, arg); set_namef("rtapi_app:T#%d", task->id); - Posix &papp = reinterpret_cast(App()); - if(papp.do_thread_lock) - pthread_mutex_lock(&papp.thread_lock); + if(instance->do_thread_lock) + pthread_mutex_lock(&instance->thread_lock); struct timespec now; clock_gettime(RTAPI_CLOCK, &now); @@ -179,10 +227,6 @@ void Posix::wait() { pthread_mutex_lock(&thread_lock); } -struct rtapi_task *Posix::do_task_new() { - return new PosixTask; -} - unsigned char Posix::do_inb(unsigned int port) { #ifdef HAVE_SYS_IO_H @@ -211,4 +255,16 @@ void Posix::do_delay(long ns) { int Posix::run_threads(int fd, int(*callback)(int fd)) { while(callback(fd)) { /* nothing */ } return 0; +} +} + +extern "C" RtapiApp *make(int policy); + +RtapiApp *make(int policy) { + if(policy == SCHED_OTHER){ + rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX non-realtime\n"); + }else{ + rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX realtime\n"); + } + return new Posix(policy); } \ No newline at end of file diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index 27ff9be464b..7cbd1776d82 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -191,9 +191,10 @@ pthread_once_t RtaiApp::key_once; pthread_key_t RtaiApp::key; } -extern "C" RtapiApp *make(); +extern "C" RtapiApp *make(int policy); -RtapiApp *make() { +RtapiApp *make(int policy) { + (void) policy; rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using LXRT realtime\n"); - return app = new RtaiApp; + return app = new RtaiApp(); } diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index bcbf097edac..2ed201bfb00 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -57,7 +57,6 @@ #include #include "hal/hal_priv.h" #include "uspace_common.h" -#include "uspace_rtapi_posix.hh" RtapiApp &App(); @@ -740,37 +739,36 @@ static int harden_rt() return 0; } +static RtapiApp *makeDllApp(string dllName, int policy){ + void *dll = nullptr; + dll = dlopen(dllName.c_str(), RTLD_NOW); + if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); + auto fn = reinterpret_cast(dlsym(dll, "make")); + if(!fn) fprintf(stderr, "dlopen: %s\n", dlerror()); + auto result = fn ? fn(policy) : nullptr; + if(result) { + return result; + }else{ + throw invalid_argument("Could not load DLL!"); + } +} static RtapiApp *makeApp() { if(euid != 0 || harden_rt() < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX non-realtime\n"); - return new Posix(SCHED_OTHER); + return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); } WithRoot r; - void *dll = nullptr; if(detect_xenomai_evl()) { - dll = dlopen(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", RTLD_NOW); - if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); + return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); }else if(detect_xenomai()) { - dll = dlopen(EMC2_HOME "/lib/libuspace-xenomai.so.0", RTLD_NOW); - if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); + return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); } else if(detect_rtai()) { - dll = dlopen(EMC2_HOME "/lib/libuspace-rtai.so.0", RTLD_NOW); - if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); - } - if(dll) - { - auto fn = reinterpret_cast(dlsym(dll, "make")); - if(!fn) fprintf(stderr, "dlopen: %s\n", dlerror()); - auto result = fn ? fn() : nullptr; - if(result) { - return result; - } + return makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); + } else { + return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); } - rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX realtime\n"); - return new Posix(SCHED_FIFO); } RtapiApp &App() { diff --git a/src/rtapi/uspace_rtapi_posix.hh b/src/rtapi/uspace_rtapi_posix.hh deleted file mode 100644 index c36b102fd3a..00000000000 --- a/src/rtapi/uspace_rtapi_posix.hh +++ /dev/null @@ -1,40 +0,0 @@ -#include "uspace_rtapi.hh" - -struct Posix : RtapiApp -{ - Posix(int policy = SCHED_FIFO); - int task_delete(int id); - int task_start(int task_id, unsigned long period_nsec); - int task_pause(int task_id); - int task_resume(int task_id); - int task_self(); - long long task_pll_get_reference(void); - int task_pll_set_correction(long value); - void wait(); - struct rtapi_task *do_task_new(); - unsigned char do_inb(unsigned int port); - void do_outb(unsigned char value, unsigned int port); - int run_threads(int fd, int (*callback)(int fd)); - static void *wrapper(void *arg); - bool do_thread_lock; - - static pthread_once_t key_once; - static pthread_key_t key; - static void init_key(void) { - pthread_key_create(&key, NULL); - } - - static pthread_once_t lock_once; - static pthread_mutex_t thread_lock; - static void init_lock(void) { - pthread_mutex_init(&thread_lock, NULL); - } - - long long do_get_time(void) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000LL + ts.tv_nsec; - } - - void do_delay(long ns); -}; \ No newline at end of file diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index 23fb4565eef..7e917e18f9b 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -198,9 +198,10 @@ pthread_once_t XenomaiApp::key_once; pthread_key_t XenomaiApp::key; } -extern "C" RtapiApp *make(); +extern "C" RtapiApp *make(int policy); -RtapiApp *make() { +RtapiApp *make(int policy) { + (void) policy; rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI (posix-skin) realtime\n"); - return new XenomaiApp; + return new XenomaiApp(); } diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index 7cb35990c4f..ec52548779d 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -218,9 +218,10 @@ pthread_once_t XenomaiApp::key_once; pthread_key_t XenomaiApp::key; } -extern "C" RtapiApp *make(); +extern "C" RtapiApp *make(int policy); -RtapiApp *make() { +RtapiApp *make(int policy) { + (void) policy; rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI4 EVL realtime\n"); - return new XenomaiApp; + return new XenomaiApp(); } From 27f9d1a3b4ab30195a96c675d26cfa5858f2c6e6 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 16:09:46 +0200 Subject: [PATCH 06/19] Cleanup: Make posix the same as others --- src/rtapi/uspace_posix.cc | 373 +++++++++++++++----------------- src/rtapi/uspace_rtai.cc | 2 +- src/rtapi/uspace_xenomai.cc | 6 +- src/rtapi/uspace_xenomai_evl.cc | 6 +- 4 files changed, 188 insertions(+), 199 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index a50a0fab877..85bc8072140 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -21,6 +21,8 @@ struct PosixTask : rtapi_task struct Posix : RtapiApp { + #define RTAPI_CLOCK (CLOCK_MONOTONIC) + Posix(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { if(instance != nullptr){ throw std::invalid_argument("Only one instance allowed!"); @@ -31,231 +33,214 @@ struct Posix : RtapiApp } instance = this; } - int task_delete(int id); - int task_start(int task_id, unsigned long period_nsec); - int task_pause(int task_id); - int task_resume(int task_id); - int task_self(); - long long task_pll_get_reference(void); - int task_pll_set_correction(long value); - void wait(); - struct rtapi_task *do_task_new(){ - return new PosixTask; - } - unsigned char do_inb(unsigned int port); - void do_outb(unsigned char value, unsigned int port); - int run_threads(int fd, int (*callback)(int fd)); - static void *wrapper(void *arg); - bool do_thread_lock; - static pthread_once_t key_once; - static pthread_key_t key; - static void init_key(void) { - pthread_key_create(&key, NULL); - } + int task_delete(int id) { + auto task = ::rtapi_get_task(id); + if(!task) return -EINVAL; - static pthread_once_t lock_once; - static pthread_mutex_t thread_lock; - static void init_lock(void) { - pthread_mutex_init(&thread_lock, NULL); + pthread_cancel(task->thr); + pthread_join(task->thr, 0); + task->magic = 0; + task_array[id] = 0; + delete task; + return 0; } - long long do_get_time(void) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000LL + ts.tv_nsec; + int task_start(int task_id, unsigned long period_nsec) { + auto task = ::rtapi_get_task(task_id); + if(!task) return -EINVAL; + + if(period_nsec < (unsigned long)period) period_nsec = (unsigned long)period; + task->period = period_nsec; + task->ratio = period_nsec / period; + + struct sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = task->prio; + + // limit PLL correction values to +/-1% of cycle time + task->pll_correction_limit = period_nsec / 100; + task->pll_correction = 0; + + int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); + + pthread_attr_t attr; + int ret; + if((ret = pthread_attr_init(&attr)) != 0) + return -ret; + if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + return -ret; + if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + return -ret; + if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + return -ret; + if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + return -ret; + if(nprocs > 1){ + const static int rt_cpu_number = find_rt_cpu_number(); + rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); + if(rt_cpu_number != -1) { + #ifdef __FreeBSD__ + cpuset_t cpuset; + #else + cpu_set_t cpuset; + #endif + CPU_ZERO(&cpuset); + CPU_SET(rt_cpu_number, &cpuset); + if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) + return -ret; + } + } + if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + return -ret; + + return 0; } - void do_delay(long ns); + static void *wrapper(void *arg) { + struct rtapi_task *task; - static Posix* instance; -}; + /* use the argument to point to the task data */ + task = (struct rtapi_task*)arg; -Posix* Posix::instance=nullptr; + long int period = instance->period; + if(task->period < period) task->period = period; + task->ratio = task->period / period; + task->period = task->ratio * period; + rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %lu ratio=%u\n", + task, task->period, task->ratio); -int Posix::task_delete(int id) -{ - auto task = ::rtapi_get_task(id); - if(!task) return -EINVAL; - - pthread_cancel(task->thr); - pthread_join(task->thr, 0); - task->magic = 0; - task_array[id] = 0; - delete task; - return 0; -} + pthread_setspecific(key, arg); + set_namef("rtapi_app:T#%d", task->id); -int Posix::task_start(int task_id, unsigned long int period_nsec) -{ - auto task = ::rtapi_get_task(task_id); - if(!task) return -EINVAL; - - if(period_nsec < (unsigned long)period) period_nsec = (unsigned long)period; - task->period = period_nsec; - task->ratio = period_nsec / period; - - struct sched_param param; - memset(¶m, 0, sizeof(param)); - param.sched_priority = task->prio; - - // limit PLL correction values to +/-1% of cycle time - task->pll_correction_limit = period_nsec / 100; - task->pll_correction = 0; - - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); - - pthread_attr_t attr; - int ret; - if((ret = pthread_attr_init(&attr)) != 0) - return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) - return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) - return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) - return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) - return -ret; - if(nprocs > 1) { - const static int rt_cpu_number = find_rt_cpu_number(); - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); - if(rt_cpu_number != -1) { -#ifdef __FreeBSD__ - cpuset_t cpuset; -#else - cpu_set_t cpuset; -#endif - CPU_ZERO(&cpuset); - CPU_SET(rt_cpu_number, &cpuset); - if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) - return -ret; - } - } - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) - return -ret; - - return 0; -} + if(instance->do_thread_lock) + pthread_mutex_lock(&instance->thread_lock); -#define RTAPI_CLOCK (CLOCK_MONOTONIC) + struct timespec now; + clock_gettime(RTAPI_CLOCK, &now); + rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); -pthread_once_t Posix::key_once = PTHREAD_ONCE_INIT; -pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; -pthread_key_t Posix::key; -pthread_mutex_t Posix::thread_lock; + /* call the task function with the task argument */ + (task->taskcode) (task->arg); -void *Posix::wrapper(void *arg) -{ - struct rtapi_task *task; + rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); + return NULL; + } - /* use the argument to point to the task data */ - task = (struct rtapi_task*)arg; + int task_pause(int task_id) { + (void)task_id; + return -ENOSYS; + } - long int period = instance->period; - if(task->period < period) task->period = period; - task->ratio = task->period / period; - task->period = task->ratio * period; - rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %lu ratio=%u\n", - task, task->period, task->ratio); + int task_resume(int task_id) { + (void)task_id; + return -ENOSYS; + } - pthread_setspecific(key, arg); - set_namef("rtapi_app:T#%d", task->id); + long long task_pll_get_reference(void) { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return 0; + return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; + } - if(instance->do_thread_lock) - pthread_mutex_lock(&instance->thread_lock); + int task_pll_set_correction(long value) { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return -EINVAL; + if (value > task->pll_correction_limit) value = task->pll_correction_limit; + if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); + task->pll_correction = value; + return 0; + } - struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); - rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); + void wait() { + if(do_thread_lock) + pthread_mutex_unlock(&thread_lock); + pthread_testcancel(); + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); + struct timespec now; + clock_gettime(RTAPI_CLOCK, &now); + if(rtapi_timespec_less(task->nextstart, now)) + { + if(policy == SCHED_FIFO) + unexpected_realtime_delay(task); + } + else + { + int res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr); + if(res < 0) perror("clock_nanosleep"); + } + if(do_thread_lock) + pthread_mutex_lock(&thread_lock); + } - /* call the task function with the task argument */ - (task->taskcode) (task->arg); + struct rtapi_task *do_task_new() { + return new PosixTask; + } + unsigned char do_inb(unsigned int port) { +#ifdef HAVE_SYS_IO_H + return inb(port); +#else + (void)port; + return 0; +#endif + } - rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); - return NULL; -} + void do_outb(unsigned char val, unsigned int port) { +#ifdef HAVE_SYS_IO_H + return outb(val, port); +#else + (void)val; + (void)port; +#endif + } -long long Posix::task_pll_get_reference(void) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return 0; - return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; -} + int run_threads(int fd, int (*callback)(int fd)) { + while(callback(fd)) { /* nothing */ } + return 0; + } -int Posix::task_pll_set_correction(long value) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - if (value > task->pll_correction_limit) value = task->pll_correction_limit; - if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); - task->pll_correction = value; - return 0; -} + int task_self() { + struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); + if(!task) return -EINVAL; + return task->id; + } -int Posix::task_pause(int) { - return -ENOSYS; -} + bool do_thread_lock; -int Posix::task_resume(int) { - return -ENOSYS; -} + static pthread_once_t key_once; + static pthread_key_t key; + static void init_key(void) { + pthread_key_create(&key, NULL); + } -int Posix::task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - return task->id; -} + static pthread_once_t lock_once; + static pthread_mutex_t thread_lock; + static void init_lock(void) { + pthread_mutex_init(&thread_lock, NULL); + } -void Posix::wait() { - if(do_thread_lock) - pthread_mutex_unlock(&thread_lock); - pthread_testcancel(); - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); - struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); - if(rtapi_timespec_less(task->nextstart, now)) - { - if(policy == SCHED_FIFO) - unexpected_realtime_delay(task); + long long do_get_time() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; } - else - { - int res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr); - if(res < 0) perror("clock_nanosleep"); + + void do_delay(long ns) { + struct timespec ts = {0, ns}; + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); } - if(do_thread_lock) - pthread_mutex_lock(&thread_lock); -} -unsigned char Posix::do_inb(unsigned int port) -{ -#ifdef HAVE_SYS_IO_H - return inb(port); -#else - (void)port; - return 0; -#endif -} + static Posix* instance; +}; -void Posix::do_outb(unsigned char val, unsigned int port) -{ -#ifdef HAVE_SYS_IO_H - return outb(val, port); -#else - (void)val; - (void)port; -#endif -} +Posix* Posix::instance=nullptr; -void Posix::do_delay(long ns) { - struct timespec ts = {0, ns}; - clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); -} +pthread_once_t Posix::key_once = PTHREAD_ONCE_INIT; +pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; +pthread_key_t Posix::key; +pthread_mutex_t Posix::thread_lock; -int Posix::run_threads(int fd, int(*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } - return 0; -} } extern "C" RtapiApp *make(int policy); @@ -267,4 +252,4 @@ RtapiApp *make(int policy) { rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX realtime\n"); } return new Posix(policy); -} \ No newline at end of file +} diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index 7cbd1776d82..659f5f80a61 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -148,8 +148,8 @@ struct RtaiApp : RtapiApp { #ifdef HAVE_SYS_IO_H return outb(val, port); #else + (void)val; (void)port; - return 0; #endif } diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index 7e917e18f9b..e406ddb07c4 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -54,8 +54,8 @@ struct XenomaiApp : RtapiApp { int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); - int ret; pthread_attr_t attr; + int ret; if((ret = pthread_attr_init(&attr)) != 0) return -ret; if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) @@ -153,6 +153,7 @@ struct XenomaiApp : RtapiApp { #ifdef HAVE_SYS_IO_H return inb(port); #else + (void)port; return 0; #endif } @@ -161,7 +162,8 @@ struct XenomaiApp : RtapiApp { #ifdef HAVE_SYS_IO_H return outb(val, port); #else - return 0; + (void)val; + (void)port; #endif } diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index ec52548779d..f6ade19d12f 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -62,8 +62,8 @@ struct XenomaiApp : RtapiApp { int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); - int ret; pthread_attr_t attr; + int ret; if((ret = pthread_attr_init(&attr)) != 0) return -ret; if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) @@ -171,6 +171,7 @@ struct XenomaiApp : RtapiApp { #ifdef HAVE_SYS_IO_H return inb(port); #else + (void)port; return 0; #endif } @@ -179,7 +180,8 @@ struct XenomaiApp : RtapiApp { #ifdef HAVE_SYS_IO_H return outb(val, port); #else - return 0; + (void)val; + (void)port; #endif } From 050aa09038f268205d82023602d4f1db8eccf609 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 16:18:15 +0200 Subject: [PATCH 07/19] Cleanup: Naming --- src/rtapi/uspace_posix.cc | 7 ++++--- src/rtapi/uspace_rtai.cc | 7 +++++-- src/rtapi/uspace_xenomai.cc | 21 ++++++++++++--------- src/rtapi/uspace_xenomai_evl.cc | 31 +++++++++++++++++-------------- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index 85bc8072140..df3a5f6737d 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -34,6 +34,10 @@ struct Posix : RtapiApp instance = this; } + struct rtapi_task *do_task_new() { + return new PosixTask; + } + int task_delete(int id) { auto task = ::rtapi_get_task(id); if(!task) return -EINVAL; @@ -174,9 +178,6 @@ struct Posix : RtapiApp pthread_mutex_lock(&thread_lock); } - struct rtapi_task *do_task_new() { - return new PosixTask; - } unsigned char do_inb(unsigned int port) { #ifdef HAVE_SYS_IO_H return inb(port); diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index 659f5f80a61..eebc44b1b53 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -5,6 +5,7 @@ #pragma GCC diagnostic ignored "-Wnarrowing" #include #pragma GCC diagnostic pop +#include #ifdef HAVE_SYS_IO_H #include #endif @@ -31,7 +32,7 @@ struct RtaiApp : RtapiApp { pthread_once(&key_once, init_key); } - RtaiTask *do_task_new() { + struct rtapi_task *do_task_new() { return new RtaiTask; } @@ -194,7 +195,9 @@ pthread_key_t RtaiApp::key; extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - (void) policy; + if(policy != SCHED_FIFO){ + throw std::invalid_argument("Only SCHED_FIFO allowed"); + } rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using LXRT realtime\n"); return app = new RtaiApp(); } diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index e406ddb07c4..c4a509541bf 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -5,14 +5,15 @@ #include #include #include +#include #ifdef HAVE_SYS_IO_H #include #endif namespace { -struct RtaiTask : rtapi_task { - RtaiTask() : rtapi_task{}, cancel{}, thr{} {} +struct XenomaiTask : rtapi_task { + XenomaiTask() : rtapi_task{}, cancel{}, thr{} {} std::atomic_int cancel; pthread_t thr; }; @@ -23,12 +24,12 @@ struct XenomaiApp : RtapiApp { pthread_once(&key_once, init_key); } - RtaiTask *do_task_new() { - return new RtaiTask; + struct rtapi_task *do_task_new() { + return new XenomaiTask; } int task_delete(int id) { - auto task = ::rtapi_get_task(id); + auto task = ::rtapi_get_task(id); if(!task) return -EINVAL; task->cancel = 1; @@ -40,7 +41,7 @@ struct XenomaiApp : RtapiApp { } int task_start(int task_id, unsigned long period_nsec) { - auto task = ::rtapi_get_task(task_id); + auto task = ::rtapi_get_task(task_id); if(!task) return -EINVAL; task->period = period_nsec; @@ -84,7 +85,7 @@ struct XenomaiApp : RtapiApp { } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); struct timespec now; @@ -130,7 +131,7 @@ struct XenomaiApp : RtapiApp { void wait() { int task_id = task_self(); - auto task = ::rtapi_get_task(task_id); + auto task = ::rtapi_get_task(task_id); if(task->cancel) { pthread_exit(nullptr); } @@ -203,7 +204,9 @@ pthread_key_t XenomaiApp::key; extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - (void) policy; + if(policy != SCHED_FIFO){ + throw std::invalid_argument("Only SCHED_FIFO allowed"); + } rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI (posix-skin) realtime\n"); return new XenomaiApp(); } diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index f6ade19d12f..f6cde96c611 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -13,30 +13,31 @@ #include #include #include +#include #ifdef HAVE_SYS_IO_H #include #endif namespace { -struct RtaiTask : rtapi_task { - RtaiTask() : rtapi_task{}, cancel{}, thr{} {} +struct EvlTask : rtapi_task { + EvlTask() : rtapi_task{}, cancel{}, thr{} {} std::atomic_int cancel; pthread_t thr; }; -struct XenomaiApp : RtapiApp { - XenomaiApp() : RtapiApp(SCHED_FIFO) { +struct EvlApp : RtapiApp { + EvlApp() : RtapiApp(SCHED_FIFO) { pthread_once(&key_once, init_key); } - RtaiTask *do_task_new() { - return new RtaiTask; + struct rtapi_task *do_task_new() { + return new EvlTask; } int task_delete(int id) { - auto task = ::rtapi_get_task(id); + auto task = ::rtapi_get_task(id); if(!task) return -EINVAL; task->cancel = 1; @@ -48,7 +49,7 @@ struct XenomaiApp : RtapiApp { } int task_start(int task_id, unsigned long period_nsec) { - auto task = ::rtapi_get_task(task_id); + auto task = ::rtapi_get_task(task_id); if(!task) return -EINVAL; task->period = period_nsec; @@ -92,7 +93,7 @@ struct XenomaiApp : RtapiApp { } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); { @@ -148,7 +149,7 @@ struct XenomaiApp : RtapiApp { void wait() { int task_id = task_self(); - auto task = ::rtapi_get_task(task_id); + auto task = ::rtapi_get_task(task_id); if(task->cancel) { pthread_exit(nullptr); } @@ -216,14 +217,16 @@ struct XenomaiApp : RtapiApp { } }; -pthread_once_t XenomaiApp::key_once; -pthread_key_t XenomaiApp::key; +pthread_once_t EvlApp::key_once; +pthread_key_t EvlApp::key; } extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - (void) policy; + if(policy != SCHED_FIFO){ + throw std::invalid_argument("Only SCHED_FIFO allowed"); + } rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI4 EVL realtime\n"); - return new XenomaiApp(); + return new EvlApp(); } From ea0eb58000eace7c4ddfefa43ae822044ade7677 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 16:53:08 +0200 Subject: [PATCH 08/19] Cleanup: Renaming --- src/rtapi/Submakefile | 2 +- src/rtapi/rtapi_pci.cc | 2 +- src/rtapi/uspace_common.h | 2 +- src/rtapi/uspace_posix.cc | 2 +- src/rtapi/uspace_rtai.cc | 2 +- src/rtapi/uspace_rtapi.cc | 257 ---- src/rtapi/uspace_rtapi_app.cc | 1069 +++-------------- .../{uspace_rtapi.hh => uspace_rtapi_app.hh} | 0 src/rtapi/uspace_rtapi_main.cc | 936 +++++++++++++++ src/rtapi/uspace_rtapi_parport.cc | 2 +- src/rtapi/uspace_xenomai.cc | 2 +- src/rtapi/uspace_xenomai_evl.cc | 2 +- 12 files changed, 1139 insertions(+), 1139 deletions(-) delete mode 100644 src/rtapi/uspace_rtapi.cc rename src/rtapi/{uspace_rtapi.hh => uspace_rtapi_app.hh} (100%) create mode 100644 src/rtapi/uspace_rtapi_main.cc diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index d89a6601d01..92e1d2628ee 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -32,7 +32,7 @@ $(patsubst ./rtapi/%,../include/%,$(RTAPIINCS)): ../include/%.h: ./rtapi/%.h ifeq ($(BUILD_SYS),uspace) RTAPI_APP_SRCS := \ - rtapi/uspace_rtapi.cc \ + rtapi/uspace_rtapi_main.cc \ rtapi/uspace_rtapi_app.cc \ rtapi/uspace_rtapi_parport.cc \ rtapi/uspace_rtapi_string.c \ diff --git a/src/rtapi/rtapi_pci.cc b/src/rtapi/rtapi_pci.cc index a490d906e9f..cfbf05ca885 100644 --- a/src/rtapi/rtapi_pci.cc +++ b/src/rtapi/rtapi_pci.cc @@ -34,7 +34,7 @@ #include #include #include -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #include #include diff --git a/src/rtapi/uspace_common.h b/src/rtapi/uspace_common.h index 636e72d665f..ffc7376b9a9 100644 --- a/src/rtapi/uspace_common.h +++ b/src/rtapi/uspace_common.h @@ -40,7 +40,7 @@ static msg_level_t msg_level = RTAPI_MSG_ERR; /* message printing level */ #include "config.h" #ifdef RTAPI -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #endif typedef struct { diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index df3a5f6737d..a9167f0c0ee 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #include #include #include diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index eebc44b1b53..edab449be21 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnarrowing" #include diff --git a/src/rtapi/uspace_rtapi.cc b/src/rtapi/uspace_rtapi.cc deleted file mode 100644 index b33f0512d9c..00000000000 --- a/src/rtapi/uspace_rtapi.cc +++ /dev/null @@ -1,257 +0,0 @@ -#include "rtapi.h" -#include "uspace_rtapi.hh" - -#include -#include -#include - -std::atomic_int WithRoot::level; -uid_t euid, ruid; - -WithRoot::WithRoot() { - if(!level++) { -#ifdef __linux__ - setfsuid(euid); -#endif - } -} - -WithRoot::~WithRoot() { - if(!--level) { -#ifdef __linux__ - setfsuid(ruid); -#endif - } -} - -rtapi_task::rtapi_task() - : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, - period{}, nextstart{}, - ratio{}, pll_correction{}, pll_correction_limit{}, - arg{}, taskcode{} - -{} - -/* Priority functions. Uspace uses POSIX task priorities. */ - -int RtapiApp::prio_highest() const -{ - return sched_get_priority_max(policy); -} - -int RtapiApp::prio_lowest() const -{ - return sched_get_priority_min(policy); -} - -int RtapiApp::prio_higher_delta() const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - return 1; - } - return -1; -} - -int RtapiApp::prio_bound(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - if (prio >= rtapi_prio_highest()) - return rtapi_prio_highest(); - if (prio < rtapi_prio_lowest()) - return rtapi_prio_lowest(); - } else { - if (prio <= rtapi_prio_highest()) - return rtapi_prio_highest(); - if (prio > rtapi_prio_lowest()) - return rtapi_prio_lowest(); - } - return prio; -} - -bool RtapiApp::prio_check(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { - return (prio <= rtapi_prio_highest()) && (prio >= rtapi_prio_lowest()); - } else { - return (prio <= rtapi_prio_lowest()) && (prio >= rtapi_prio_highest()); - } -} - -int RtapiApp::prio_next_higher(int prio) const -{ - prio = prio_bound(prio); - if(prio != rtapi_prio_highest()) - return prio + prio_higher_delta(); - return prio; -} - -int RtapiApp::prio_next_lower(int prio) const -{ - prio = prio_bound(prio); - if(prio != rtapi_prio_lowest()) - return prio - prio_higher_delta(); - return prio; -} - -int RtapiApp::allocate_task_id() -{ - for(int n=0; nid = n; - task->owner = owner; - task->uses_fp = uses_fp; - task->arg = arg; - task->stacksize = stacksize; - task->taskcode = taskcode; - task->prio = prio; - task->magic = TASK_MAGIC; - task_array[n] = task; - - /* and return handle to the caller */ - - return n; -} - -rtapi_task *RtapiApp::get_task(int task_id) { - if(task_id < 0 || task_id >= MAX_TASKS) return NULL; - /* validate task handle */ - rtapi_task *task = task_array[task_id]; - if(!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) - return NULL; - - return task; -} - -void RtapiApp::unexpected_realtime_delay(rtapi_task *task, int /*nperiod*/) { - static int printed = 0; - if(!printed) - { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unexpected realtime delay on task %d with period %ld\n" - "This Message will only display once per session.\n" - "Run the Latency Test and resolve before continuing.\n", - task->id, task->period); - printed = 1; - } -} - -long RtapiApp::clock_set_period(long nsecs) -{ - if(nsecs == 0) return period; - if(period != 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); - return -EINVAL; - } - period = nsecs; - return period; -} - -//parse_cpu_list from https://gitlab.com/Xenomai/xenomai4/libevl/-/blob/11e6a1fb183a315ae861762e7650fd5e10d83ff5/tests/helpers.c -//License: MIT -static void parse_cpu_list(const char *path, cpu_set_t *cpuset) -{ - char *p, *range, *range_p = NULL, *id, *id_r; - int start, end, cpu; - char buf[BUFSIZ]; - FILE *fp; - - CPU_ZERO(cpuset); - - fp = fopen(path, "r"); - if (fp == NULL) - return; - - if (!fgets(buf, sizeof(buf), fp)) - goto out; - - p = buf; - while ((range = strtok_r(p, ",", &range_p)) != NULL) { - if (*range == '\0' || *range == '\n') - goto next; - end = -1; - id = strtok_r(range, "-", &id_r); - if (id) { - start = atoi(id); - id = strtok_r(NULL, "-", &id_r); - if (id) - end = atoi(id); - else if (end < 0) - end = start; - for (cpu = start; cpu <= end; cpu++) - CPU_SET(cpu, cpuset); - } - next: - p = NULL; - } -out: - fclose(fp); -} - -int find_rt_cpu_number() { - if(getenv("RTAPI_CPU_NUMBER")) return atoi(getenv("RTAPI_CPU_NUMBER")); - -#ifdef __linux__ - const char* isolated_file="/sys/devices/system/cpu/isolated"; - cpu_set_t cpuset; - - parse_cpu_list(isolated_file, &cpuset); - - //Print list - rtapi_print_msg(RTAPI_MSG_INFO, "cpuset isolated "); - for(int i=0; i - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include - -#ifdef __linux__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_IO_H -#include -#endif -#include -#include -#ifdef __linux__ -#include -#include -#endif -#ifdef __FreeBSD__ -#include -#endif - -#include - #include "rtapi.h" -#include -#include "hal/hal_priv.h" -#include "uspace_common.h" - -RtapiApp &App(); - -struct message_t { - msg_level_t level; - char msg[1024-sizeof(level)]; -}; - -boost::lockfree::queue> -rtapi_msg_queue; - -pthread_t queue_thread; -void *queue_function(void * /*arg*/) { - set_namef("rtapi_app:mesg"); - // note: can't use anything in this function that requires App() to exist - // but it's OK to use functions that aren't safe for realtime (that's the - // point of running this in a thread) - while(1) { - pthread_testcancel(); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); - rtapi_msg_queue.consume_all([](const message_t &m) { - fputs(m.msg, m.level == RTAPI_MSG_ALL ? stdout : stderr); - }); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); - struct timespec ts = {0, 10000000}; - rtapi_clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL, NULL); - } - return nullptr; -} - -static int sim_rtapi_run_threads(int fd, int (*callback)(int fd)); - -using namespace std; - -template T DLSYM(void *handle, const string &name) { - return (T)(dlsym(handle, name.c_str())); -} - -template T DLSYM(void *handle, const char *name) { - return (T)(dlsym(handle, name)); -} - -static std::map modules; - -static int instance_count = 0; -static int force_exit = 0; - -static int do_newinst_cmd(const string& type, const string& name, const string& arg) { - void *module = modules["hal_lib"]; - if(!module) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: hal_lib is required, but not loaded\n"); - return -1; - } - - hal_comp_t *(*find_comp_by_name)(char*) = - DLSYM(module, "halpr_find_comp_by_name"); - if(!find_comp_by_name) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: halpr_find_comp_by_name not found\n"); - return -1; - } - - hal_comp_t *comp = find_comp_by_name((char*)type.c_str()); - if(!comp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: component %s not found\n", type.c_str()); - return -1; - } - - return comp->make((char*)name.c_str(), (char*)arg.c_str()); -} - -static int do_one_item(char item_type_char, const string ¶m_name, const string ¶m_value, void *vitem, int idx=0) { - char *endp; - switch(item_type_char) { - case 'l': { - long *litem = *(long**) vitem; - litem[idx] = strtol(param_value.c_str(), &endp, 0); - if(*endp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'", - param_value.c_str(), param_name.c_str()); - return -1; - } - return 0; - } - case 'i': { - int *iitem = *(int**) vitem; - iitem[idx] = strtol(param_value.c_str(), &endp, 0); - if(*endp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'", - param_value.c_str(), param_name.c_str()); - return -1; - } - return 0; - } - case 's': { - char **sitem = *(char***) vitem; - sitem[idx] = strdup(param_value.c_str()); - return 0; - } - default: - rtapi_print_msg(RTAPI_MSG_ERR, - "%s: Invalid type character `%c'\n", - param_name.c_str(), item_type_char); - return -1; - } - return 0; -} - -void remove_quotes(string &s) { - s.erase(remove_copy(s.begin(), s.end(), s.begin(), '"'), s.end()); -} - -static int do_comp_args(void *module, vector args) { - for(unsigned i=1; i < args.size(); i++) { - string &s = args[i]; - remove_quotes(s); - size_t idx = s.find('='); - if(idx == string::npos) { - rtapi_print_msg(RTAPI_MSG_ERR, "Invalid parameter `%s'\n", - s.c_str()); - return -1; - } - string param_name(s, 0, idx); - string param_value(s, idx+1); - void *item=DLSYM(module, "rtapi_info_address_" + param_name); - if(!item) { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unknown parameter `%s'\n", s.c_str()); - return -1; - } - char **item_type=DLSYM(module, "rtapi_info_type_" + param_name); - if(!item_type || !*item_type) { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unknown parameter `%s' (type information missing)\n", - s.c_str()); - return -1; - } - - int*max_size_ptr=DLSYM(module, "rtapi_info_size_" + param_name); - - char item_type_char = **item_type; - if(max_size_ptr) { - int max_size = *max_size_ptr; - size_t idx = 0; - int i = 0; - while(idx != string::npos) { - if(i == max_size) { - rtapi_print_msg(RTAPI_MSG_ERR, - "%s: can only take %d arguments\n", - s.c_str(), max_size); - return -1; - } - size_t idx1 = param_value.find(",", idx); - string substr(param_value, idx, idx1 - idx); - int result = do_one_item(item_type_char, s, substr, item, i); - if(result != 0) return result; - i++; - idx = idx1 == string::npos ? idx1 : idx1 + 1; - } - } else { - int result = do_one_item(item_type_char, s, param_value, item); - if(result != 0) return result; - } - } - return 0; -} - -static int do_load_cmd(const string& name, const vector& args) { - void *w = modules[name]; - if(w == NULL) { - char what[LINELEN+1]; - snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR, name.c_str()); - void *module = modules[name] = dlopen(what, RTLD_GLOBAL | RTLD_NOW); - if(!module) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n", name.c_str(), dlerror()); - modules.erase(name); - return -1; - } - /// XXX handle arguments - int (*start)(void) = DLSYM(module, "rtapi_app_main"); - if(!start) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlsym: %s\n", name.c_str(), dlerror()); - dlclose(module); - modules.erase(name); - return -1; - } - int result; - - result = do_comp_args(module, args); - if(result < 0) { - dlclose(module); - modules.erase(name); - return -1; - } +#include "uspace_rtapi_app.hh" - if ((result=start()) < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: rtapi_app_main: %s (%d)\n", - name.c_str(), strerror(-result), result); - dlclose(module); - modules.erase(name); - return result; - } else { - instance_count ++; - return 0; - } - } else { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: already exists\n", name.c_str()); - return -1; - } -} - -static int do_unload_cmd(const string& name) { - void *w = modules[name]; - if(w == NULL) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n", name.c_str()); - return -1; - } else { - int (*stop)(void) = DLSYM(w, "rtapi_app_exit"); - if(stop) stop(); - modules.erase(modules.find(name)); - dlclose(w); - instance_count --; - } - return 0; -} - -static int do_debug_cmd(const string& value) { - try{ - int new_level = stoi(value); - if (new_level < 0 || new_level > 5){ - rtapi_print_msg(RTAPI_MSG_ERR, "Debug level must be >=0 and <= 5\n"); - return -EINVAL; - } - return rtapi_set_msg_level(new_level); - }catch(invalid_argument &e){ - //stoi will throw an exception if parsing is not possible - rtapi_print_msg(RTAPI_MSG_ERR, "Debug level is not a number\n"); - return -EINVAL; - } -} - -struct ReadError : std::exception {}; -struct WriteError : std::exception {}; - -static int read_number(int fd) { - int r = 0, neg=1; - char ch; - - while(1) { - int res = read(fd, &ch, 1); - if(res != 1) return -1; - if(ch == '-') neg = -1; - else if(ch == ' ') return r * neg; - else r = 10 * r + ch - '0'; - } -} - -static string read_string(int fd) { - int len = read_number(fd); - if(len < 0) - throw ReadError(); - if(!len) - return string(); - string str(len, 0); - if(read(fd, str.data(), len) != len) - throw ReadError(); - return str; -} - -static vector read_strings(int fd) { - vector result; - int count = read_number(fd); - if(count < 0) - return result; - for(int i=0; i& strings) { - string buf; - write_number(buf, strings.size()); - for(unsigned int i=0; i args) { - if(args.size() == 0) { return 0; } - if(args.size() == 1 && args[0] == "exit") { - force_exit = 1; - return 0; - } else if(args.size() >= 2 && args[0] == "load") { - string name = args[1]; - args.erase(args.begin()); - return do_load_cmd(name, args); - } else if(args.size() == 2 && args[0] == "unload") { - return do_unload_cmd(args[1]); - } else if(args.size() == 3 && args[0] == "newinst") { - return do_newinst_cmd(args[1], args[2], ""); - } else if(args.size() == 4 && args[0] == "newinst") { - return do_newinst_cmd(args[1], args[2], args[3]); - } else if(args.size() == 2 && args[0] == "debug") { - return do_debug_cmd(args[1]); - } else { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unrecognized command starting with %s\n", - args[0].c_str()); - return -1; - } -} - -static int slave(int fd, const vector& args) { - try { - write_strings(fd, args); - } - catch (WriteError &e) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to write to master: %s\n", strerror(errno)); - } - - int result = read_number(fd); - return result; -} - -static int callback(int fd) -{ - struct sockaddr_un client_addr; - memset(&client_addr, 0, sizeof(client_addr)); - socklen_t len = sizeof(client_addr); - int fd1 = accept(fd, (sockaddr*)&client_addr, &len); - if(fd1 < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to accept connection from slave: %s\n", strerror(errno)); - return -1; - } else { - int result; - try { - result = handle_command(read_strings(fd1)); - } catch (ReadError &e) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to read from slave: %s\n", strerror(errno)); - close(fd1); - return -1; - } - string buf; - write_number(buf, result); - if(write(fd1, buf.data(), buf.size()) != (ssize_t)buf.size()) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to write to slave: %s\n", strerror(errno)); - }; - close(fd1); - } - return !force_exit && instance_count > 0; -} +#include +#include +#include -static pthread_t main_thread{}; +std::atomic_int WithRoot::level; +uid_t euid, ruid; -static int master(int fd, const vector& args) { - main_thread = pthread_self(); - int result; - if((result = pthread_create(&queue_thread, nullptr, &queue_function, nullptr)) != 0) { - errno = result; - perror("pthread_create (queue function)"); - return -1; - } - do_load_cmd("hal_lib", vector()); - instance_count = 0; - App(); // force rtapi_app to be created - if(args.size()) { - result = handle_command(args); - if(result != 0) goto out; - if(force_exit || instance_count == 0) goto out; - } - sim_rtapi_run_threads(fd, callback); -out: - pthread_cancel(queue_thread); - pthread_join(queue_thread, nullptr); - rtapi_msg_queue.consume_all([](const message_t &m) { - fputs(m.msg, m.level == RTAPI_MSG_ALL ? stdout : stderr); - }); - return result; -} - -static std::string -_get_fifo_path() { - std::string s; - if(getenv("RTAPI_FIFO_PATH")) - s = getenv("RTAPI_FIFO_PATH"); - else if(getenv("HOME")) - s = std::string(getenv("HOME")) + "/.rtapi_fifo"; - else { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe."); - return NULL; - } - if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s", - sizeof(sockaddr_un::sun_path), s.c_str()); - return NULL; +WithRoot::WithRoot() { + if(!level++) { +#ifdef __linux__ + setfsuid(euid); +#endif } - return s; } -static const char * -get_fifo_path() { - static std::string path = _get_fifo_path(); - return path.c_str(); -} - -static int -get_fifo_path(char *buf, size_t bufsize) { - int len; - const char *s = get_fifo_path(); - if(!s) return -1; - len=snprintf(buf+1, bufsize-1, "%s", s); - return len; -} - -int main(int argc, char **argv) { - if(getuid() == 0) { - char *fallback_uid_str = getenv("RTAPI_UID"); - int fallback_uid = fallback_uid_str ? atoi(fallback_uid_str) : 0; - if(fallback_uid == 0) - { - // Cppcheck cannot see EMC2_BIN_DIR when RTAPI is defined, but that - // doesn't happen in uspace. - fprintf(stderr, - "Refusing to run as root without fallback UID specified\n" - "To run under a debugger with I/O, use e.g.,\n" - // cppcheck-suppress unknownMacro - " sudo env RTAPI_UID=`id -u` RTAPI_FIFO_PATH=$HOME/.rtapi_fifo gdb " EMC2_BIN_DIR "/rtapi_app\n"); - exit(1); - } - if (setreuid(fallback_uid, 0) != 0) { perror("setreuid"); abort(); } - fprintf(stderr, - "Running with fallback_uid. getuid()=%d geteuid()=%d\n", - getuid(), geteuid()); - } - ruid = getuid(); - euid = geteuid(); - if (setresuid(euid, euid, ruid) != 0) { perror("setresuid"); abort(); } +WithRoot::~WithRoot() { + if(!--level) { #ifdef __linux__ - setfsuid(ruid); + setfsuid(ruid); #endif - vector args; - for(int i=1; i(malloc(PRE_ALLOC_SIZE)); - if (buf == NULL) { - rtapi_print_msg(RTAPI_MSG_WARN, "malloc(PRE_ALLOC_SIZE) failed\n"); - return; - } - long pagesize = sysconf(_SC_PAGESIZE); - /* Touch each page in this piece of memory to get it mapped into RAM */ - for (size_t i = 0; i < PRE_ALLOC_SIZE; i += pagesize) { - /* Each write to this buffer will generate a pagefault. - * Once the pagefault is handled a page will be locked in - * memory and never given back to the system. */ - buf[i] = 0; - } - free((void *)buf); + return sched_get_priority_min(policy); } -static int harden_rt() -{ - if(!rtapi_is_realtime()) return -EINVAL; - - WITH_ROOT; -#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__)) - if (iopl(3) < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, - "iopl() failed: %s\n" - "cannot gain I/O privileges - " - "forgot 'sudo make setuid' or using secure boot? -" - "parallel port access is not allowed\n", - strerror(errno)); +int RtapiApp::prio_higher_delta() const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + return 1; } -#endif - - struct sigaction sig_act = {}; -#ifdef __linux__ - // enable realtime - if (setrlimit(RLIMIT_RTPRIO, &unlimited) < 0) - { - rtapi_print_msg(RTAPI_MSG_WARN, - "setrlimit(RTLIMIT_RTPRIO): %s\n", - strerror(errno)); - return -errno; - } - - // enable core dumps - if (setrlimit(RLIMIT_CORE, &unlimited) < 0) - rtapi_print_msg(RTAPI_MSG_WARN, - "setrlimit: %s - core dumps may be truncated or non-existent\n", - strerror(errno)); - - // even when setuid root - if (prctl(PR_SET_DUMPABLE, 1) < 0) - rtapi_print_msg(RTAPI_MSG_WARN, - "prctl(PR_SET_DUMPABLE) failed: no core dumps will be created - %d - %s\n", - errno, strerror(errno)); -#endif /* __linux__ */ - - configure_memory(); - - sigemptyset( &sig_act.sa_mask ); - sig_act.sa_handler = SIG_IGN; - sig_act.sa_sigaction = NULL; - - // prevent stopping of RT threads by ^Z - sigaction(SIGTSTP, &sig_act, (struct sigaction *) NULL); - - sig_act.sa_sigaction = signal_handler; - sig_act.sa_flags = SA_SIGINFO; - - sigaction(SIGSEGV, &sig_act, (struct sigaction *) NULL); - sigaction(SIGILL, &sig_act, (struct sigaction *) NULL); - sigaction(SIGFPE, &sig_act, (struct sigaction *) NULL); - sigaction(SIGTERM, &sig_act, (struct sigaction *) NULL); - sigaction(SIGINT, &sig_act, (struct sigaction *) NULL); - -#ifdef __linux__ - int fd = open("/dev/cpu_dma_latency", O_WRONLY | O_CLOEXEC); - if (fd < 0) { - rtapi_print_msg(RTAPI_MSG_WARN, "failed to open /dev/cpu_dma_latency: %s\n", strerror(errno)); - } else { - int r; - r = write(fd, "\0\0\0\0", 4); - if (r != 4) { - rtapi_print_msg(RTAPI_MSG_WARN, "failed to write to /dev/cpu_dma_latency: %s\n", strerror(errno)); - } - // deliberately leak fd until program exit - } -#endif /* __linux__ */ - return 0; + return -1; } -static RtapiApp *makeDllApp(string dllName, int policy){ - void *dll = nullptr; - dll = dlopen(dllName.c_str(), RTLD_NOW); - if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); - auto fn = reinterpret_cast(dlsym(dll, "make")); - if(!fn) fprintf(stderr, "dlopen: %s\n", dlerror()); - auto result = fn ? fn(policy) : nullptr; - if(result) { - return result; - }else{ - throw invalid_argument("Could not load DLL!"); +int RtapiApp::prio_bound(int prio) const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + if (prio >= rtapi_prio_highest()) + return rtapi_prio_highest(); + if (prio < rtapi_prio_lowest()) + return rtapi_prio_lowest(); + } else { + if (prio <= rtapi_prio_highest()) + return rtapi_prio_highest(); + if (prio > rtapi_prio_lowest()) + return rtapi_prio_lowest(); } + return prio; } -static RtapiApp *makeApp() -{ - if(euid != 0 || harden_rt() < 0) - { - return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); - } - WithRoot r; - if(detect_xenomai_evl()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); - }else if(detect_xenomai()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); - } else if(detect_rtai()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); +bool RtapiApp::prio_check(int prio) const { + if(rtapi_prio_highest() > rtapi_prio_lowest()) { + return (prio <= rtapi_prio_highest()) && (prio >= rtapi_prio_lowest()); } else { - return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); + return (prio <= rtapi_prio_lowest()) && (prio >= rtapi_prio_highest()); } } -RtapiApp &App() -{ - static RtapiApp *app = makeApp(); - return *app; -} - -/* data for all tasks */ -struct rtapi_task *task_array[MAX_TASKS]; - -int rtapi_prio_highest(void) -{ - return App().prio_highest(); -} -int rtapi_prio_lowest(void) +int RtapiApp::prio_next_higher(int prio) const { - return App().prio_lowest(); + prio = prio_bound(prio); + if(prio != rtapi_prio_highest()) + return prio + prio_higher_delta(); + return prio; } -int rtapi_prio_next_higher(int prio) +int RtapiApp::prio_next_lower(int prio) const { - return App().prio_next_higher(prio); + prio = prio_bound(prio); + if(prio != rtapi_prio_lowest()) + return prio - prio_higher_delta(); + return prio; } -int rtapi_prio_next_lower(int prio) +int RtapiApp::allocate_task_id() { - return App().prio_next_lower(prio); -} - -long rtapi_clock_set_period(long nsecs) -{ - return App().clock_set_period(nsecs); + for(int n=0; nid = n; + task->owner = owner; + task->uses_fp = uses_fp; + task->arg = arg; + task->stacksize = stacksize; + task->taskcode = taskcode; + task->prio = prio; + task->magic = TASK_MAGIC; + task_array[n] = task; + + /* and return handle to the caller */ + + return n; +} + +rtapi_task *RtapiApp::get_task(int task_id) { + if(task_id < 0 || task_id >= MAX_TASKS) return NULL; + /* validate task handle */ + rtapi_task *task = task_array[task_id]; + if(!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) + return NULL; + + return task; +} + +void RtapiApp::unexpected_realtime_delay(rtapi_task *task, int /*nperiod*/) { + static int printed = 0; + if(!printed) + { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unexpected realtime delay on task %d with period %ld\n" + "This Message will only display once per session.\n" + "Run the Latency Test and resolve before continuing.\n", + task->id, task->period); + printed = 1; } - return ret; -} - -int rtapi_task_pause(int task_id) -{ - return App().task_pause(task_id); -} - -int rtapi_task_resume(int task_id) -{ - return App().task_resume(task_id); -} - -int rtapi_task_self() -{ - return App().task_self(); } -long long rtapi_task_pll_get_reference(void) +long RtapiApp::clock_set_period(long nsecs) { - return App().task_pll_get_reference(); -} - -int rtapi_task_pll_set_correction(long value) + if(nsecs == 0) return period; + if(period != 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); + return -EINVAL; + } + period = nsecs; + return period; +} + +//parse_cpu_list from https://gitlab.com/Xenomai/xenomai4/libevl/-/blob/11e6a1fb183a315ae861762e7650fd5e10d83ff5/tests/helpers.c +//License: MIT +static void parse_cpu_list(const char *path, cpu_set_t *cpuset) { - return App().task_pll_set_correction(value); -} + char *p, *range, *range_p = NULL, *id, *id_r; + int start, end, cpu; + char buf[BUFSIZ]; + FILE *fp; -void rtapi_wait(void) -{ - App().wait(); -} + CPU_ZERO(cpuset); -void rtapi_outb(unsigned char byte, unsigned int port) -{ - App().do_outb(byte, port); -} + fp = fopen(path, "r"); + if (fp == NULL) + return; -unsigned char rtapi_inb(unsigned int port) -{ - return App().do_inb(port); + if (!fgets(buf, sizeof(buf), fp)) + goto out; + + p = buf; + while ((range = strtok_r(p, ",", &range_p)) != NULL) { + if (*range == '\0' || *range == '\n') + goto next; + end = -1; + id = strtok_r(range, "-", &id_r); + if (id) { + start = atoi(id); + id = strtok_r(NULL, "-", &id_r); + if (id) + end = atoi(id); + else if (end < 0) + end = start; + for (cpu = start; cpu <= end; cpu++) + CPU_SET(cpu, cpuset); + } + next: + p = NULL; + } +out: + fclose(fp); } -long int simple_strtol(const char *nptr, char **endptr, int base) { - return strtol(nptr, endptr, base); -} +int find_rt_cpu_number() { + if(getenv("RTAPI_CPU_NUMBER")) return atoi(getenv("RTAPI_CPU_NUMBER")); -int sim_rtapi_run_threads(int fd, int (*callback)(int fd)) { - return App().run_threads(fd, callback); -} +#ifdef __linux__ + const char* isolated_file="/sys/devices/system/cpu/isolated"; + cpu_set_t cpuset; -long long rtapi_get_time() { - return App().do_get_time(); -} + parse_cpu_list(isolated_file, &cpuset); -void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { - if(main_thread && pthread_self() != main_thread) { - message_t m; - m.level = level; - vsnprintf(m.msg, sizeof(m.msg), fmt, ap); - rtapi_msg_queue.push(m); - } else { - vfprintf(level == RTAPI_MSG_ALL ? stdout : stderr, fmt, ap); + //Print list + rtapi_print_msg(RTAPI_MSG_INFO, "cpuset isolated "); + for(int i=0; i rtapi_delay_max()) ns = rtapi_delay_max(); - App().do_delay(ns); -} - -const unsigned long ONE_SEC_IN_NS = 1000000000; -void rtapi_timespec_advance(struct timespec &result, const struct timespec &src, unsigned long nsec) -{ - time_t sec = src.tv_sec; - while(nsec >= ONE_SEC_IN_NS) - { - ++sec; - nsec -= ONE_SEC_IN_NS; + int top = -1; + for(int i=0; i= ONE_SEC_IN_NS) - { - ++sec; - nsec -= ONE_SEC_IN_NS; + if(top == -1){ + rtapi_print_msg(RTAPI_MSG_ERR, "No isolated CPU's found, expect some latency or set RTAPI_CPU_NUMBER to select CPU\n"); } - result.tv_sec = sec; - result.tv_nsec = nsec; + return top; +#else + return (-1); +#endif } -int rtapi_open_as_root(const char *filename, int mode) { - WITH_ROOT; - int r = open(filename, mode); - if(r < 0) return -errno; - return r; -} +void set_namef(const char *fmt, ...) { + char *buf = NULL; + va_list ap; -int rtapi_spawn_as_root(pid_t *pid, const char *path, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) -{ - return posix_spawn(pid, path, file_actions, attrp, argv, envp); -} + va_start(ap, fmt); + if (vasprintf(&buf, fmt, ap) < 0) { + va_end(ap); + return; + } + va_end(ap); -int rtapi_spawnp_as_root(pid_t *pid, const char *path, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) -{ - return posix_spawnp(pid, path, file_actions, attrp, argv, envp); -} + int res = pthread_setname_np(pthread_self(), buf); + if (res) { + fprintf(stderr, "pthread_setname_np() failed for %s: %d\n", buf, res); + } + free(buf); +} \ No newline at end of file diff --git a/src/rtapi/uspace_rtapi.hh b/src/rtapi/uspace_rtapi_app.hh similarity index 100% rename from src/rtapi/uspace_rtapi.hh rename to src/rtapi/uspace_rtapi_app.hh diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc new file mode 100644 index 00000000000..2ed201bfb00 --- /dev/null +++ b/src/rtapi/uspace_rtapi_main.cc @@ -0,0 +1,936 @@ +/* Copyright (C) 2006-2014 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include + +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_IO_H +#include +#endif +#include +#include +#ifdef __linux__ +#include +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + +#include + +#include "rtapi.h" +#include +#include "hal/hal_priv.h" +#include "uspace_common.h" + +RtapiApp &App(); + +struct message_t { + msg_level_t level; + char msg[1024-sizeof(level)]; +}; + +boost::lockfree::queue> +rtapi_msg_queue; + +pthread_t queue_thread; +void *queue_function(void * /*arg*/) { + set_namef("rtapi_app:mesg"); + // note: can't use anything in this function that requires App() to exist + // but it's OK to use functions that aren't safe for realtime (that's the + // point of running this in a thread) + while(1) { + pthread_testcancel(); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); + rtapi_msg_queue.consume_all([](const message_t &m) { + fputs(m.msg, m.level == RTAPI_MSG_ALL ? stdout : stderr); + }); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); + struct timespec ts = {0, 10000000}; + rtapi_clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL, NULL); + } + return nullptr; +} + +static int sim_rtapi_run_threads(int fd, int (*callback)(int fd)); + +using namespace std; + +template T DLSYM(void *handle, const string &name) { + return (T)(dlsym(handle, name.c_str())); +} + +template T DLSYM(void *handle, const char *name) { + return (T)(dlsym(handle, name)); +} + +static std::map modules; + +static int instance_count = 0; +static int force_exit = 0; + +static int do_newinst_cmd(const string& type, const string& name, const string& arg) { + void *module = modules["hal_lib"]; + if(!module) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: hal_lib is required, but not loaded\n"); + return -1; + } + + hal_comp_t *(*find_comp_by_name)(char*) = + DLSYM(module, "halpr_find_comp_by_name"); + if(!find_comp_by_name) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: halpr_find_comp_by_name not found\n"); + return -1; + } + + hal_comp_t *comp = find_comp_by_name((char*)type.c_str()); + if(!comp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: component %s not found\n", type.c_str()); + return -1; + } + + return comp->make((char*)name.c_str(), (char*)arg.c_str()); +} + +static int do_one_item(char item_type_char, const string ¶m_name, const string ¶m_value, void *vitem, int idx=0) { + char *endp; + switch(item_type_char) { + case 'l': { + long *litem = *(long**) vitem; + litem[idx] = strtol(param_value.c_str(), &endp, 0); + if(*endp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'", + param_value.c_str(), param_name.c_str()); + return -1; + } + return 0; + } + case 'i': { + int *iitem = *(int**) vitem; + iitem[idx] = strtol(param_value.c_str(), &endp, 0); + if(*endp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'", + param_value.c_str(), param_name.c_str()); + return -1; + } + return 0; + } + case 's': { + char **sitem = *(char***) vitem; + sitem[idx] = strdup(param_value.c_str()); + return 0; + } + default: + rtapi_print_msg(RTAPI_MSG_ERR, + "%s: Invalid type character `%c'\n", + param_name.c_str(), item_type_char); + return -1; + } + return 0; +} + +void remove_quotes(string &s) { + s.erase(remove_copy(s.begin(), s.end(), s.begin(), '"'), s.end()); +} + +static int do_comp_args(void *module, vector args) { + for(unsigned i=1; i < args.size(); i++) { + string &s = args[i]; + remove_quotes(s); + size_t idx = s.find('='); + if(idx == string::npos) { + rtapi_print_msg(RTAPI_MSG_ERR, "Invalid parameter `%s'\n", + s.c_str()); + return -1; + } + string param_name(s, 0, idx); + string param_value(s, idx+1); + void *item=DLSYM(module, "rtapi_info_address_" + param_name); + if(!item) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unknown parameter `%s'\n", s.c_str()); + return -1; + } + char **item_type=DLSYM(module, "rtapi_info_type_" + param_name); + if(!item_type || !*item_type) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unknown parameter `%s' (type information missing)\n", + s.c_str()); + return -1; + } + + int*max_size_ptr=DLSYM(module, "rtapi_info_size_" + param_name); + + char item_type_char = **item_type; + if(max_size_ptr) { + int max_size = *max_size_ptr; + size_t idx = 0; + int i = 0; + while(idx != string::npos) { + if(i == max_size) { + rtapi_print_msg(RTAPI_MSG_ERR, + "%s: can only take %d arguments\n", + s.c_str(), max_size); + return -1; + } + size_t idx1 = param_value.find(",", idx); + string substr(param_value, idx, idx1 - idx); + int result = do_one_item(item_type_char, s, substr, item, i); + if(result != 0) return result; + i++; + idx = idx1 == string::npos ? idx1 : idx1 + 1; + } + } else { + int result = do_one_item(item_type_char, s, param_value, item); + if(result != 0) return result; + } + } + return 0; +} + +static int do_load_cmd(const string& name, const vector& args) { + void *w = modules[name]; + if(w == NULL) { + char what[LINELEN+1]; + snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR, name.c_str()); + void *module = modules[name] = dlopen(what, RTLD_GLOBAL | RTLD_NOW); + if(!module) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n", name.c_str(), dlerror()); + modules.erase(name); + return -1; + } + /// XXX handle arguments + int (*start)(void) = DLSYM(module, "rtapi_app_main"); + if(!start) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlsym: %s\n", name.c_str(), dlerror()); + dlclose(module); + modules.erase(name); + return -1; + } + int result; + + result = do_comp_args(module, args); + if(result < 0) { + dlclose(module); + modules.erase(name); + return -1; + } + + if ((result=start()) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: rtapi_app_main: %s (%d)\n", + name.c_str(), strerror(-result), result); + dlclose(module); + modules.erase(name); + return result; + } else { + instance_count ++; + return 0; + } + } else { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: already exists\n", name.c_str()); + return -1; + } +} + +static int do_unload_cmd(const string& name) { + void *w = modules[name]; + if(w == NULL) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n", name.c_str()); + return -1; + } else { + int (*stop)(void) = DLSYM(w, "rtapi_app_exit"); + if(stop) stop(); + modules.erase(modules.find(name)); + dlclose(w); + instance_count --; + } + return 0; +} + +static int do_debug_cmd(const string& value) { + try{ + int new_level = stoi(value); + if (new_level < 0 || new_level > 5){ + rtapi_print_msg(RTAPI_MSG_ERR, "Debug level must be >=0 and <= 5\n"); + return -EINVAL; + } + return rtapi_set_msg_level(new_level); + }catch(invalid_argument &e){ + //stoi will throw an exception if parsing is not possible + rtapi_print_msg(RTAPI_MSG_ERR, "Debug level is not a number\n"); + return -EINVAL; + } +} + +struct ReadError : std::exception {}; +struct WriteError : std::exception {}; + +static int read_number(int fd) { + int r = 0, neg=1; + char ch; + + while(1) { + int res = read(fd, &ch, 1); + if(res != 1) return -1; + if(ch == '-') neg = -1; + else if(ch == ' ') return r * neg; + else r = 10 * r + ch - '0'; + } +} + +static string read_string(int fd) { + int len = read_number(fd); + if(len < 0) + throw ReadError(); + if(!len) + return string(); + string str(len, 0); + if(read(fd, str.data(), len) != len) + throw ReadError(); + return str; +} + +static vector read_strings(int fd) { + vector result; + int count = read_number(fd); + if(count < 0) + return result; + for(int i=0; i& strings) { + string buf; + write_number(buf, strings.size()); + for(unsigned int i=0; i args) { + if(args.size() == 0) { return 0; } + if(args.size() == 1 && args[0] == "exit") { + force_exit = 1; + return 0; + } else if(args.size() >= 2 && args[0] == "load") { + string name = args[1]; + args.erase(args.begin()); + return do_load_cmd(name, args); + } else if(args.size() == 2 && args[0] == "unload") { + return do_unload_cmd(args[1]); + } else if(args.size() == 3 && args[0] == "newinst") { + return do_newinst_cmd(args[1], args[2], ""); + } else if(args.size() == 4 && args[0] == "newinst") { + return do_newinst_cmd(args[1], args[2], args[3]); + } else if(args.size() == 2 && args[0] == "debug") { + return do_debug_cmd(args[1]); + } else { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unrecognized command starting with %s\n", + args[0].c_str()); + return -1; + } +} + +static int slave(int fd, const vector& args) { + try { + write_strings(fd, args); + } + catch (WriteError &e) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: failed to write to master: %s\n", strerror(errno)); + } + + int result = read_number(fd); + return result; +} + +static int callback(int fd) +{ + struct sockaddr_un client_addr; + memset(&client_addr, 0, sizeof(client_addr)); + socklen_t len = sizeof(client_addr); + int fd1 = accept(fd, (sockaddr*)&client_addr, &len); + if(fd1 < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: failed to accept connection from slave: %s\n", strerror(errno)); + return -1; + } else { + int result; + try { + result = handle_command(read_strings(fd1)); + } catch (ReadError &e) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: failed to read from slave: %s\n", strerror(errno)); + close(fd1); + return -1; + } + string buf; + write_number(buf, result); + if(write(fd1, buf.data(), buf.size()) != (ssize_t)buf.size()) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: failed to write to slave: %s\n", strerror(errno)); + }; + close(fd1); + } + return !force_exit && instance_count > 0; +} + +static pthread_t main_thread{}; + +static int master(int fd, const vector& args) { + main_thread = pthread_self(); + int result; + if((result = pthread_create(&queue_thread, nullptr, &queue_function, nullptr)) != 0) { + errno = result; + perror("pthread_create (queue function)"); + return -1; + } + do_load_cmd("hal_lib", vector()); + instance_count = 0; + App(); // force rtapi_app to be created + if(args.size()) { + result = handle_command(args); + if(result != 0) goto out; + if(force_exit || instance_count == 0) goto out; + } + sim_rtapi_run_threads(fd, callback); +out: + pthread_cancel(queue_thread); + pthread_join(queue_thread, nullptr); + rtapi_msg_queue.consume_all([](const message_t &m) { + fputs(m.msg, m.level == RTAPI_MSG_ALL ? stdout : stderr); + }); + return result; +} + +static std::string +_get_fifo_path() { + std::string s; + if(getenv("RTAPI_FIFO_PATH")) + s = getenv("RTAPI_FIFO_PATH"); + else if(getenv("HOME")) + s = std::string(getenv("HOME")) + "/.rtapi_fifo"; + else { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe."); + return NULL; + } + if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s", + sizeof(sockaddr_un::sun_path), s.c_str()); + return NULL; + } + return s; +} + +static const char * +get_fifo_path() { + static std::string path = _get_fifo_path(); + return path.c_str(); +} + +static int +get_fifo_path(char *buf, size_t bufsize) { + int len; + const char *s = get_fifo_path(); + if(!s) return -1; + len=snprintf(buf+1, bufsize-1, "%s", s); + return len; +} + +int main(int argc, char **argv) { + if(getuid() == 0) { + char *fallback_uid_str = getenv("RTAPI_UID"); + int fallback_uid = fallback_uid_str ? atoi(fallback_uid_str) : 0; + if(fallback_uid == 0) + { + // Cppcheck cannot see EMC2_BIN_DIR when RTAPI is defined, but that + // doesn't happen in uspace. + fprintf(stderr, + "Refusing to run as root without fallback UID specified\n" + "To run under a debugger with I/O, use e.g.,\n" + // cppcheck-suppress unknownMacro + " sudo env RTAPI_UID=`id -u` RTAPI_FIFO_PATH=$HOME/.rtapi_fifo gdb " EMC2_BIN_DIR "/rtapi_app\n"); + exit(1); + } + if (setreuid(fallback_uid, 0) != 0) { perror("setreuid"); abort(); } + fprintf(stderr, + "Running with fallback_uid. getuid()=%d geteuid()=%d\n", + getuid(), geteuid()); + } + ruid = getuid(); + euid = geteuid(); + if (setresuid(euid, euid, ruid) != 0) { perror("setresuid"); abort(); } +#ifdef __linux__ + setfsuid(ruid); +#endif + vector args; + for(int i=1; i(malloc(PRE_ALLOC_SIZE)); + if (buf == NULL) { + rtapi_print_msg(RTAPI_MSG_WARN, "malloc(PRE_ALLOC_SIZE) failed\n"); + return; + } + long pagesize = sysconf(_SC_PAGESIZE); + /* Touch each page in this piece of memory to get it mapped into RAM */ + for (size_t i = 0; i < PRE_ALLOC_SIZE; i += pagesize) { + /* Each write to this buffer will generate a pagefault. + * Once the pagefault is handled a page will be locked in + * memory and never given back to the system. */ + buf[i] = 0; + } + free((void *)buf); +} + +static int harden_rt() +{ + if(!rtapi_is_realtime()) return -EINVAL; + + WITH_ROOT; +#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__)) + if (iopl(3) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, + "iopl() failed: %s\n" + "cannot gain I/O privileges - " + "forgot 'sudo make setuid' or using secure boot? -" + "parallel port access is not allowed\n", + strerror(errno)); + } +#endif + + struct sigaction sig_act = {}; +#ifdef __linux__ + // enable realtime + if (setrlimit(RLIMIT_RTPRIO, &unlimited) < 0) + { + rtapi_print_msg(RTAPI_MSG_WARN, + "setrlimit(RTLIMIT_RTPRIO): %s\n", + strerror(errno)); + return -errno; + } + + // enable core dumps + if (setrlimit(RLIMIT_CORE, &unlimited) < 0) + rtapi_print_msg(RTAPI_MSG_WARN, + "setrlimit: %s - core dumps may be truncated or non-existent\n", + strerror(errno)); + + // even when setuid root + if (prctl(PR_SET_DUMPABLE, 1) < 0) + rtapi_print_msg(RTAPI_MSG_WARN, + "prctl(PR_SET_DUMPABLE) failed: no core dumps will be created - %d - %s\n", + errno, strerror(errno)); +#endif /* __linux__ */ + + configure_memory(); + + sigemptyset( &sig_act.sa_mask ); + sig_act.sa_handler = SIG_IGN; + sig_act.sa_sigaction = NULL; + + // prevent stopping of RT threads by ^Z + sigaction(SIGTSTP, &sig_act, (struct sigaction *) NULL); + + sig_act.sa_sigaction = signal_handler; + sig_act.sa_flags = SA_SIGINFO; + + sigaction(SIGSEGV, &sig_act, (struct sigaction *) NULL); + sigaction(SIGILL, &sig_act, (struct sigaction *) NULL); + sigaction(SIGFPE, &sig_act, (struct sigaction *) NULL); + sigaction(SIGTERM, &sig_act, (struct sigaction *) NULL); + sigaction(SIGINT, &sig_act, (struct sigaction *) NULL); + +#ifdef __linux__ + int fd = open("/dev/cpu_dma_latency", O_WRONLY | O_CLOEXEC); + if (fd < 0) { + rtapi_print_msg(RTAPI_MSG_WARN, "failed to open /dev/cpu_dma_latency: %s\n", strerror(errno)); + } else { + int r; + r = write(fd, "\0\0\0\0", 4); + if (r != 4) { + rtapi_print_msg(RTAPI_MSG_WARN, "failed to write to /dev/cpu_dma_latency: %s\n", strerror(errno)); + } + // deliberately leak fd until program exit + } +#endif /* __linux__ */ + return 0; +} + +static RtapiApp *makeDllApp(string dllName, int policy){ + void *dll = nullptr; + dll = dlopen(dllName.c_str(), RTLD_NOW); + if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); + auto fn = reinterpret_cast(dlsym(dll, "make")); + if(!fn) fprintf(stderr, "dlopen: %s\n", dlerror()); + auto result = fn ? fn(policy) : nullptr; + if(result) { + return result; + }else{ + throw invalid_argument("Could not load DLL!"); + } +} + +static RtapiApp *makeApp() +{ + if(euid != 0 || harden_rt() < 0) + { + return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); + } + WithRoot r; + if(detect_xenomai_evl()) { + return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); + }else if(detect_xenomai()) { + return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); + } else if(detect_rtai()) { + return makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); + } else { + return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); + } +} +RtapiApp &App() +{ + static RtapiApp *app = makeApp(); + return *app; +} + +/* data for all tasks */ +struct rtapi_task *task_array[MAX_TASKS]; + +int rtapi_prio_highest(void) +{ + return App().prio_highest(); +} + +int rtapi_prio_lowest(void) +{ + return App().prio_lowest(); +} + +int rtapi_prio_next_higher(int prio) +{ + return App().prio_next_higher(prio); +} + +int rtapi_prio_next_lower(int prio) +{ + return App().prio_next_lower(prio); +} + +long rtapi_clock_set_period(long nsecs) +{ + return App().clock_set_period(nsecs); +} + +int rtapi_task_new(void (*taskcode) (void*), void *arg, + int prio, int owner, unsigned long int stacksize, int uses_fp) { + return App().task_new(taskcode, arg, prio, owner, stacksize, uses_fp); +} + +int rtapi_task_delete(int id) { + return App().task_delete(id); +} + +int rtapi_task_start(int task_id, unsigned long period_nsec) +{ + int ret = App().task_start(task_id, period_nsec); + if(ret != 0) { + errno = -ret; + perror("rtapi_task_start()"); + } + return ret; +} + +int rtapi_task_pause(int task_id) +{ + return App().task_pause(task_id); +} + +int rtapi_task_resume(int task_id) +{ + return App().task_resume(task_id); +} + +int rtapi_task_self() +{ + return App().task_self(); +} + +long long rtapi_task_pll_get_reference(void) +{ + return App().task_pll_get_reference(); +} + +int rtapi_task_pll_set_correction(long value) +{ + return App().task_pll_set_correction(value); +} + +void rtapi_wait(void) +{ + App().wait(); +} + +void rtapi_outb(unsigned char byte, unsigned int port) +{ + App().do_outb(byte, port); +} + +unsigned char rtapi_inb(unsigned int port) +{ + return App().do_inb(port); +} + +long int simple_strtol(const char *nptr, char **endptr, int base) { + return strtol(nptr, endptr, base); +} + +int sim_rtapi_run_threads(int fd, int (*callback)(int fd)) { + return App().run_threads(fd, callback); +} + +long long rtapi_get_time() { + return App().do_get_time(); +} + +void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { + if(main_thread && pthread_self() != main_thread) { + message_t m; + m.level = level; + vsnprintf(m.msg, sizeof(m.msg), fmt, ap); + rtapi_msg_queue.push(m); + } else { + vfprintf(level == RTAPI_MSG_ALL ? stdout : stderr, fmt, ap); + } +} + +long int rtapi_delay_max() { return 10000; } + +void rtapi_delay(long ns) { + if(ns > rtapi_delay_max()) ns = rtapi_delay_max(); + App().do_delay(ns); +} + +const unsigned long ONE_SEC_IN_NS = 1000000000; +void rtapi_timespec_advance(struct timespec &result, const struct timespec &src, unsigned long nsec) +{ + time_t sec = src.tv_sec; + while(nsec >= ONE_SEC_IN_NS) + { + ++sec; + nsec -= ONE_SEC_IN_NS; + } + nsec += src.tv_nsec; + if(nsec >= ONE_SEC_IN_NS) + { + ++sec; + nsec -= ONE_SEC_IN_NS; + } + result.tv_sec = sec; + result.tv_nsec = nsec; +} + +int rtapi_open_as_root(const char *filename, int mode) { + WITH_ROOT; + int r = open(filename, mode); + if(r < 0) return -errno; + return r; +} + +int rtapi_spawn_as_root(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + return posix_spawn(pid, path, file_actions, attrp, argv, envp); +} + +int rtapi_spawnp_as_root(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + return posix_spawnp(pid, path, file_actions, attrp, argv, envp); +} diff --git a/src/rtapi/uspace_rtapi_parport.cc b/src/rtapi/uspace_rtapi_parport.cc index 027ffe80ff5..f208181fa97 100644 --- a/src/rtapi/uspace_rtapi_parport.cc +++ b/src/rtapi/uspace_rtapi_parport.cc @@ -19,7 +19,7 @@ #include #include #include -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #include #include #include diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index c4a509541bf..1c51230d291 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #include #include #include diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index f6cde96c611..154d71ef542 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -1,6 +1,6 @@ #include "config.h" #include "rtapi.h" -#include "uspace_rtapi.hh" +#include "uspace_rtapi_app.hh" #include From 371793cdd9187a8872c9ed1dea6e76ea1d6ac59c Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 16:55:02 +0200 Subject: [PATCH 09/19] Cleanup: Don't start master just to exit --- src/rtapi/uspace_rtapi_main.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 2ed201bfb00..e47cea0162a 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -541,6 +541,11 @@ int main(int argc, char **argv) { int result = ::bind(fd, (sockaddr*)&addr, len+sizeof(addr.sun_family)+1); if(result == 0) { + //If called in master mode with exit command, no need to start master + //and exit again + if(args.size() == 1 && args[0] == "exit") { + return 0; + } int result = listen(fd, 10); if(result != 0) { perror("listen"); exit(1); } setsid(); // create a new session if we can... From 309757829b986bc60817f646c8813d124f0ea01d Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 17:39:13 +0200 Subject: [PATCH 10/19] Cleanup: rtapi_task::ratio is unused, remove --- src/rtapi/uspace_posix.cc | 15 +-------------- src/rtapi/uspace_rtapi_app.cc | 2 +- src/rtapi/uspace_rtapi_app.hh | 1 - 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index a9167f0c0ee..2b59798ff34 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -54,10 +54,7 @@ struct Posix : RtapiApp auto task = ::rtapi_get_task(task_id); if(!task) return -EINVAL; - if(period_nsec < (unsigned long)period) period_nsec = (unsigned long)period; task->period = period_nsec; - task->ratio = period_nsec / period; - struct sched_param param; memset(¶m, 0, sizeof(param)); param.sched_priority = task->prio; @@ -102,17 +99,7 @@ struct Posix : RtapiApp } static void *wrapper(void *arg) { - struct rtapi_task *task; - - /* use the argument to point to the task data */ - task = (struct rtapi_task*)arg; - - long int period = instance->period; - if(task->period < period) task->period = period; - task->ratio = task->period / period; - task->period = task->ratio * period; - rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %lu ratio=%u\n", - task, task->period, task->ratio); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); set_namef("rtapi_app:T#%d", task->id); diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index 2ca79209027..4f6b6ed04cf 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -27,7 +27,7 @@ WithRoot::~WithRoot() { rtapi_task::rtapi_task() : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, period{}, nextstart{}, - ratio{}, pll_correction{}, pll_correction_limit{}, + pll_correction{}, pll_correction_limit{}, arg{}, taskcode{} {} diff --git a/src/rtapi/uspace_rtapi_app.hh b/src/rtapi/uspace_rtapi_app.hh index ca3b32e0754..c1c033de726 100644 --- a/src/rtapi/uspace_rtapi_app.hh +++ b/src/rtapi/uspace_rtapi_app.hh @@ -59,7 +59,6 @@ struct rtapi_task { int prio; long period; struct timespec nextstart; - unsigned ratio; long pll_correction; long pll_correction_limit; void *arg; From e4436eb368abcdbbdf02507acbe26bae75b0d819 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 17:55:22 +0200 Subject: [PATCH 11/19] Cleanup: Rename, remove define --- src/rtapi/uspace_posix.cc | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index 2b59798ff34..3357ad3471d 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -19,11 +19,9 @@ struct PosixTask : rtapi_task pthread_t thr; /* thread's context */ }; -struct Posix : RtapiApp +struct PosixApp : RtapiApp { - #define RTAPI_CLOCK (CLOCK_MONOTONIC) - - Posix(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { + PosixApp(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { if(instance != nullptr){ throw std::invalid_argument("Only one instance allowed!"); } @@ -108,7 +106,7 @@ struct Posix : RtapiApp pthread_mutex_lock(&instance->thread_lock); struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); + clock_gettime(CLOCK_MONOTONIC, &now); rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); /* call the task function with the task argument */ @@ -150,7 +148,7 @@ struct Posix : RtapiApp struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); struct timespec now; - clock_gettime(RTAPI_CLOCK, &now); + clock_gettime(CLOCK_MONOTONIC, &now); if(rtapi_timespec_less(task->nextstart, now)) { if(policy == SCHED_FIFO) @@ -219,15 +217,15 @@ struct Posix : RtapiApp clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); } - static Posix* instance; + static PosixApp* instance; }; -Posix* Posix::instance=nullptr; +PosixApp* PosixApp::instance=nullptr; -pthread_once_t Posix::key_once = PTHREAD_ONCE_INIT; -pthread_once_t Posix::lock_once = PTHREAD_ONCE_INIT; -pthread_key_t Posix::key; -pthread_mutex_t Posix::thread_lock; +pthread_once_t PosixApp::key_once = PTHREAD_ONCE_INIT; +pthread_once_t PosixApp::lock_once = PTHREAD_ONCE_INIT; +pthread_key_t PosixApp::key; +pthread_mutex_t PosixApp::thread_lock; } @@ -239,5 +237,5 @@ RtapiApp *make(int policy) { }else{ rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX realtime\n"); } - return new Posix(policy); + return new PosixApp(policy); } From c8af827762238ce5c85c83c34bdc6d0c22f97b17 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 17:59:07 +0200 Subject: [PATCH 12/19] Cleanup: Get rid of instance, we can lock before we start thread --- src/rtapi/uspace_posix.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index 3357ad3471d..18c4963068b 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -22,14 +22,10 @@ struct PosixTask : rtapi_task struct PosixApp : RtapiApp { PosixApp(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { - if(instance != nullptr){ - throw std::invalid_argument("Only one instance allowed!"); - } pthread_once(&key_once, init_key); if(do_thread_lock) { pthread_once(&lock_once, init_lock); } - instance = this; } struct rtapi_task *do_task_new() { @@ -90,6 +86,8 @@ struct PosixApp : RtapiApp return -ret; } } + if(do_thread_lock) + pthread_mutex_lock(&thread_lock); if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) return -ret; @@ -102,9 +100,6 @@ struct PosixApp : RtapiApp pthread_setspecific(key, arg); set_namef("rtapi_app:T#%d", task->id); - if(instance->do_thread_lock) - pthread_mutex_lock(&instance->thread_lock); - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); @@ -216,12 +211,8 @@ struct PosixApp : RtapiApp struct timespec ts = {0, ns}; clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); } - - static PosixApp* instance; }; -PosixApp* PosixApp::instance=nullptr; - pthread_once_t PosixApp::key_once = PTHREAD_ONCE_INIT; pthread_once_t PosixApp::lock_once = PTHREAD_ONCE_INIT; pthread_key_t PosixApp::key; From b762d047d3683a0bfc589aea2fd430db6fe957e9 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 19:06:51 +0200 Subject: [PATCH 13/19] Cleanup: Re-Add lost GPL headers --- src/rtapi/uspace_posix.cc | 17 +++++++++++++++++ src/rtapi/uspace_rtapi_app.cc | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index 18c4963068b..833aaa28211 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -1,3 +1,20 @@ +/* Copyright (C) 2006-2014 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include "config.h" #include "rtapi.h" #include "uspace_rtapi_app.hh" diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index 4f6b6ed04cf..2831fc51b4c 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -1,3 +1,20 @@ +/* Copyright (C) 2006-2014 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include "rtapi.h" #include "uspace_rtapi_app.hh" From fefeb053b42d3bd1f74f34938aa495b553a0d2b0 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 19:14:23 +0200 Subject: [PATCH 14/19] Cleanup: Add GPL headers where missing --- src/rtapi/uspace_rtai.cc | 16 ++++++++++++++++ src/rtapi/uspace_xenomai.cc | 16 ++++++++++++++++ src/rtapi/uspace_xenomai_evl.cc | 19 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index edab449be21..bf5ea576e80 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -1,3 +1,19 @@ +/* Copyright (C) 2016 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ #include "config.h" #include "rtapi.h" #include "uspace_rtapi_app.hh" diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index 1c51230d291..4c1c2d485b5 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -1,3 +1,19 @@ +/* Copyright (C) 2016 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ #include "config.h" #include "rtapi.h" #include "uspace_rtapi_app.hh" diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index 154d71ef542..4ed37933504 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -1,3 +1,22 @@ +/* Copyright (C) 2016 Jeff Epler + * Copyright (C) 2026 Hannes Diethelm + * Copy uspace_xenomai.cc and adapted to Xenomai4 EVL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include "config.h" #include "rtapi.h" #include "uspace_rtapi_app.hh" From 956f791a36c5ba8b8eb20bb6b25ed1702ad78ff4 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Mon, 6 Apr 2026 21:13:20 +0200 Subject: [PATCH 15/19] Cleanup: Nicer app init --- src/rtapi/uspace_rtapi_main.cc | 50 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index e47cea0162a..846b7cc35b7 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -747,32 +747,46 @@ static int harden_rt() static RtapiApp *makeDllApp(string dllName, int policy){ void *dll = nullptr; dll = dlopen(dllName.c_str(), RTLD_NOW); - if(!dll) fprintf(stderr, "dlopen: %s\n", dlerror()); + if(!dll){ + fprintf(stderr, "dlopen: %s\n", dlerror()); + return nullptr; + } auto fn = reinterpret_cast(dlsym(dll, "make")); - if(!fn) fprintf(stderr, "dlopen: %s\n", dlerror()); - auto result = fn ? fn(policy) : nullptr; - if(result) { - return result; - }else{ - throw invalid_argument("Could not load DLL!"); + if(!fn){ + fprintf(stderr, "dlsym: %s\n", dlerror()); + return nullptr; } + auto result = fn(policy); + if(!result) { + fprintf(stderr, "dlsym: %s\n", dlerror()); + return nullptr; + } + return result; } static RtapiApp *makeApp() { + RtapiApp* app; if(euid != 0 || harden_rt() < 0) { - return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); - } - WithRoot r; - if(detect_xenomai_evl()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); - }else if(detect_xenomai()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); - } else if(detect_rtai()) { - return makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); - } else { - return makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); + app=makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); + }else{ + WithRoot r; + if(detect_xenomai_evl()) { + app=makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); + }else if(detect_xenomai()) { + app=makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); + } else if(detect_rtai()) { + app=makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); + } else { + app=makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); + } + } + + if(!app){ + throw invalid_argument("Could not load rtapi dll"); + }else{ + return app; } } RtapiApp &App() From ef0f61a6d3abf2b1c7baa13eaaa7042c0e7a7dbe Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Tue, 7 Apr 2026 08:58:54 +0200 Subject: [PATCH 16/19] Cleanup: Get rid of "using namespace std" --- src/rtapi/uspace_rtapi_main.cc | 74 +++++++++++++++++----------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 846b7cc35b7..148eb1beae3 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -89,9 +89,7 @@ void *queue_function(void * /*arg*/) { static int sim_rtapi_run_threads(int fd, int (*callback)(int fd)); -using namespace std; - -template T DLSYM(void *handle, const string &name) { +template T DLSYM(void *handle, const std::string &name) { return (T)(dlsym(handle, name.c_str())); } @@ -99,12 +97,12 @@ template T DLSYM(void *handle, const char *name) { return (T)(dlsym(handle, name)); } -static std::map modules; +static std::map modules; static int instance_count = 0; static int force_exit = 0; -static int do_newinst_cmd(const string& type, const string& name, const string& arg) { +static int do_newinst_cmd(const std::string& type, const std::string& name, const std::string& arg) { void *module = modules["hal_lib"]; if(!module) { rtapi_print_msg(RTAPI_MSG_ERR, @@ -130,7 +128,7 @@ static int do_newinst_cmd(const string& type, const string& name, const string& return comp->make((char*)name.c_str(), (char*)arg.c_str()); } -static int do_one_item(char item_type_char, const string ¶m_name, const string ¶m_value, void *vitem, int idx=0) { +static int do_one_item(char item_type_char, const std::string ¶m_name, const std::string ¶m_value, void *vitem, int idx=0) { char *endp; switch(item_type_char) { case 'l': { @@ -169,22 +167,22 @@ static int do_one_item(char item_type_char, const string ¶m_name, const stri return 0; } -void remove_quotes(string &s) { +void remove_quotes(std::string &s) { s.erase(remove_copy(s.begin(), s.end(), s.begin(), '"'), s.end()); } -static int do_comp_args(void *module, vector args) { +static int do_comp_args(void *module, std::vector args) { for(unsigned i=1; i < args.size(); i++) { - string &s = args[i]; + std::string &s = args[i]; remove_quotes(s); size_t idx = s.find('='); - if(idx == string::npos) { + if(idx == std::string::npos) { rtapi_print_msg(RTAPI_MSG_ERR, "Invalid parameter `%s'\n", s.c_str()); return -1; } - string param_name(s, 0, idx); - string param_value(s, idx+1); + std::string param_name(s, 0, idx); + std::string param_value(s, idx+1); void *item=DLSYM(module, "rtapi_info_address_" + param_name); if(!item) { rtapi_print_msg(RTAPI_MSG_ERR, @@ -206,7 +204,7 @@ static int do_comp_args(void *module, vector args) { int max_size = *max_size_ptr; size_t idx = 0; int i = 0; - while(idx != string::npos) { + while(idx != std::string::npos) { if(i == max_size) { rtapi_print_msg(RTAPI_MSG_ERR, "%s: can only take %d arguments\n", @@ -214,11 +212,11 @@ static int do_comp_args(void *module, vector args) { return -1; } size_t idx1 = param_value.find(",", idx); - string substr(param_value, idx, idx1 - idx); + std::string substr(param_value, idx, idx1 - idx); int result = do_one_item(item_type_char, s, substr, item, i); if(result != 0) return result; i++; - idx = idx1 == string::npos ? idx1 : idx1 + 1; + idx = idx1 == std::string::npos ? idx1 : idx1 + 1; } } else { int result = do_one_item(item_type_char, s, param_value, item); @@ -228,7 +226,7 @@ static int do_comp_args(void *module, vector args) { return 0; } -static int do_load_cmd(const string& name, const vector& args) { +static int do_load_cmd(const std::string& name, const std::vector& args) { void *w = modules[name]; if(w == NULL) { char what[LINELEN+1]; @@ -272,7 +270,7 @@ static int do_load_cmd(const string& name, const vector& args) { } } -static int do_unload_cmd(const string& name) { +static int do_unload_cmd(const std::string& name) { void *w = modules[name]; if(w == NULL) { rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n", name.c_str()); @@ -287,7 +285,7 @@ static int do_unload_cmd(const string& name) { return 0; } -static int do_debug_cmd(const string& value) { +static int do_debug_cmd(const std::string& value) { try{ int new_level = stoi(value); if (new_level < 0 || new_level > 5){ @@ -295,7 +293,7 @@ static int do_debug_cmd(const string& value) { return -EINVAL; } return rtapi_set_msg_level(new_level); - }catch(invalid_argument &e){ + }catch(std::invalid_argument &e){ //stoi will throw an exception if parsing is not possible rtapi_print_msg(RTAPI_MSG_ERR, "Debug level is not a number\n"); return -EINVAL; @@ -318,20 +316,20 @@ static int read_number(int fd) { } } -static string read_string(int fd) { +static std::string read_string(int fd) { int len = read_number(fd); if(len < 0) throw ReadError(); if(!len) - return string(); - string str(len, 0); + return std::string(); + std::string str(len, 0); if(read(fd, str.data(), len) != len) throw ReadError(); return str; } -static vector read_strings(int fd) { - vector result; +static std::vector read_strings(int fd) { + std::vector result; int count = read_number(fd); if(count < 0) return result; @@ -341,19 +339,19 @@ static vector read_strings(int fd) { return result; } -static void write_number(string &buf, int num) { +static void write_number(std::string &buf, int num) { char numbuf[10]; snprintf(numbuf, sizeof(numbuf), "%d ", num); buf = buf + numbuf; } -static void write_string(string &buf, const string& s) { +static void write_string(std::string &buf, const std::string& s) { write_number(buf, s.size()); buf += s; } -static void write_strings(int fd, const vector& strings) { - string buf; +static void write_strings(int fd, const std::vector& strings) { + std::string buf; write_number(buf, strings.size()); for(unsigned int i=0; i& strings) { if(write(fd, buf.data(), buf.size()) != (ssize_t)buf.size()) throw WriteError(); } -static int handle_command(vector args) { +static int handle_command(std::vector args) { if(args.size() == 0) { return 0; } if(args.size() == 1 && args[0] == "exit") { force_exit = 1; return 0; } else if(args.size() >= 2 && args[0] == "load") { - string name = args[1]; + std::string name = args[1]; args.erase(args.begin()); return do_load_cmd(name, args); } else if(args.size() == 2 && args[0] == "unload") { @@ -386,7 +384,7 @@ static int handle_command(vector args) { } } -static int slave(int fd, const vector& args) { +static int slave(int fd, const std::vector& args) { try { write_strings(fd, args); } @@ -419,7 +417,7 @@ static int callback(int fd) close(fd1); return -1; } - string buf; + std::string buf; write_number(buf, result); if(write(fd1, buf.data(), buf.size()) != (ssize_t)buf.size()) { rtapi_print_msg(RTAPI_MSG_ERR, @@ -432,7 +430,7 @@ static int callback(int fd) static pthread_t main_thread{}; -static int master(int fd, const vector& args) { +static int master(int fd, const std::vector& args) { main_thread = pthread_self(); int result; if((result = pthread_create(&queue_thread, nullptr, &queue_function, nullptr)) != 0) { @@ -440,7 +438,7 @@ static int master(int fd, const vector& args) { perror("pthread_create (queue function)"); return -1; } - do_load_cmd("hal_lib", vector()); + do_load_cmd("hal_lib", std::vector()); instance_count = 0; App(); // force rtapi_app to be created if(args.size()) { @@ -520,8 +518,8 @@ int main(int argc, char **argv) { #ifdef __linux__ setfsuid(ruid); #endif - vector args; - for(int i=1; i args; + for(int i=1; i Date: Tue, 7 Apr 2026 09:22:56 +0200 Subject: [PATCH 17/19] Cleanup: use fmt::format where possible --- src/rtapi/Submakefile | 2 +- src/rtapi/uspace_rtapi_main.cc | 29 +++++++++++------------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index 92e1d2628ee..883f9486fc8 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -44,7 +44,7 @@ $(call TOOBJSDEPS, $(RTAPI_APP_SRCS)): EXTRAFLAGS += -DSIM \ -UULAPI -DRTAPI -pthread ../bin/rtapi_app: $(call TOOBJS, $(RTAPI_APP_SRCS)) $(ECHO) Linking $(notdir $@) - $(Q)$(CXX) -rdynamic -o $@ $^ $(LIBDL) -pthread -lrt $(LIBUDEV_LIBS) -ldl $(LDFLAGS) + $(Q)$(CXX) -rdynamic -o $@ $^ $(LIBDL) -pthread -lrt -lfmt $(LIBUDEV_LIBS) -ldl $(LDFLAGS) TARGETS += ../bin/rtapi_app endif diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 148eb1beae3..04b902c9781 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -51,6 +51,7 @@ #include #endif +#include #include #include "rtapi.h" @@ -229,9 +230,9 @@ static int do_comp_args(void *module, std::vector args) { static int do_load_cmd(const std::string& name, const std::vector& args) { void *w = modules[name]; if(w == NULL) { - char what[LINELEN+1]; - snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR, name.c_str()); - void *module = modules[name] = dlopen(what, RTLD_GLOBAL | RTLD_NOW); + std::string what; + what=fmt::format("{}/{}.so", EMC2_RTLIB_DIR, name); + void *module = modules[name] = dlopen(what.c_str(), RTLD_GLOBAL | RTLD_NOW); if(!module) { rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n", name.c_str(), dlerror()); modules.erase(name); @@ -340,9 +341,7 @@ static std::vector read_strings(int fd) { } static void write_number(std::string &buf, int num) { - char numbuf[10]; - snprintf(numbuf, sizeof(numbuf), "%d ", num); - buf = buf + numbuf; + buf = buf + fmt::format("{} ", num); } static void write_string(std::string &buf, const std::string& s) { @@ -457,7 +456,7 @@ static int master(int fd, const std::vector& args) { } static std::string -_get_fifo_path() { +get_fifo_path() { std::string s; if(getenv("RTAPI_FIFO_PATH")) s = getenv("RTAPI_FIFO_PATH"); @@ -466,29 +465,23 @@ _get_fifo_path() { else { rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe."); - return NULL; + return std::string(); } if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s", sizeof(sockaddr_un::sun_path), s.c_str()); - return NULL; + return std::string(); } return s; } -static const char * -get_fifo_path() { - static std::string path = _get_fifo_path(); - return path.c_str(); -} - static int get_fifo_path(char *buf, size_t bufsize) { int len; - const char *s = get_fifo_path(); - if(!s) return -1; - len=snprintf(buf+1, bufsize-1, "%s", s); + const std::string s = get_fifo_path(); + if(s.empty()) return -1; + len=snprintf(buf+1, bufsize-1, "%s", s.c_str()); return len; } From 0f39be6ccad344520a2d1b6e8f3063b7f9600e63 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Tue, 7 Apr 2026 09:38:28 +0200 Subject: [PATCH 18/19] Cleanup: Nicer get_fifo_path() / Add missing newlines --- src/rtapi/uspace_rtapi_main.cc | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 04b902c9781..420bd297860 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -137,7 +137,7 @@ static int do_one_item(char item_type_char, const std::string ¶m_name, const litem[idx] = strtol(param_value.c_str(), &endp, 0); if(*endp) { rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'", + "`%s' invalid for parameter `%s'\n", param_value.c_str(), param_name.c_str()); return -1; } @@ -148,7 +148,7 @@ static int do_one_item(char item_type_char, const std::string ¶m_name, const iitem[idx] = strtol(param_value.c_str(), &endp, 0); if(*endp) { rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'", + "`%s' invalid for parameter `%s'\n", param_value.c_str(), param_name.c_str()); return -1; } @@ -458,20 +458,13 @@ static int master(int fd, const std::vector& args) { static std::string get_fifo_path() { std::string s; - if(getenv("RTAPI_FIFO_PATH")) + if(getenv("RTAPI_FIFO_PATH")){ s = getenv("RTAPI_FIFO_PATH"); - else if(getenv("HOME")) + }else if(getenv("HOME")){ s = std::string(getenv("HOME")) + "/.rtapi_fifo"; - else { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe."); - return std::string(); - } - if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { + }else{ rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s", - sizeof(sockaddr_un::sun_path), s.c_str()); - return std::string(); + "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe.\n"); } return s; } @@ -480,7 +473,15 @@ static int get_fifo_path(char *buf, size_t bufsize) { int len; const std::string s = get_fifo_path(); - if(s.empty()) return -1; + if(s.empty()){ + return -1; + } + if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { + rtapi_print_msg(RTAPI_MSG_ERR, + "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s\n", + sizeof(sockaddr_un::sun_path), s.c_str()); + return -1; + } len=snprintf(buf+1, bufsize-1, "%s", s.c_str()); return len; } From f0a0d6f81f5f44c0d882f714311bc4093cbe9a10 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Tue, 7 Apr 2026 19:22:58 +0200 Subject: [PATCH 19/19] Cleanup: Clang format --- src/rtapi/uspace_posix.cc | 131 +++--- src/rtapi/uspace_rtai.cc | 81 ++-- src/rtapi/uspace_rtapi_app.cc | 178 ++++---- src/rtapi/uspace_rtapi_app.hh | 71 +-- src/rtapi/uspace_rtapi_main.cc | 775 ++++++++++++++++++-------------- src/rtapi/uspace_xenomai.cc | 108 +++-- src/rtapi/uspace_xenomai_evl.cc | 104 +++-- 7 files changed, 831 insertions(+), 617 deletions(-) diff --git a/src/rtapi/uspace_posix.cc b/src/rtapi/uspace_posix.cc index 833aaa28211..3d4d41f4288 100644 --- a/src/rtapi/uspace_posix.cc +++ b/src/rtapi/uspace_posix.cc @@ -26,21 +26,19 @@ #include #endif -namespace -{ -struct PosixTask : rtapi_task -{ - PosixTask() : rtapi_task{}, thr{} - {} - - pthread_t thr; /* thread's context */ +namespace { +struct PosixTask : rtapi_task { + PosixTask() : rtapi_task{}, thr{} { + } + + pthread_t thr; /* thread's context */ }; -struct PosixApp : RtapiApp -{ - PosixApp(int policy = SCHED_FIFO) : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { +struct PosixApp : RtapiApp { + PosixApp(int policy = SCHED_FIFO) + : RtapiApp(policy), do_thread_lock(policy != SCHED_FIFO) { pthread_once(&key_once, init_key); - if(do_thread_lock) { + if (do_thread_lock) { pthread_once(&lock_once, init_lock); } } @@ -51,7 +49,8 @@ struct PosixApp : RtapiApp int task_delete(int id) { auto task = ::rtapi_get_task(id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; pthread_cancel(task->thr); pthread_join(task->thr, 0); @@ -63,7 +62,8 @@ struct PosixApp : RtapiApp int task_start(int task_id, unsigned long period_nsec) { auto task = ::rtapi_get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->period = period_nsec; struct sched_param param; @@ -74,55 +74,59 @@ struct PosixApp : RtapiApp task->pll_correction_limit = period_nsec / 100; task->pll_correction = 0; - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); + int nprocs = sysconf(_SC_NPROCESSORS_ONLN); pthread_attr_t attr; int ret; - if((ret = pthread_attr_init(&attr)) != 0) + if ((ret = pthread_attr_init(&attr)) != 0) return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + if ((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + if ((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) return -ret; - if(nprocs > 1){ + if (nprocs > 1) { const static int rt_cpu_number = find_rt_cpu_number(); - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); - if(rt_cpu_number != -1) { - #ifdef __FreeBSD__ + rtapi_print_msg( + RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number + ); + if (rt_cpu_number != -1) { +#ifdef __FreeBSD__ cpuset_t cpuset; - #else +#else cpu_set_t cpuset; - #endif +#endif CPU_ZERO(&cpuset); CPU_SET(rt_cpu_number, &cpuset); - if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) + if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) return -ret; } } - if(do_thread_lock) + if (do_thread_lock) pthread_mutex_lock(&thread_lock); - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + if ((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) return -ret; return 0; } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); set_namef("rtapi_app:T#%d", task->id); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); + rtapi_timespec_advance( + task->nextstart, now, task->period + task->pll_correction + ); /* call the task function with the task argument */ - (task->taskcode) (task->arg); + (task->taskcode)(task->arg); rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); return NULL; @@ -139,39 +143,50 @@ struct PosixApp : RtapiApp } long long task_pll_get_reference(void) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return 0; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return 0; return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; } int task_pll_set_correction(long value) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - if (value > task->pll_correction_limit) value = task->pll_correction_limit; - if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; + if (value > task->pll_correction_limit) + value = task->pll_correction_limit; + if (value < -(task->pll_correction_limit)) + value = -(task->pll_correction_limit); task->pll_correction = value; return 0; } void wait() { - if(do_thread_lock) + if (do_thread_lock) pthread_mutex_unlock(&thread_lock); pthread_testcancel(); - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + rtapi_timespec_advance( + task->nextstart, + task->nextstart, + task->period + task->pll_correction + ); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if(rtapi_timespec_less(task->nextstart, now)) - { - if(policy == SCHED_FIFO) + if (rtapi_timespec_less(task->nextstart, now)) { + if (policy == SCHED_FIFO) unexpected_realtime_delay(task); + } else { + int res = clock_nanosleep( + CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr + ); + if (res < 0) + perror("clock_nanosleep"); } - else - { - int res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr); - if(res < 0) perror("clock_nanosleep"); - } - if(do_thread_lock) + if (do_thread_lock) pthread_mutex_lock(&thread_lock); } @@ -194,13 +209,17 @@ struct PosixApp : RtapiApp } int run_threads(int fd, int (*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } + while (callback(fd)) { + /* nothing */ + } return 0; } int task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; return task->id; } @@ -235,14 +254,14 @@ pthread_once_t PosixApp::lock_once = PTHREAD_ONCE_INIT; pthread_key_t PosixApp::key; pthread_mutex_t PosixApp::thread_lock; -} +} // namespace extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - if(policy == SCHED_OTHER){ + if (policy == SCHED_OTHER) { rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX non-realtime\n"); - }else{ + } else { rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using POSIX realtime\n"); } return new PosixApp(policy); diff --git a/src/rtapi/uspace_rtai.cc b/src/rtapi/uspace_rtai.cc index bf5ea576e80..209da69cea6 100644 --- a/src/rtapi/uspace_rtai.cc +++ b/src/rtapi/uspace_rtai.cc @@ -26,20 +26,19 @@ #include #endif -namespace -{ +namespace { RtapiApp *app; struct RtaiTask : rtapi_task { - RtaiTask() : rtapi_task{}, cancel{}, rt_task{}, thr{} {} + RtaiTask() : rtapi_task{}, cancel{}, rt_task{}, thr{} { + } std::atomic_int cancel; RT_TASK *rt_task; pthread_t thr; }; -template -T *get_task(int task_id) { - return static_cast(RtapiApp::get_task(task_id)); +template T *get_task(int task_id) { + return static_cast(RtapiApp::get_task(task_id)); } @@ -54,7 +53,8 @@ struct RtaiApp : RtapiApp { int task_delete(int id) { auto task = ::get_task(id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->cancel = 1; pthread_join(task->thr, nullptr); @@ -66,7 +66,8 @@ struct RtaiApp : RtapiApp { int task_start(int task_id, unsigned long period_nsec) { auto task = ::get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->period = period_nsec; struct sched_param param; @@ -79,40 +80,47 @@ struct RtaiApp : RtapiApp { int ret; pthread_attr_t attr; - if((ret = pthread_attr_init(&attr)) != 0) + if ((ret = pthread_attr_init(&attr)) != 0) return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + if ((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + if ((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) return -ret; - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + if ((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) return -ret; return 0; } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); - - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); - int cpus_allowed = 1 << (nprocs-1); //Use last CPU as default + + int nprocs = sysconf(_SC_NPROCESSORS_ONLN); + int cpus_allowed = 1 << (nprocs - 1); //Use last CPU as default const static int rt_cpu_number = find_rt_cpu_number(); - if(rt_cpu_number != -1) { - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); + if (rt_cpu_number != -1) { + rtapi_print_msg( + RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number + ); cpus_allowed = 1 << rt_cpu_number; } - task->rt_task = rt_task_init_schmod(task->id, task->prio, 0, 0, SCHED_FIFO, cpus_allowed); + task->rt_task = rt_task_init_schmod( + task->id, task->prio, 0, 0, SCHED_FIFO, cpus_allowed + ); rt_set_periodic_mode(); start_rt_timer(nano2count(task->period)); - if(task->uses_fp) rt_task_use_fpu(task->rt_task, 1); + if (task->uses_fp) + rt_task_use_fpu(task->rt_task, 1); rt_make_hard_real_time(); - rt_task_make_periodic_relative_ns(task->rt_task, task->period, task->period); - (task->taskcode) (task->arg); + rt_task_make_periodic_relative_ns( + task->rt_task, task->period, task->period + ); + (task->taskcode)(task->arg); rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); rt_make_soft_real_time(); @@ -121,13 +129,15 @@ struct RtaiApp : RtapiApp { int task_pause(int task_id) { auto task = ::get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; return rt_task_suspend(task->rt_task); } int task_resume(int task_id) { auto task = ::get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; return rt_task_resume(task->rt_task); } @@ -145,11 +155,12 @@ struct RtaiApp : RtapiApp { void wait() { int task_id = task_self(); auto task = ::get_task(task_id); - if(task->cancel) { + if (task->cancel) { rt_make_soft_real_time(); pthread_exit(nullptr); } - if(rt_task_wait_period() < 0) unexpected_realtime_delay(task); + if (rt_task_wait_period() < 0) + unexpected_realtime_delay(task); } unsigned char do_inb(unsigned int port) { @@ -171,13 +182,17 @@ struct RtaiApp : RtapiApp { } int run_threads(int fd, int (*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } + while (callback(fd)) { + /* nothing */ + } return 0; } int task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; return task->id; } @@ -206,12 +221,12 @@ struct RtaiApp : RtapiApp { pthread_once_t RtaiApp::key_once; pthread_key_t RtaiApp::key; -} +} // namespace extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - if(policy != SCHED_FIFO){ + if (policy != SCHED_FIFO) { throw std::invalid_argument("Only SCHED_FIFO allowed"); } rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using LXRT realtime\n"); diff --git a/src/rtapi/uspace_rtapi_app.cc b/src/rtapi/uspace_rtapi_app.cc index 2831fc51b4c..2bdebc162ee 100644 --- a/src/rtapi/uspace_rtapi_app.cc +++ b/src/rtapi/uspace_rtapi_app.cc @@ -26,7 +26,7 @@ std::atomic_int WithRoot::level; uid_t euid, ruid; WithRoot::WithRoot() { - if(!level++) { + if (!level++) { #ifdef __linux__ setfsuid(euid); #endif @@ -34,7 +34,7 @@ WithRoot::WithRoot() { } WithRoot::~WithRoot() { - if(!--level) { + if (!--level) { #ifdef __linux__ setfsuid(ruid); #endif @@ -42,34 +42,31 @@ WithRoot::~WithRoot() { } rtapi_task::rtapi_task() - : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, - period{}, nextstart{}, - pll_correction{}, pll_correction_limit{}, - arg{}, taskcode{} + : magic{}, id{}, owner{}, uses_fp{}, stacksize{}, prio{}, period{}, + nextstart{}, pll_correction{}, pll_correction_limit{}, arg{}, taskcode{} -{} +{ +} /* Priority functions. Uspace uses POSIX task priorities. */ -int RtapiApp::prio_highest() const -{ +int RtapiApp::prio_highest() const { return sched_get_priority_max(policy); } -int RtapiApp::prio_lowest() const -{ - return sched_get_priority_min(policy); +int RtapiApp::prio_lowest() const { + return sched_get_priority_min(policy); } int RtapiApp::prio_higher_delta() const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { + if (rtapi_prio_highest() > rtapi_prio_lowest()) { return 1; } return -1; } int RtapiApp::prio_bound(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { + if (rtapi_prio_highest() > rtapi_prio_lowest()) { if (prio >= rtapi_prio_highest()) return rtapi_prio_highest(); if (prio < rtapi_prio_lowest()) @@ -84,76 +81,82 @@ int RtapiApp::prio_bound(int prio) const { } bool RtapiApp::prio_check(int prio) const { - if(rtapi_prio_highest() > rtapi_prio_lowest()) { + if (rtapi_prio_highest() > rtapi_prio_lowest()) { return (prio <= rtapi_prio_highest()) && (prio >= rtapi_prio_lowest()); } else { return (prio <= rtapi_prio_lowest()) && (prio >= rtapi_prio_highest()); } } -int RtapiApp::prio_next_higher(int prio) const -{ +int RtapiApp::prio_next_higher(int prio) const { prio = prio_bound(prio); - if(prio != rtapi_prio_highest()) + if (prio != rtapi_prio_highest()) return prio + prio_higher_delta(); return prio; } -int RtapiApp::prio_next_lower(int prio) const -{ +int RtapiApp::prio_next_lower(int prio) const { prio = prio_bound(prio); - if(prio != rtapi_prio_lowest()) + if (prio != rtapi_prio_lowest()) return prio - prio_higher_delta(); return prio; } -int RtapiApp::allocate_task_id() -{ - for(int n=0; nid = n; - task->owner = owner; - task->uses_fp = uses_fp; - task->arg = arg; - task->stacksize = stacksize; - task->taskcode = taskcode; - task->prio = prio; - task->magic = TASK_MAGIC; - task_array[n] = task; - - /* and return handle to the caller */ - - return n; +int RtapiApp::task_new( + void (*taskcode)(void *), + void *arg, + int prio, + int owner, + unsigned long int stacksize, + int uses_fp +) { + /* check requested priority */ + if (!prio_check(prio)) { + rtapi_print_msg(RTAPI_MSG_ERR,"rtapi:task_new prio is not in bound lowest %i prio %i highest %i\n", + rtapi_prio_lowest(), prio, rtapi_prio_highest()); + return -EINVAL; + } + + /* label as a valid task structure */ + int n = allocate_task_id(); + if (n < 0) + return n; + + struct rtapi_task *task = do_task_new(); + if (stacksize < (1024 * 1024)) + stacksize = (1024 * 1024); + task->id = n; + task->owner = owner; + task->uses_fp = uses_fp; + task->arg = arg; + task->stacksize = stacksize; + task->taskcode = taskcode; + task->prio = prio; + task->magic = TASK_MAGIC; + task_array[n] = task; + + /* and return handle to the caller */ + + return n; } rtapi_task *RtapiApp::get_task(int task_id) { - if(task_id < 0 || task_id >= MAX_TASKS) return NULL; + if (task_id < 0 || task_id >= MAX_TASKS) + return NULL; /* validate task handle */ rtapi_task *task = task_array[task_id]; - if(!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) + if (!task || task == TASK_MAGIC_INIT || task->magic != TASK_MAGIC) return NULL; return task; @@ -161,32 +164,33 @@ rtapi_task *RtapiApp::get_task(int task_id) { void RtapiApp::unexpected_realtime_delay(rtapi_task *task, int /*nperiod*/) { static int printed = 0; - if(!printed) - { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unexpected realtime delay on task %d with period %ld\n" - "This Message will only display once per session.\n" - "Run the Latency Test and resolve before continuing.\n", - task->id, task->period); + if (!printed) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "Unexpected realtime delay on task %d with period %ld\n" + "This Message will only display once per session.\n" + "Run the Latency Test and resolve before continuing.\n", + task->id, + task->period + ); printed = 1; } } -long RtapiApp::clock_set_period(long nsecs) -{ - if(nsecs == 0) return period; - if(period != 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); - return -EINVAL; - } - period = nsecs; - return period; +long RtapiApp::clock_set_period(long nsecs) { + if (nsecs == 0) + return period; + if (period != 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); + return -EINVAL; + } + period = nsecs; + return period; } //parse_cpu_list from https://gitlab.com/Xenomai/xenomai4/libevl/-/blob/11e6a1fb183a315ae861762e7650fd5e10d83ff5/tests/helpers.c //License: MIT -static void parse_cpu_list(const char *path, cpu_set_t *cpuset) -{ +static void parse_cpu_list(const char *path, cpu_set_t *cpuset) { char *p, *range, *range_p = NULL, *id, *id_r; int start, end, cpu; char buf[BUFSIZ]; @@ -225,29 +229,35 @@ static void parse_cpu_list(const char *path, cpu_set_t *cpuset) } int find_rt_cpu_number() { - if(getenv("RTAPI_CPU_NUMBER")) return atoi(getenv("RTAPI_CPU_NUMBER")); + if (getenv("RTAPI_CPU_NUMBER")) + return atoi(getenv("RTAPI_CPU_NUMBER")); #ifdef __linux__ - const char* isolated_file="/sys/devices/system/cpu/isolated"; + const char *isolated_file = "/sys/devices/system/cpu/isolated"; cpu_set_t cpuset; parse_cpu_list(isolated_file, &cpuset); //Print list rtapi_print_msg(RTAPI_MSG_INFO, "cpuset isolated "); - for(int i=0; i tb.tv_sec) return 0; +static inline bool +rtapi_timespec_less(const struct timespec &ta, const struct timespec &tb) { + if (ta.tv_sec < tb.tv_sec) + return 1; + if (ta.tv_sec > tb.tv_sec) + return 0; return ta.tv_nsec < tb.tv_nsec; } -void rtapi_timespec_advance(struct timespec &result, const struct timespec &src, unsigned long nsec); +void rtapi_timespec_advance( + struct timespec &result, const struct timespec &src, unsigned long nsec +); -struct WithRoot -{ +struct WithRoot { WithRoot(); ~WithRoot(); static std::atomic_int level; }; struct rtapi_task { - rtapi_task(); + rtapi_task(); - int magic; /* to check for valid handle */ - int id; - int owner; - int uses_fp; - size_t stacksize; - int prio; - long period; - struct timespec nextstart; - long pll_correction; - long pll_correction_limit; - void *arg; - void (*taskcode) (void*); /* pointer to task function */ + int magic; /* to check for valid handle */ + int id; + int owner; + int uses_fp; + size_t stacksize; + int prio; + long period; + struct timespec nextstart; + long pll_correction; + long pll_correction_limit; + void *arg; + void (*taskcode)(void *); /* pointer to task function */ }; -struct RtapiApp -{ +struct RtapiApp { - RtapiApp(int policy = SCHED_OTHER) : policy(policy), period(0) {} + RtapiApp(int policy = SCHED_OTHER) : policy(policy), period(0) { + } virtual int prio_highest() const; virtual int prio_lowest() const; @@ -78,12 +82,18 @@ struct RtapiApp int prio_next_higher(int prio) const; int prio_next_lower(int prio) const; long clock_set_period(long int period_nsec); - int task_new(void (*taskcode)(void*), void *arg, - int prio, int owner, unsigned long int stacksize, int uses_fp); + int task_new( + void (*taskcode)(void *), + void *arg, + int prio, + int owner, + unsigned long int stacksize, + int uses_fp + ); virtual rtapi_task *do_task_new() = 0; static int allocate_task_id(); static struct rtapi_task *get_task(int task_id); - void unexpected_realtime_delay(rtapi_task *task, int nperiod=1); + void unexpected_realtime_delay(rtapi_task *task, int nperiod = 1); virtual int task_delete(int id) = 0; virtual int task_start(int task_id, unsigned long period_nsec) = 0; virtual int task_pause(int task_id) = 0; @@ -101,17 +111,16 @@ struct RtapiApp long period; }; -template -T *rtapi_get_task(int task_id) { - return static_cast(RtapiApp::get_task(task_id)); +template T *rtapi_get_task(int task_id) { + return static_cast(RtapiApp::get_task(task_id)); } int find_rt_cpu_number(); void set_namef(const char *fmt, ...); -#define MAX_TASKS 64 -#define TASK_MAGIC 21979 /* random numbers used as signatures */ -#define TASK_MAGIC_INIT ((rtapi_task*)(-1)) +#define MAX_TASKS 64 +#define TASK_MAGIC 21979 /* random numbers used as signatures */ +#define TASK_MAGIC_INIT ((rtapi_task *)(-1)) extern struct rtapi_task *task_array[MAX_TASKS]; diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 420bd297860..0617595b5d9 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -63,11 +63,11 @@ RtapiApp &App(); struct message_t { msg_level_t level; - char msg[1024-sizeof(level)]; + char msg[1024 - sizeof(level)]; }; boost::lockfree::queue> -rtapi_msg_queue; + rtapi_msg_queue; pthread_t queue_thread; void *queue_function(void * /*arg*/) { @@ -75,7 +75,7 @@ void *queue_function(void * /*arg*/) { // note: can't use anything in this function that requires App() to exist // but it's OK to use functions that aren't safe for realtime (that's the // point of running this in a thread) - while(1) { + while (1) { pthread_testcancel(); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); rtapi_msg_queue.consume_all([](const message_t &m) { @@ -90,81 +90,101 @@ void *queue_function(void * /*arg*/) { static int sim_rtapi_run_threads(int fd, int (*callback)(int fd)); -template T DLSYM(void *handle, const std::string &name) { - return (T)(dlsym(handle, name.c_str())); +template T DLSYM(void *handle, const std::string &name) { + return (T)(dlsym(handle, name.c_str())); } -template T DLSYM(void *handle, const char *name) { - return (T)(dlsym(handle, name)); +template T DLSYM(void *handle, const char *name) { + return (T)(dlsym(handle, name)); } -static std::map modules; +static std::map modules; static int instance_count = 0; static int force_exit = 0; -static int do_newinst_cmd(const std::string& type, const std::string& name, const std::string& arg) { +static int do_newinst_cmd( + const std::string &type, const std::string &name, const std::string &arg +) { void *module = modules["hal_lib"]; - if(!module) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: hal_lib is required, but not loaded\n"); + if (!module) { + rtapi_print_msg( + RTAPI_MSG_ERR, "newinst: hal_lib is required, but not loaded\n" + ); return -1; } - hal_comp_t *(*find_comp_by_name)(char*) = - DLSYM(module, "halpr_find_comp_by_name"); - if(!find_comp_by_name) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: halpr_find_comp_by_name not found\n"); + hal_comp_t *(*find_comp_by_name)(char *) = + DLSYM(module, "halpr_find_comp_by_name"); + if (!find_comp_by_name) { + rtapi_print_msg( + RTAPI_MSG_ERR, "newinst: halpr_find_comp_by_name not found\n" + ); return -1; } - hal_comp_t *comp = find_comp_by_name((char*)type.c_str()); - if(!comp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "newinst: component %s not found\n", type.c_str()); + hal_comp_t *comp = find_comp_by_name((char *)type.c_str()); + if (!comp) { + rtapi_print_msg( + RTAPI_MSG_ERR, "newinst: component %s not found\n", type.c_str() + ); return -1; } - return comp->make((char*)name.c_str(), (char*)arg.c_str()); + return comp->make((char *)name.c_str(), (char *)arg.c_str()); } -static int do_one_item(char item_type_char, const std::string ¶m_name, const std::string ¶m_value, void *vitem, int idx=0) { +static int do_one_item( + char item_type_char, + const std::string ¶m_name, + const std::string ¶m_value, + void *vitem, + int idx = 0 +) { char *endp; - switch(item_type_char) { - case 'l': { - long *litem = *(long**) vitem; - litem[idx] = strtol(param_value.c_str(), &endp, 0); - if(*endp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'\n", - param_value.c_str(), param_name.c_str()); - return -1; - } - return 0; - } - case 'i': { - int *iitem = *(int**) vitem; - iitem[idx] = strtol(param_value.c_str(), &endp, 0); - if(*endp) { - rtapi_print_msg(RTAPI_MSG_ERR, - "`%s' invalid for parameter `%s'\n", - param_value.c_str(), param_name.c_str()); - return -1; - } - return 0; - } - case 's': { - char **sitem = *(char***) vitem; - sitem[idx] = strdup(param_value.c_str()); - return 0; + switch (item_type_char) { + case 'l': { + long *litem = *(long **)vitem; + litem[idx] = strtol(param_value.c_str(), &endp, 0); + if (*endp) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'\n", + param_value.c_str(), + param_name.c_str() + ); + return -1; } - default: - rtapi_print_msg(RTAPI_MSG_ERR, - "%s: Invalid type character `%c'\n", - param_name.c_str(), item_type_char); + return 0; + } + case 'i': { + int *iitem = *(int **)vitem; + iitem[idx] = strtol(param_value.c_str(), &endp, 0); + if (*endp) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'\n", + param_value.c_str(), + param_name.c_str() + ); return -1; } + return 0; + } + case 's': { + char **sitem = *(char ***)vitem; + sitem[idx] = strdup(param_value.c_str()); + return 0; + } + default: + rtapi_print_msg( + RTAPI_MSG_ERR, + "%s: Invalid type character `%c'\n", + param_name.c_str(), + item_type_char + ); + return -1; + } return 0; } @@ -173,75 +193,92 @@ void remove_quotes(std::string &s) { } static int do_comp_args(void *module, std::vector args) { - for(unsigned i=1; i < args.size(); i++) { + for (unsigned i = 1; i < args.size(); i++) { std::string &s = args[i]; - remove_quotes(s); + remove_quotes(s); size_t idx = s.find('='); - if(idx == std::string::npos) { - rtapi_print_msg(RTAPI_MSG_ERR, "Invalid parameter `%s'\n", - s.c_str()); + if (idx == std::string::npos) { + rtapi_print_msg( + RTAPI_MSG_ERR, "Invalid parameter `%s'\n", s.c_str() + ); return -1; } std::string param_name(s, 0, idx); - std::string param_value(s, idx+1); - void *item=DLSYM(module, "rtapi_info_address_" + param_name); - if(!item) { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unknown parameter `%s'\n", s.c_str()); + std::string param_value(s, idx + 1); + void *item = DLSYM(module, "rtapi_info_address_" + param_name); + if (!item) { + rtapi_print_msg( + RTAPI_MSG_ERR, "Unknown parameter `%s'\n", s.c_str() + ); return -1; } - char **item_type=DLSYM(module, "rtapi_info_type_" + param_name); - if(!item_type || !*item_type) { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unknown parameter `%s' (type information missing)\n", - s.c_str()); + char **item_type = + DLSYM(module, "rtapi_info_type_" + param_name); + if (!item_type || !*item_type) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "Unknown parameter `%s' (type information missing)\n", + s.c_str() + ); return -1; } - int*max_size_ptr=DLSYM(module, "rtapi_info_size_" + param_name); + int *max_size_ptr = + DLSYM(module, "rtapi_info_size_" + param_name); char item_type_char = **item_type; - if(max_size_ptr) { + if (max_size_ptr) { int max_size = *max_size_ptr; size_t idx = 0; int i = 0; - while(idx != std::string::npos) { - if(i == max_size) { - rtapi_print_msg(RTAPI_MSG_ERR, - "%s: can only take %d arguments\n", - s.c_str(), max_size); + while (idx != std::string::npos) { + if (i == max_size) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "%s: can only take %d arguments\n", + s.c_str(), + max_size + ); return -1; } size_t idx1 = param_value.find(",", idx); std::string substr(param_value, idx, idx1 - idx); int result = do_one_item(item_type_char, s, substr, item, i); - if(result != 0) return result; + if (result != 0) + return result; i++; idx = idx1 == std::string::npos ? idx1 : idx1 + 1; } } else { int result = do_one_item(item_type_char, s, param_value, item); - if(result != 0) return result; + if (result != 0) + return result; } } return 0; } -static int do_load_cmd(const std::string& name, const std::vector& args) { +static int +do_load_cmd(const std::string &name, const std::vector &args) { void *w = modules[name]; - if(w == NULL) { + if (w == NULL) { std::string what; - what=fmt::format("{}/{}.so", EMC2_RTLIB_DIR, name); - void *module = modules[name] = dlopen(what.c_str(), RTLD_GLOBAL | RTLD_NOW); - if(!module) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n", name.c_str(), dlerror()); + what = fmt::format("{}/{}.so", EMC2_RTLIB_DIR, name); + void *module = modules[name] = + dlopen(what.c_str(), RTLD_GLOBAL | RTLD_NOW); + if (!module) { + rtapi_print_msg( + RTAPI_MSG_ERR, "%s: dlopen: %s\n", name.c_str(), dlerror() + ); modules.erase(name); return -1; } - /// XXX handle arguments - int (*start)(void) = DLSYM(module, "rtapi_app_main"); - if(!start) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlsym: %s\n", name.c_str(), dlerror()); + /// XXX handle arguments + int (*start)(void) = DLSYM(module, "rtapi_app_main"); + if (!start) { + rtapi_print_msg( + RTAPI_MSG_ERR, "%s: dlsym: %s\n", name.c_str(), dlerror() + ); dlclose(module); modules.erase(name); return -1; @@ -249,21 +286,26 @@ static int do_load_cmd(const std::string& name, const std::vector& int result; result = do_comp_args(module, args); - if(result < 0) { + if (result < 0) { dlclose(module); modules.erase(name); return -1; } - if ((result=start()) < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, "%s: rtapi_app_main: %s (%d)\n", - name.c_str(), strerror(-result), result); + if ((result = start()) < 0) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "%s: rtapi_app_main: %s (%d)\n", + name.c_str(), + strerror(-result), + result + ); dlclose(module); modules.erase(name); - return result; + return result; } else { - instance_count ++; - return 0; + instance_count++; + return 0; } } else { rtapi_print_msg(RTAPI_MSG_ERR, "%s: already exists\n", name.c_str()); @@ -271,30 +313,33 @@ static int do_load_cmd(const std::string& name, const std::vector& } } -static int do_unload_cmd(const std::string& name) { +static int do_unload_cmd(const std::string &name) { void *w = modules[name]; - if(w == NULL) { + if (w == NULL) { rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n", name.c_str()); - return -1; + return -1; } else { - int (*stop)(void) = DLSYM(w, "rtapi_app_exit"); - if(stop) stop(); - modules.erase(modules.find(name)); + int (*stop)(void) = DLSYM(w, "rtapi_app_exit"); + if (stop) + stop(); + modules.erase(modules.find(name)); dlclose(w); - instance_count --; + instance_count--; } return 0; } -static int do_debug_cmd(const std::string& value) { - try{ +static int do_debug_cmd(const std::string &value) { + try { int new_level = stoi(value); - if (new_level < 0 || new_level > 5){ - rtapi_print_msg(RTAPI_MSG_ERR, "Debug level must be >=0 and <= 5\n"); + if (new_level < 0 || new_level > 5) { + rtapi_print_msg( + RTAPI_MSG_ERR, "Debug level must be >=0 and <= 5\n" + ); return -EINVAL; } return rtapi_set_msg_level(new_level); - }catch(std::invalid_argument &e){ + } catch (std::invalid_argument &e) { //stoi will throw an exception if parsing is not possible rtapi_print_msg(RTAPI_MSG_ERR, "Debug level is not a number\n"); return -EINVAL; @@ -305,26 +350,30 @@ struct ReadError : std::exception {}; struct WriteError : std::exception {}; static int read_number(int fd) { - int r = 0, neg=1; + int r = 0, neg = 1; char ch; - while(1) { + while (1) { int res = read(fd, &ch, 1); - if(res != 1) return -1; - if(ch == '-') neg = -1; - else if(ch == ' ') return r * neg; - else r = 10 * r + ch - '0'; + if (res != 1) + return -1; + if (ch == '-') + neg = -1; + else if (ch == ' ') + return r * neg; + else + r = 10 * r + ch - '0'; } } static std::string read_string(int fd) { int len = read_number(fd); - if(len < 0) + if (len < 0) throw ReadError(); - if(!len) + if (!len) return std::string(); std::string str(len, 0); - if(read(fd, str.data(), len) != len) + if (read(fd, str.data(), len) != len) throw ReadError(); return str; } @@ -332,9 +381,9 @@ static std::string read_string(int fd) { static std::vector read_strings(int fd) { std::vector result; int count = read_number(fd); - if(count < 0) + if (count < 0) return result; - for(int i=0; i& strings) { +static void write_strings(int fd, const std::vector &strings) { std::string buf; write_number(buf, strings.size()); - for(unsigned int i=0; i args) { - if(args.size() == 0) { return 0; } - if(args.size() == 1 && args[0] == "exit") { + if (args.size() == 0) { + return 0; + } + if (args.size() == 1 && args[0] == "exit") { force_exit = 1; return 0; - } else if(args.size() >= 2 && args[0] == "load") { + } else if (args.size() >= 2 && args[0] == "load") { std::string name = args[1]; args.erase(args.begin()); return do_load_cmd(name, args); - } else if(args.size() == 2 && args[0] == "unload") { + } else if (args.size() == 2 && args[0] == "unload") { return do_unload_cmd(args[1]); - } else if(args.size() == 3 && args[0] == "newinst") { + } else if (args.size() == 3 && args[0] == "newinst") { return do_newinst_cmd(args[1], args[2], ""); - } else if(args.size() == 4 && args[0] == "newinst") { + } else if (args.size() == 4 && args[0] == "newinst") { return do_newinst_cmd(args[1], args[2], args[3]); - } else if(args.size() == 2 && args[0] == "debug") { + } else if (args.size() == 2 && args[0] == "debug") { return do_debug_cmd(args[1]); } else { - rtapi_print_msg(RTAPI_MSG_ERR, - "Unrecognized command starting with %s\n", - args[0].c_str()); + rtapi_print_msg( + RTAPI_MSG_ERR, + "Unrecognized command starting with %s\n", + args[0].c_str() + ); return -1; } } -static int slave(int fd, const std::vector& args) { +static int slave(int fd, const std::vector &args) { try { write_strings(fd, args); - } - catch (WriteError &e) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to write to master: %s\n", strerror(errno)); + } catch (WriteError &e) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: failed to write to master: %s\n", + strerror(errno) + ); } int result = read_number(fd); return result; } -static int callback(int fd) -{ +static int callback(int fd) { struct sockaddr_un client_addr; memset(&client_addr, 0, sizeof(client_addr)); socklen_t len = sizeof(client_addr); - int fd1 = accept(fd, (sockaddr*)&client_addr, &len); - if(fd1 < 0) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to accept connection from slave: %s\n", strerror(errno)); + int fd1 = accept(fd, (sockaddr *)&client_addr, &len); + if (fd1 < 0) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: failed to accept connection from slave: %s\n", + strerror(errno) + ); return -1; } else { int result; try { result = handle_command(read_strings(fd1)); } catch (ReadError &e) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to read from slave: %s\n", strerror(errno)); + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: failed to read from slave: %s\n", + strerror(errno) + ); close(fd1); return -1; } std::string buf; write_number(buf, result); - if(write(fd1, buf.data(), buf.size()) != (ssize_t)buf.size()) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: failed to write to slave: %s\n", strerror(errno)); + if (write(fd1, buf.data(), buf.size()) != (ssize_t)buf.size()) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: failed to write to slave: %s\n", + strerror(errno) + ); }; close(fd1); } @@ -429,10 +493,12 @@ static int callback(int fd) static pthread_t main_thread{}; -static int master(int fd, const std::vector& args) { +static int master(int fd, const std::vector &args) { main_thread = pthread_self(); int result; - if((result = pthread_create(&queue_thread, nullptr, &queue_function, nullptr)) != 0) { + if ((result = + pthread_create(&queue_thread, nullptr, &queue_function, nullptr) + ) != 0) { errno = result; perror("pthread_create (queue function)"); return -1; @@ -440,10 +506,12 @@ static int master(int fd, const std::vector& args) { do_load_cmd("hal_lib", std::vector()); instance_count = 0; App(); // force rtapi_app to be created - if(args.size()) { + if (args.size()) { result = handle_command(args); - if(result != 0) goto out; - if(force_exit || instance_count == 0) goto out; + if (result != 0) + goto out; + if (force_exit || instance_count == 0) + goto out; } sim_rtapi_run_threads(fd, callback); out: @@ -455,114 +523,147 @@ static int master(int fd, const std::vector& args) { return result; } -static std::string -get_fifo_path() { +static std::string get_fifo_path() { std::string s; - if(getenv("RTAPI_FIFO_PATH")){ - s = getenv("RTAPI_FIFO_PATH"); - }else if(getenv("HOME")){ - s = std::string(getenv("HOME")) + "/.rtapi_fifo"; - }else{ - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo creation is unsafe.\n"); + if (getenv("RTAPI_FIFO_PATH")) { + s = getenv("RTAPI_FIFO_PATH"); + } else if (getenv("HOME")) { + s = std::string(getenv("HOME")) + "/.rtapi_fifo"; + } else { + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: RTAPI_FIFO_PATH and HOME are unset. rtapi fifo " + "creation is unsafe.\n" + ); } return s; } -static int -get_fifo_path(char *buf, size_t bufsize) { - int len; +static int get_fifo_path(char *buf, size_t bufsize) { + int len; const std::string s = get_fifo_path(); - if(s.empty()){ + if (s.empty()) { return -1; } - if(s.size() + 1 > sizeof(sockaddr_un::sun_path)) { - rtapi_print_msg(RTAPI_MSG_ERR, - "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s\n", - sizeof(sockaddr_un::sun_path), s.c_str()); - return -1; + if (s.size() + 1 > sizeof(sockaddr_un::sun_path)) { + rtapi_print_msg( + RTAPI_MSG_ERR, + "rtapi_app: rtapi fifo path is too long (arch limit %zd): %s\n", + sizeof(sockaddr_un::sun_path), + s.c_str() + ); + return -1; } - len=snprintf(buf+1, bufsize-1, "%s", s.c_str()); + len = snprintf(buf + 1, bufsize - 1, "%s", s.c_str()); return len; } int main(int argc, char **argv) { - if(getuid() == 0) { + if (getuid() == 0) { char *fallback_uid_str = getenv("RTAPI_UID"); int fallback_uid = fallback_uid_str ? atoi(fallback_uid_str) : 0; - if(fallback_uid == 0) - { - // Cppcheck cannot see EMC2_BIN_DIR when RTAPI is defined, but that - // doesn't happen in uspace. - fprintf(stderr, + if (fallback_uid == 0) { + // Cppcheck cannot see EMC2_BIN_DIR when RTAPI is defined, but that + // doesn't happen in uspace. + fprintf( + stderr, "Refusing to run as root without fallback UID specified\n" "To run under a debugger with I/O, use e.g.,\n" // cppcheck-suppress unknownMacro - " sudo env RTAPI_UID=`id -u` RTAPI_FIFO_PATH=$HOME/.rtapi_fifo gdb " EMC2_BIN_DIR "/rtapi_app\n"); + " sudo env RTAPI_UID=`id -u` " + "RTAPI_FIFO_PATH=$HOME/.rtapi_fifo gdb " EMC2_BIN_DIR + "/rtapi_app\n" + ); exit(1); } - if (setreuid(fallback_uid, 0) != 0) { perror("setreuid"); abort(); } - fprintf(stderr, + if (setreuid(fallback_uid, 0) != 0) { + perror("setreuid"); + abort(); + } + fprintf( + stderr, "Running with fallback_uid. getuid()=%d geteuid()=%d\n", - getuid(), geteuid()); + getuid(), + geteuid() + ); } ruid = getuid(); euid = geteuid(); - if (setresuid(euid, euid, ruid) != 0) { perror("setresuid"); abort(); } + if (setresuid(euid, euid, ruid) != 0) { + perror("setresuid"); + abort(); + } #ifdef __linux__ setfsuid(ruid); #endif std::vector args; - for(int i=1; i(dlsym(dll, "make")); - if(!fn){ + auto fn = reinterpret_cast(dlsym(dll, "make")); + if (!fn) { fprintf(stderr, "dlsym: %s\n", dlerror()); return nullptr; } auto result = fn(policy); - if(!result) { + if (!result) { fprintf(stderr, "dlsym: %s\n", dlerror()); return nullptr; } return result; } -static RtapiApp *makeApp() -{ - RtapiApp* app; - if(euid != 0 || harden_rt() < 0) - { - app=makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); - }else{ +static RtapiApp *makeApp() { + RtapiApp *app; + if (euid != 0 || harden_rt() < 0) { + app = makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_OTHER); + } else { WithRoot r; - if(detect_xenomai_evl()) { - app=makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); - }else if(detect_xenomai()) { - app=makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); - } else if(detect_rtai()) { - app=makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); + if (detect_xenomai_evl()) { + app = makeDllApp(EMC2_HOME "/lib/libuspace-xenomai-evl.so.0", SCHED_FIFO); + } else if (detect_xenomai()) { + app = makeDllApp(EMC2_HOME "/lib/libuspace-xenomai.so.0", SCHED_FIFO); + } else if (detect_rtai()) { + app = makeDllApp(EMC2_HOME "/lib/libuspace-rtai.so.0", SCHED_FIFO); } else { - app=makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); + app = makeDllApp(EMC2_HOME "/lib/libuspace-posix.so.0", SCHED_FIFO); } } - - if(!app){ + + if (!app) { throw std::invalid_argument("Could not load rtapi dll"); - }else{ + } else { return app; } } -RtapiApp &App() -{ +RtapiApp &App() { static RtapiApp *app = makeApp(); return *app; } @@ -790,33 +904,34 @@ RtapiApp &App() /* data for all tasks */ struct rtapi_task *task_array[MAX_TASKS]; -int rtapi_prio_highest(void) -{ +int rtapi_prio_highest(void) { return App().prio_highest(); } -int rtapi_prio_lowest(void) -{ +int rtapi_prio_lowest(void) { return App().prio_lowest(); } -int rtapi_prio_next_higher(int prio) -{ +int rtapi_prio_next_higher(int prio) { return App().prio_next_higher(prio); } -int rtapi_prio_next_lower(int prio) -{ +int rtapi_prio_next_lower(int prio) { return App().prio_next_lower(prio); } -long rtapi_clock_set_period(long nsecs) -{ +long rtapi_clock_set_period(long nsecs) { return App().clock_set_period(nsecs); } -int rtapi_task_new(void (*taskcode) (void*), void *arg, - int prio, int owner, unsigned long int stacksize, int uses_fp) { +int rtapi_task_new( + void (*taskcode)(void *), + void *arg, + int prio, + int owner, + unsigned long int stacksize, + int uses_fp +) { return App().task_new(taskcode, arg, prio, owner, stacksize, uses_fp); } @@ -824,58 +939,49 @@ int rtapi_task_delete(int id) { return App().task_delete(id); } -int rtapi_task_start(int task_id, unsigned long period_nsec) -{ +int rtapi_task_start(int task_id, unsigned long period_nsec) { int ret = App().task_start(task_id, period_nsec); - if(ret != 0) { + if (ret != 0) { errno = -ret; perror("rtapi_task_start()"); } return ret; } -int rtapi_task_pause(int task_id) -{ +int rtapi_task_pause(int task_id) { return App().task_pause(task_id); } -int rtapi_task_resume(int task_id) -{ +int rtapi_task_resume(int task_id) { return App().task_resume(task_id); } -int rtapi_task_self() -{ +int rtapi_task_self() { return App().task_self(); } -long long rtapi_task_pll_get_reference(void) -{ +long long rtapi_task_pll_get_reference(void) { return App().task_pll_get_reference(); } -int rtapi_task_pll_set_correction(long value) -{ +int rtapi_task_pll_set_correction(long value) { return App().task_pll_set_correction(value); } -void rtapi_wait(void) -{ +void rtapi_wait(void) { App().wait(); } -void rtapi_outb(unsigned char byte, unsigned int port) -{ +void rtapi_outb(unsigned char byte, unsigned int port) { App().do_outb(byte, port); } -unsigned char rtapi_inb(unsigned int port) -{ +unsigned char rtapi_inb(unsigned int port) { return App().do_inb(port); } long int simple_strtol(const char *nptr, char **endptr, int base) { - return strtol(nptr, endptr, base); + return strtol(nptr, endptr, base); } int sim_rtapi_run_threads(int fd, int (*callback)(int fd)) { @@ -887,7 +993,7 @@ long long rtapi_get_time() { } void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { - if(main_thread && pthread_self() != main_thread) { + if (main_thread && pthread_self() != main_thread) { message_t m; m.level = level; vsnprintf(m.msg, sizeof(m.msg), fmt, ap); @@ -897,25 +1003,27 @@ void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { } } -long int rtapi_delay_max() { return 10000; } +long int rtapi_delay_max() { + return 10000; +} void rtapi_delay(long ns) { - if(ns > rtapi_delay_max()) ns = rtapi_delay_max(); + if (ns > rtapi_delay_max()) + ns = rtapi_delay_max(); App().do_delay(ns); } const unsigned long ONE_SEC_IN_NS = 1000000000; -void rtapi_timespec_advance(struct timespec &result, const struct timespec &src, unsigned long nsec) -{ +void rtapi_timespec_advance( + struct timespec &result, const struct timespec &src, unsigned long nsec +) { time_t sec = src.tv_sec; - while(nsec >= ONE_SEC_IN_NS) - { + while (nsec >= ONE_SEC_IN_NS) { ++sec; nsec -= ONE_SEC_IN_NS; } nsec += src.tv_nsec; - if(nsec >= ONE_SEC_IN_NS) - { + if (nsec >= ONE_SEC_IN_NS) { ++sec; nsec -= ONE_SEC_IN_NS; } @@ -926,22 +1034,29 @@ void rtapi_timespec_advance(struct timespec &result, const struct timespec &src, int rtapi_open_as_root(const char *filename, int mode) { WITH_ROOT; int r = open(filename, mode); - if(r < 0) return -errno; + if (r < 0) + return -errno; return r; } -int rtapi_spawn_as_root(pid_t *pid, const char *path, +int rtapi_spawn_as_root( + pid_t *pid, + const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) -{ + char *const argv[], + char *const envp[] +) { return posix_spawn(pid, path, file_actions, attrp, argv, envp); } -int rtapi_spawnp_as_root(pid_t *pid, const char *path, +int rtapi_spawnp_as_root( + pid_t *pid, + const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, - char *const argv[], char *const envp[]) -{ + char *const argv[], + char *const envp[] +) { return posix_spawnp(pid, path, file_actions, attrp, argv, envp); } diff --git a/src/rtapi/uspace_xenomai.cc b/src/rtapi/uspace_xenomai.cc index 4c1c2d485b5..5f0c5139472 100644 --- a/src/rtapi/uspace_xenomai.cc +++ b/src/rtapi/uspace_xenomai.cc @@ -18,7 +18,7 @@ #include "rtapi.h" #include "uspace_rtapi_app.hh" #include -#include +#include #include #include #include @@ -26,10 +26,10 @@ #include #endif -namespace -{ +namespace { struct XenomaiTask : rtapi_task { - XenomaiTask() : rtapi_task{}, cancel{}, thr{} {} + XenomaiTask() : rtapi_task{}, cancel{}, thr{} { + } std::atomic_int cancel; pthread_t thr; }; @@ -46,7 +46,8 @@ struct XenomaiApp : RtapiApp { int task_delete(int id) { auto task = ::rtapi_get_task(id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->cancel = 1; pthread_join(task->thr, nullptr); @@ -58,7 +59,8 @@ struct XenomaiApp : RtapiApp { int task_start(int task_id, unsigned long period_nsec) { auto task = ::rtapi_get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->period = period_nsec; struct sched_param param; @@ -69,39 +71,43 @@ struct XenomaiApp : RtapiApp { task->pll_correction_limit = period_nsec / 100; task->pll_correction = 0; - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); + int nprocs = sysconf(_SC_NPROCESSORS_ONLN); pthread_attr_t attr; int ret; - if((ret = pthread_attr_init(&attr)) != 0) + if ((ret = pthread_attr_init(&attr)) != 0) return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + if ((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + if ((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) return -ret; - if(nprocs > 1){ + if (nprocs > 1) { const static int rt_cpu_number = find_rt_cpu_number(); - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); - if(rt_cpu_number != -1) { + rtapi_print_msg( + RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number + ); + if (rt_cpu_number != -1) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(rt_cpu_number, &cpuset); - if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) + if ((ret = pthread_attr_setaffinity_np( + &attr, sizeof(cpuset), &cpuset + )) != 0) return -ret; } } - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + if ((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) return -ret; return 0; } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); struct timespec now; @@ -112,9 +118,11 @@ struct XenomaiApp : RtapiApp { // "xenomai: watchdog triggered" and rtapi_app was killed. // // encountered on: 3.18.20-xenomai-2.6.5 with a 2-thread SMP system - rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); + rtapi_timespec_advance( + task->nextstart, now, task->period + task->pll_correction + ); - (task->taskcode) (task->arg); + (task->taskcode)(task->arg); rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); return nullptr; @@ -131,16 +139,22 @@ struct XenomaiApp : RtapiApp { } long long task_pll_get_reference(void) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return 0; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return 0; return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; } int task_pll_set_correction(long value) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - if (value > task->pll_correction_limit) value = task->pll_correction_limit; - if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; + if (value > task->pll_correction_limit) + value = task->pll_correction_limit; + if (value < -(task->pll_correction_limit)) + value = -(task->pll_correction_limit); task->pll_correction = value; return 0; } @@ -148,21 +162,25 @@ struct XenomaiApp : RtapiApp { void wait() { int task_id = task_self(); auto task = ::rtapi_get_task(task_id); - if(task->cancel) { + if (task->cancel) { pthread_exit(nullptr); } - rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); + rtapi_timespec_advance( + task->nextstart, + task->nextstart, + task->period + task->pll_correction + ); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if(rtapi_timespec_less(task->nextstart, now)) - { - if(policy == SCHED_FIFO) + if (rtapi_timespec_less(task->nextstart, now)) { + if (policy == SCHED_FIFO) unexpected_realtime_delay(task); - } - else - { - int res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr); - if(res < 0) perror("clock_nanosleep"); + } else { + int res = clock_nanosleep( + CLOCK_MONOTONIC, TIMER_ABSTIME, &task->nextstart, nullptr + ); + if (res < 0) + perror("clock_nanosleep"); } } @@ -185,13 +203,17 @@ struct XenomaiApp : RtapiApp { } int run_threads(int fd, int (*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } + while (callback(fd)) { + /* nothing */ + } return 0; } int task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; return task->id; } @@ -215,14 +237,16 @@ struct XenomaiApp : RtapiApp { pthread_once_t XenomaiApp::key_once; pthread_key_t XenomaiApp::key; -} +} // namespace extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - if(policy != SCHED_FIFO){ + if (policy != SCHED_FIFO) { throw std::invalid_argument("Only SCHED_FIFO allowed"); } - rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI (posix-skin) realtime\n"); + rtapi_print_msg( + RTAPI_MSG_ERR, "Note: Using XENOMAI (posix-skin) realtime\n" + ); return new XenomaiApp(); } diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index 4ed37933504..a19d57b39ec 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -37,10 +37,10 @@ #include #endif -namespace -{ +namespace { struct EvlTask : rtapi_task { - EvlTask() : rtapi_task{}, cancel{}, thr{} {} + EvlTask() : rtapi_task{}, cancel{}, thr{} { + } std::atomic_int cancel; pthread_t thr; }; @@ -57,7 +57,8 @@ struct EvlApp : RtapiApp { int task_delete(int id) { auto task = ::rtapi_get_task(id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->cancel = 1; pthread_join(task->thr, nullptr); @@ -69,7 +70,8 @@ struct EvlApp : RtapiApp { int task_start(int task_id, unsigned long period_nsec) { auto task = ::rtapi_get_task(task_id); - if(!task) return -EINVAL; + if (!task) + return -EINVAL; task->period = period_nsec; struct sched_param param; @@ -80,39 +82,43 @@ struct EvlApp : RtapiApp { task->pll_correction_limit = period_nsec / 100; task->pll_correction = 0; - int nprocs = sysconf( _SC_NPROCESSORS_ONLN ); + int nprocs = sysconf(_SC_NPROCESSORS_ONLN); pthread_attr_t attr; int ret; - if((ret = pthread_attr_init(&attr)) != 0) + if ((ret = pthread_attr_init(&attr)) != 0) return -ret; - if((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) + if ((ret = pthread_attr_setstacksize(&attr, task->stacksize)) != 0) return -ret; - if((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) + if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) return -ret; - if((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) + if ((ret = pthread_attr_setschedparam(&attr, ¶m)) != 0) return -ret; - if((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) + if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) return -ret; - if(nprocs > 1){ + if (nprocs > 1) { const static int rt_cpu_number = find_rt_cpu_number(); - rtapi_print_msg(RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number); - if(rt_cpu_number != -1) { + rtapi_print_msg( + RTAPI_MSG_INFO, "rt_cpu_number = %i\n", rt_cpu_number + ); + if (rt_cpu_number != -1) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(rt_cpu_number, &cpuset); - if((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset)) != 0) + if ((ret = pthread_attr_setaffinity_np( + &attr, sizeof(cpuset), &cpuset + )) != 0) return -ret; } } - if((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) + if ((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast(task))) != 0) return -ret; return 0; } static void *wrapper(void *arg) { - auto task = reinterpret_cast(arg); + auto task = reinterpret_cast(arg); pthread_setspecific(key, arg); { @@ -120,8 +126,10 @@ struct EvlApp : RtapiApp { /* Attach to the core. */ rtapi_print("linuxcnc-task:%d\n", gettid()); int tfd = evl_attach_self("linuxcnc-thread:%d", gettid()); - if (tfd < 0){ - rtapi_print("evl_attach_self() failed ret %i errno %i\n", tfd, errno); + if (tfd < 0) { + rtapi_print( + "evl_attach_self() failed ret %i errno %i\n", tfd, errno + ); } } @@ -133,9 +141,11 @@ struct EvlApp : RtapiApp { // "xenomai: watchdog triggered" and rtapi_app was killed. // // encountered on: 3.18.20-xenomai-2.6.5 with a 2-thread SMP system - rtapi_timespec_advance(task->nextstart, now, task->period + task->pll_correction); + rtapi_timespec_advance( + task->nextstart, now, task->period + task->pll_correction + ); - (task->taskcode) (task->arg); + (task->taskcode)(task->arg); rtapi_print("ERROR: reached end of wrapper for task %d\n", task->id); return nullptr; @@ -152,16 +162,22 @@ struct EvlApp : RtapiApp { } long long task_pll_get_reference(void) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return 0; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return 0; return task->nextstart.tv_sec * 1000000000LL + task->nextstart.tv_nsec; } int task_pll_set_correction(long value) { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; - if (value > task->pll_correction_limit) value = task->pll_correction_limit; - if (value < -(task->pll_correction_limit)) value = -(task->pll_correction_limit); + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; + if (value > task->pll_correction_limit) + value = task->pll_correction_limit; + if (value < -(task->pll_correction_limit)) + value = -(task->pll_correction_limit); task->pll_correction = value; return 0; } @@ -169,21 +185,23 @@ struct EvlApp : RtapiApp { void wait() { int task_id = task_self(); auto task = ::rtapi_get_task(task_id); - if(task->cancel) { + if (task->cancel) { pthread_exit(nullptr); } - rtapi_timespec_advance(task->nextstart, task->nextstart, task->period + task->pll_correction); + rtapi_timespec_advance( + task->nextstart, + task->nextstart, + task->period + task->pll_correction + ); struct timespec now; evl_read_clock(EVL_CLOCK_MONOTONIC, &now); - if(rtapi_timespec_less(task->nextstart, now)) - { - if(policy == SCHED_FIFO) + if (rtapi_timespec_less(task->nextstart, now)) { + if (policy == SCHED_FIFO) unexpected_realtime_delay(task); - } - else - { + } else { int res = evl_sleep_until(EVL_CLOCK_MONOTONIC, &task->nextstart); - if(res < 0) perror("evl_sleep_until"); + if (res < 0) + perror("evl_sleep_until"); } } @@ -206,13 +224,17 @@ struct EvlApp : RtapiApp { } int run_threads(int fd, int (*callback)(int fd)) { - while(callback(fd)) { /* nothing */ } + while (callback(fd)) { + /* nothing */ + } return 0; } int task_self() { - struct rtapi_task *task = reinterpret_cast(pthread_getspecific(key)); - if(!task) return -EINVAL; + struct rtapi_task *task = + reinterpret_cast(pthread_getspecific(key)); + if (!task) + return -EINVAL; return task->id; } @@ -238,12 +260,12 @@ struct EvlApp : RtapiApp { pthread_once_t EvlApp::key_once; pthread_key_t EvlApp::key; -} +} // namespace extern "C" RtapiApp *make(int policy); RtapiApp *make(int policy) { - if(policy != SCHED_FIFO){ + if (policy != SCHED_FIFO) { throw std::invalid_argument("Only SCHED_FIFO allowed"); } rtapi_print_msg(RTAPI_MSG_ERR, "Note: Using XENOMAI4 EVL realtime\n");