Skip to content
30 changes: 20 additions & 10 deletions src/rtapi/Submakefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ $(patsubst ./rtapi/%,../include/%,$(RTAPIINCS)): ../include/%.h: ./rtapi/%.h
ifeq ($(BUILD_SYS),uspace)

RTAPI_APP_SRCS := \
rtapi/uspace_rtapi_main.cc \
rtapi/uspace_rtapi_app.cc \
rtapi/uspace_rtapi_parport.cc \
rtapi/uspace_rtapi_string.c \
Expand All @@ -43,39 +44,48 @@ $(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

USPACE_POSIX_SRCS := rtapi/uspace_posix.cc
USERSRCS += $(USPACE_POSIX_SRCS)
$(call TOOBJSDEPS, $(USPACE_POSIX_SRCS)): EXTRAFLAGS += -pthread -fPIC
../lib/liblinuxcnc-uspace-posix.so.0: $(call TOOBJS, $(USPACE_POSIX_SRCS))
$(ECHO) Linking $(notdir $@)
$(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ -Wl,-soname,$(notdir $@)
TARGETS += ../lib/liblinuxcnc-uspace-posix.so.0
TARGETS += ../lib/liblinuxcnc-uspace-posix.so

ifeq ($(CONFIG_USPACE_RTAI),y)
USPACE_RTAI_SRCS := rtapi/uspace_rtai.cc
USERSRCS += $(USPACE_RTAI_SRCS)
$(call TOOBJSDEPS, $(USPACE_RTAI_SRCS)): EXTRAFLAGS += -pthread -fPIC $(filter-out -Wstrict-prototypes,$(RTAI_LXRT_CFLAGS))
../lib/libuspace-rtai.so.0: $(call TOOBJS, $(USPACE_RTAI_SRCS))
../lib/liblinuxcnc-uspace-rtai.so.0: $(call TOOBJS, $(USPACE_RTAI_SRCS))
$(ECHO) Linking $(notdir $@)
$(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ $(RTAI_LXRT_LDFLAGS) -Wl,-soname,$(notdir $@)
TARGETS += ../lib/libuspace-rtai.so.0
TARGETS += ../lib/libuspace-rtai.so
TARGETS += ../lib/liblinuxcnc-uspace-rtai.so.0
TARGETS += ../lib/liblinuxcnc-uspace-rtai.so
endif

ifeq ($(CONFIG_USPACE_XENOMAI),y)
USPACE_XENOMAI_SRCS := rtapi/uspace_xenomai.cc
USERSRCS += $(USPACE_XENOMAI_SRCS)
$(call TOOBJSDEPS, $(USPACE_XENOMAI_SRCS)): EXTRAFLAGS += -fPIC $(XENOMAI_CFLAGS)
../lib/libuspace-xenomai.so.0: $(call TOOBJS, $(USPACE_XENOMAI_SRCS))
../lib/liblinuxcnc-uspace-xenomai.so.0: $(call TOOBJS, $(USPACE_XENOMAI_SRCS))
$(ECHO) Linking $(notdir $@)
$(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ $(XENOMAI_LDFLAGS) -Wl,-soname,$(notdir $@)
TARGETS += ../lib/libuspace-xenomai.so.0
TARGETS += ../lib/libuspace-xenomai.so
TARGETS += ../lib/liblinuxcnc-uspace-xenomai.so.0
TARGETS += ../lib/liblinuxcnc-uspace-xenomai.so
endif

ifeq ($(CONFIG_USPACE_XENOMAI_EVL),y)
USPACE_XENOMAI_EVL_SRCS := rtapi/uspace_xenomai_evl.cc
USERSRCS += $(USPACE_XENOMAI_EVL_SRCS)
$(call TOOBJSDEPS, $(USPACE_XENOMAI_EVL_SRCS)): EXTRAFLAGS += -fPIC $(XENOMAI_EVL_CFLAGS)
../lib/libuspace-xenomai-evl.so.0: $(call TOOBJS, $(USPACE_XENOMAI_EVL_SRCS))
../lib/liblinuxcnc-uspace-xenomai-evl.so.0: $(call TOOBJS, $(USPACE_XENOMAI_EVL_SRCS))
$(ECHO) Linking $(notdir $@)
$(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ $(XENOMAI_EVL_LDFLAGS) -Wl,-soname,$(notdir $@)
TARGETS += ../lib/libuspace-xenomai-evl.so.0
TARGETS += ../lib/libuspace-xenomai-evl.so
TARGETS += ../lib/liblinuxcnc-uspace-xenomai-evl.so.0
TARGETS += ../lib/liblinuxcnc-uspace-xenomai-evl.so
endif
2 changes: 1 addition & 1 deletion src/rtapi/rtapi_pci.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include <rtapi.h>
#include <rtapi_pci.h>
#include <rtapi_firmware.h>
#include "rtapi_uspace.hh"
#include "uspace_rtapi_app.hh"

#include <dirent.h>
#include <errno.h>
Expand Down
5 changes: 3 additions & 2 deletions src/rtapi/uspace_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <string.h>
#include <unistd.h>
Expand All @@ -39,7 +40,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_app.hh"
#endif

typedef struct {
Expand Down Expand Up @@ -115,7 +116,7 @@ int rtapi_shmem_new(int key, int module_id, unsigned long int size)
*/
/* ensure the segment is owned by user, not root */
if(geteuid() == 0) {
stat.shm_perm.uid = ruid;
stat.shm_perm.uid = WithRoot::getRuid();
res = shmctl(shmem->id, IPC_SET, &stat);
if(res < 0) perror("shmctl IPC_SET");
}
Expand Down
253 changes: 253 additions & 0 deletions src/rtapi/uspace_posix.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/* Copyright (C) 2006-2014 Jeff Epler <jepler@unpythonic.net>
*
* 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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdexcept>
#ifdef HAVE_SYS_IO_H
#include <sys/io.h>
#endif

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) {
pthread_once(&key_once, init_key);
if (do_thread_lock) {
pthread_once(&lock_once, init_lock);
}
}

struct rtapi_task *do_task_new() {
return new PosixTask;
}

int task_delete(int id) {
auto task = ::rtapi_get_task<PosixTask>(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 task_start(int task_id, unsigned long period_nsec) {
auto task = ::rtapi_get_task<PosixTask>(task_id);
if (!task)
return -EINVAL;

task->period = period_nsec;
struct sched_param param;
memset(&param, 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, &param)) != 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 (do_thread_lock)
pthread_mutex_lock(&thread_lock);
if ((ret = pthread_create(&task->thr, &attr, &wrapper, reinterpret_cast<void *>(task))) != 0)
return -ret;

return 0;
}

static void *wrapper(void *arg) {
auto task = reinterpret_cast<PosixTask *>(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);

/* 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;
}

int task_pause(int task_id) {
(void)task_id;
return -ENOSYS;
}

int task_resume(int task_id) {
(void)task_id;
return -ENOSYS;
}

long long task_pll_get_reference(void) {
struct rtapi_task *task = reinterpret_cast<rtapi_task *>(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<rtapi_task *>(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)
pthread_mutex_unlock(&thread_lock);
pthread_testcancel();
struct rtapi_task *task = reinterpret_cast<rtapi_task *>(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)
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);
}

unsigned char do_inb(unsigned int port) {
#ifdef HAVE_SYS_IO_H
return inb(port);
#else
(void)port;
return 0;
#endif
}

void do_outb(unsigned char val, unsigned int port) {
#ifdef HAVE_SYS_IO_H
return outb(val, port);
#else
(void)val;
(void)port;
#endif
}

int run_threads(int fd, int (*callback)(int fd)) {
while (callback(fd)) {
/* nothing */
}
return 0;
}

int task_self() {
struct rtapi_task *task = reinterpret_cast<rtapi_task *>(pthread_getspecific(key));
if (!task)
return -EINVAL;
return task->id;
}

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() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
}

void do_delay(long ns) {
struct timespec ts = {0, ns};
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr);
}
};

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;

} // namespace

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 PosixApp(policy);
}
Loading
Loading