Skip to content

Commit d28f74f

Browse files
committed
rtapi_app: Make realtime checks relaiable
The same checks are performed always the same now. If something is not properly checked, makeApp() fill fail instead of just chosing a different RT implementation by itsself. New function: rtapi_realtime_type_t rtapi_get_realtime_type(void)
1 parent a86ea85 commit d28f74f

4 files changed

Lines changed: 250 additions & 173 deletions

File tree

src/rtapi/rtai_rtapi.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,8 +1688,9 @@ unsigned char rtapi_inb(unsigned int port)
16881688
return inb(port);
16891689
}
16901690

1691-
int rtapi_is_realtime() { return 1; }
1692-
int rtapi_is_kernelspace() { return 1; }
1691+
int rtapi_is_realtime(void) { return 1; }
1692+
rtapi_realtime_type_t rtapi_get_realtime_type(void){ return REALTIME_TYPE_RTAI; }
1693+
int rtapi_is_kernelspace(void) { return 1; }
16931694

16941695
/* starting with kernel 2.6, symbols that are used by other modules
16951696
_must_ be explicitly exported. 2.4 and earlier kernels exported
@@ -1746,4 +1747,5 @@ EXPORT_SYMBOL(rtapi_disable_interrupt);
17461747
EXPORT_SYMBOL(rtapi_outb);
17471748
EXPORT_SYMBOL(rtapi_inb);
17481749
EXPORT_SYMBOL(rtapi_is_realtime);
1750+
EXPORT_SYMBOL(rtapi_get_realtime_type);
17491751
EXPORT_SYMBOL(rtapi_is_kernelspace);

src/rtapi/rtapi.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,23 @@ int rtapi_spawnp_as_root(pid_t *pid, const char *path,
985985
#endif
986986

987987
extern int rtapi_is_kernelspace(void);
988+
989+
//You can use type > REALTIME_TYPE_NONE to check if you have realtime at all
990+
typedef enum{
991+
REALTIME_TYPE_UNINITIALIZED = -1, //Realtime not running, type unknown
992+
REALTIME_TYPE_NONE = 0, //No realtime available
993+
REALTIME_TYPE_RTAI = 1,
994+
REALTIME_TYPE_PREEMPT_DYNAMIC = 2,
995+
REALTIME_TYPE_PREEMPT_RT = 3,
996+
REALTIME_TYPE_LXRT = 4,
997+
REALTIME_TYPE_XENOMAI = 5,
998+
REALTIME_TYPE_XENOMAI_EVL = 6,
999+
} rtapi_realtime_type_t;
1000+
9881001
extern int rtapi_is_realtime(void);
1002+
#ifdef RTAPI
1003+
extern rtapi_realtime_type_t rtapi_get_realtime_type(void);
1004+
#endif
9891005

9901006
int rtapi_open_as_root(const char *filename, int mode);
9911007

src/rtapi/uspace_common.h

Lines changed: 5 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -340,131 +340,15 @@ int rtapi_exit(int module_id)
340340

341341
int rtapi_is_kernelspace() { return 0; }
342342

343-
#ifdef __linux__
344-
// detect_preempt_rt() inspects uname for the PREEMPT_RT marker. Used only
345-
// for diagnostic warning at startup; callers must not gate behavior on
346-
// the kernel string, since SCHED_FIFO on a PREEMPT_DYNAMIC kernel is still
347-
// useful (better than SCHED_OTHER, worse than PREEMPT_RT).
348-
static inline int detect_preempt_rt() {
349-
struct utsname u;
350-
if(uname(&u) < 0) return 0;
351-
return strcasestr(u.version, "PREEMPT RT") != 0
352-
|| strcasestr(u.version, "PREEMPT_RT") != 0;
353-
}
354-
#else
355-
static inline int detect_preempt_rt() {
356-
return 0;
357-
}
358-
#endif
359-
360-
// FIXME: detect_rtai/detect_xenomai/detect_xenomai_evl currently gate on
361-
// setuid because the RTAI/Xenomai backends still need root for iopl()
362-
// (RTAI) or RTDM device access (Xenomai/EVL). Long-term these should
363-
// probe the actual capability the way can_set_sched_fifo() does, paired
364-
// with udev rules + a 'xenomai'/'evl' group; @hdiethelm has a follow-up
365-
// planned. Until then, an unprivileged user on a Xenomai kernel cannot
366-
// claim the Xenomai backend, and falls back to the SCHED_FIFO probe.
367-
static inline int has_setuid_root() {
368-
return geteuid() == 0;
369-
}
370-
371-
#ifdef USPACE_RTAI
372-
static int detect_rtai() {
373-
if(!has_setuid_root()) return 0;
374-
struct utsname u;
375-
uname(&u);
376-
return strcasestr (u.release, "-rtai") != 0;
377-
}
378-
#else
379-
static int detect_rtai() {
380-
return 0;
381-
}
382-
#endif
383-
#ifdef USPACE_XENOMAI
384-
static int detect_xenomai() {
385-
if(!has_setuid_root()) return 0;
386-
struct stat sb;
387-
//Running xenomai has /proc/xenomai
388-
return stat("/proc/xenomai", &sb) == 0;
389-
}
390-
#else
391-
static int detect_xenomai() {
392-
return 0;
393-
}
394-
#endif
395-
#ifdef USPACE_XENOMAI_EVL
396-
static int detect_xenomai_evl() {
397-
if(!has_setuid_root()) return 0;
398-
struct stat sb;
399-
//Running xenomai evl has /dev/evl but no /proc/xenomai
400-
return stat("/dev/evl", &sb) == 0;
401-
}
402-
#else
403-
static int detect_xenomai_evl() {
343+
#ifndef RTAPI
344+
//For RTAPI, this function is implemented in uspace_rtapi_main.cc
345+
//For user components, keep it in for now with a warning to avoid link issues
346+
int rtapi_is_realtime() {
347+
rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_is_realtime() only allowed in real time context");
404348
return 0;
405349
}
406350
#endif
407351

408-
// errno from the most recent sched_setscheduler(SCHED_FIFO) probe. Zero
409-
// when the probe succeeded or has not run yet. Read via
410-
// rtapi_sched_fifo_errno() from diagnostic code.
411-
static int rtapi_sched_fifo_last_errno = 0;
412-
413-
// Success-probe for realtime scheduling: briefly try to set SCHED_FIFO on
414-
// the calling thread and restore the previous policy. Succeeds when the
415-
// process holds CAP_SYS_NICE (file caps or setuid root) or has a matching
416-
// RLIMIT_RTPRIO. Works on any kernel, so the probe also covers the
417-
// PREEMPT_RT-vs-stock distinction implicitly: if we can actually get
418-
// SCHED_FIFO, the platform can deliver realtime, regardless of how.
419-
static int can_set_sched_fifo(void) {
420-
struct sched_param old_param, probe_param;
421-
int old_policy = sched_getscheduler(0);
422-
if(old_policy < 0) {
423-
rtapi_sched_fifo_last_errno = errno;
424-
return 0;
425-
}
426-
if(sched_getparam(0, &old_param) < 0) {
427-
rtapi_sched_fifo_last_errno = errno;
428-
return 0;
429-
}
430-
431-
memset(&probe_param, 0, sizeof(probe_param));
432-
probe_param.sched_priority = sched_get_priority_min(SCHED_FIFO);
433-
if(sched_setscheduler(0, SCHED_FIFO, &probe_param) < 0) {
434-
rtapi_sched_fifo_last_errno = errno;
435-
return 0;
436-
}
437-
438-
// Best-effort restore; if this fails we are still on SCHED_FIFO at
439-
// minimum priority, which is no worse than where we started.
440-
sched_setscheduler(0, old_policy, &old_param);
441-
rtapi_sched_fifo_last_errno = 0;
442-
return 1;
443-
}
444-
445-
static inline int rtapi_sched_fifo_errno(void) { return rtapi_sched_fifo_last_errno; }
446-
447-
// rtapi_is_realtime() reports whether this process can actually run
448-
// realtime code. This matches the convention used by JACK, PipeWire,
449-
// rtkit, Xenomai, and Klipper: surface the observed capability, not
450-
// kernel metadata. The old setuid-root stat check has been removed; it
451-
// stat()ed EMC2_BIN_DIR/rtapi_app rather than the running binary (breaking
452-
// wrapper-based installs like NixOS /run/wrappers) and silently masked
453-
// LINUXCNC_FORCE_REALTIME (see issue #3928).
454-
int rtapi_is_realtime() {
455-
static int cached = -1;
456-
if(cached != -1) return cached;
457-
458-
const char *force = getenv("LINUXCNC_FORCE_REALTIME");
459-
if(force != NULL && atoi(force) != 0)
460-
return (cached = 1);
461-
462-
if(detect_rtai() || detect_xenomai() || detect_xenomai_evl())
463-
return (cached = 1);
464-
465-
return (cached = can_set_sched_fifo());
466-
}
467-
468352
/* Like clock_nanosleep, except that an optional 'estimate of now' parameter may
469353
* optionally be passed in. This is a very slight optimization for platforms
470354
* where rtapi_clock_nanosleep is implemented in terms of nanosleep, because it

0 commit comments

Comments
 (0)