Skip to content

Update to RTEMS 6 with Libbsd and Legacy net support - #61

Open
kiwichris wants to merge 1 commit into
epics-modules:masterfrom
kiwichris:rtems-6-legacy-libbsd
Open

kiwichris wants to merge 1 commit into
epics-modules:masterfrom
kiwichris:rtems-6-legacy-libbsd

Conversation

@kiwichris

@kiwichris kiwichris commented Aug 7, 2024 •

Copy link
Copy Markdown

This pull request adds support for RTEMS 6 for the legacy network and libbsd.

It needs a current build of RTEMS 6 and tools.

@kiwichris

Copy link
Copy Markdown
Author

I have reviewed the CI failures and I do not think they are related to the changes I have made.

@anjohnson

Copy link
Copy Markdown
Member

I just pushed a change to the master branch here which cleaned up some compiler warnings, and the subsequent CI build jobs for RTEMS 4.9 and 4.10 both succeeded. I also re-triggered those CI builds for this PR which unfortunately both failed again, so some code change inside this PR must have caused the failures.

I don't care about the pre-commit check failure, just the ability to build this module against RTEMS 4.9 and 4.10. Note that the EPICS Base 7.0 version that this CI is using at the moment doesn't include your RTEMS-6 PRs, and we expect future releases of this module to continue to build against older EPICS versions anyway — the CI jobs that build it for Linux against both 3.14 and 3.15 should hint at that.

@kiwichris
kiwichris force-pushed the rtems-6-legacy-libbsd branch from 29a2d9e to 1a65c02 Compare August 25, 2024 03:34
@kiwichris

kiwichris commented Aug 25, 2024 •

Copy link
Copy Markdown
Author

@anjohnson I have resolved the issue with 4.10 and I assume 4.9. It seems the define _RTEMS_VIOLATE_KERNEL_VISIBILITY__ effects what is included by rtems.h and in this case wkspace.h was not being included. I have moved the include order to clean this up.

@hjunkes

hjunkes commented Aug 26, 2024

Copy link
Copy Markdown

Unfortunately, when I try to compile (MVME6100 legacy RTEMS6) I get this:
...
/include -I/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-support/StreamDevice/include -c ../devIocStatsWaveform.c
In file included from ../os/RTEMS/devIocStatsOSD.h:84,
from ../devIocStats.h:52,
from ../devIocStatsWaveform.c:76:
/home/rtems/MVME6100_6_legacy_INST/rtems/6/powerpc-rtems6/include/stdlib.h:260:21: error: macro "random" passed 1 arguments, but takes just 0
260 | long random (void);
| ^
In file included from /home/rtems/MVME6100_6_legacy_INST/rtems/6/powerpc-rtems6/beatnik/lib/include/sys/malloc.h:39,
from /home/rtems/MVME6100_6_legacy_INST/rtems/6/powerpc-rtems6/beatnik/lib/include/sys/mbuf.h:38,
from ../os/RTEMS/devIocStatsOSD.h:65:
/home/rtems/MVME6100_6_legacy_INST/rtems/6/powerpc-rtems6/beatnik/lib/include/rtems/rtems_bsdnet_internal.h:63: note: macro "random" defined here
63 | #define random() rtems_bsdnet_random()
|
make[2]: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_BUILD:259: devIocStatsWaveform.o] Error 1
make[2]: Leaving directory '/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-support/iocStats/devIocStats/O.RTEMS-beatnik'
make[1]: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_ARCHS:58: install.RTEMS-beatnik] Error 2
make[1]: Leaving directory '/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-support/iocStats/devIocStats'
make: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_DIRS:85: devIocStats.install] Error 2

@hjunkes

hjunkes commented Aug 26, 2024

Copy link
Copy Markdown

e.g. in devIocStats/os/RTEMS/devIocStatsOSD.h
RTEMS_MAJOR, RTEMS_MINOR, RTEMS_REVISION
are not defined. Is that why the version status queries do not work?
defined in 6/powerpc-rtems6/beatnik/lib/include/rtems/score/cpuopts.h
So rtems.h must be included before the __RTEMS_XXX macros can be used?

But then I get this error:
support/StreamDevice/include -c ../os/RTEMS/osdFdUsage.c
../os/RTEMS/osdFdUsage.c: In function 'devIocStatsGetFDUsage':
../os/RTEMS/osdFdUsage.c:49:16: error: implicit declaration of function 'rtems_libio_count_open_iops' [-Werror=implicit-function-declaration]
49 | pval->used = rtems_libio_count_open_iops();
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_BUILD:259: osdFdUsage.o] Error 1
make[2]: Leaving directory '/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-support/iocStats/devIocStats/O.RTEMS-beatnik'
make[1]: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_ARCHS:58: install.RTEMS-beatnik] Error 2
make[1]: Leaving directory '/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-support/iocStats/devIocStats'
make: *** [/home/rtems/MVME6100_6_legacy_INST/EPICS/epics-base/configure/RULES_DIRS:85: devIocStats.install] Error 2

@hjunkes

hjunkes commented Aug 26, 2024

Copy link
Copy Markdown

ok, found this:
https://gitlab.rtems.org/rtems/rtos/rtems/-/merge_requests/117#note_109499
Will update my RTEMS ...

@kiwichris

Copy link
Copy Markdown
Author

The rtems.h needs to be after #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ for the build to complete for the pre RTEMS 6 versions. I could have broken it for 6 making the change?

@hjunkes

hjunkes commented Aug 27, 2024

Copy link
Copy Markdown

Works with the current RTEMS6 master(main). rtems_libio_count_open_iops is defined there.

@kiwichris

Copy link
Copy Markdown
Author

Works with the current RTEMS6 master(main). rtems_libio_count_open_iops is defined there.

Thanks for confirming this. I do not know what the approval for workflows means.

@anjohnson

Copy link
Copy Markdown
Member

@simon-ess will have to speak up if he cares about the clang-format failure (those checks seem rather obnoxious to me), but this looks good for the RTEMS builds, thanks!

@simon-ess

Copy link
Copy Markdown
Contributor

I would prefer that the formatting check pass; otherwise it should be disabled, since we would then be just ignoring a failing test.

We could discuss exactly what the best formatting is, but I don't like the idea of letting it fail.

@kiwichris

Copy link
Copy Markdown
Author

I would prefer that the formatting check pass; otherwise it should be disabled, since we would then be just ignoring a failing test.

I had no idea there was a coding standard. I am happy to take a look.

We could discuss exactly what the best formatting is, but I don't like the idea of letting it fail.

This makes sense. I can fix it.

@kiwichris
kiwichris force-pushed the rtems-6-legacy-libbsd branch from 1a65c02 to a5ccfbe Compare September 5, 2024 05:37
@kiwichris

Copy link
Copy Markdown
Author

I have pushed changes to fix the formatting. I did the changes manually from the diff in the CI log.

Is this OK?

@hjunkes

hjunkes commented Oct 5, 2024

Copy link
Copy Markdown

I found a problem when I wanted to use iocStats for beaglebone black (arm).
I had to change the following:
diff --git a/devIocStats/os/RTEMS/osdClustInfo.c b/devIocStats/os/RTEMS/osdClustInfo.c
index 1e07474..e1c74b7 100644
--- a/devIocStats/os/RTEMS/osdClustInfo.c
+++ b/devIocStats/os/RTEMS/osdClustInfo.c
@@ -110,6 +110,8 @@ int devIocStatsGetClusterInfo(int pool, clustInfo *pval) {
return 0;
}

+int devIocStatsGetClusterUsage(int pool, int pval) { return -1; }
+
#else /
RTEMS_LIBBSD_STACK */

/* This would otherwise need _KERNEL to be defined... */

@kiwichris

Copy link
Copy Markdown
Author

@hjunkes thanks for the LibBSD fix. I have added it to the PR with a minor change. The pval argument is int*.

I have build iocStats against RTEMS 6.1 and the MVME2700 BSP and LibBSD.

@kiwichris

Copy link
Copy Markdown
Author

Ping

@hjunkes

hjunkes commented Jan 25, 2026 •

Copy link
Copy Markdown

Sorry for the long delay. I am currently trying RTEMS 7 with rtems-libbsd and EPICS R7.0.9.1-DEV with RTEMS-xilinx_zynq_a9_qemu. Unfortunately, I get a core dump on iocInit if devIocStats.dbd is included.
I need to investigate this.

Starting iocInit
############################################################################
## EPICS R7.0.9.1-DEV
## Rev. R7.0.9-228-gc556e21df5decc3def9f-dirty
## Rev. Date Git: 2025-12-08 09:35:25 +0100
############################################################################

*** FATAL ***
fatal source: 9 (RTEMS_FATAL_SOURCE_EXCEPTION)

R0   = 0x00000000 R8  = 0x00000000
R1   = 0x00000000 R9  = 0x0083a578
R2   = 0x00000000 R10 = 0x0083a50c
R3   = 0x00000000 R11 = 0x00000065
R4   = 0x0faaec00 R12 = 0x00000000
R5   = 0x00892000 SP  = 0x00891fa0
R6   = 0x013da420 LR  = 0x002e02a7
R7   = 0x00000000 PC  = 0x0028a408
CPSR = 0x40010173 VEC = 0x00000004
FPEXC = 0x40000000
FPSCR = 0x80000010
D00 = 0x0000000000000047
D01 = 0x0000000000000000
D02 = 0x0000003f00000040
D03 = 0x0000003d0000003e
D04 = 0x0000006500000066
D05 = 0x0000006300000064
D06 = 0x8040201008040201
D07 = 0x000dca8500100000
D08 = 0x0000000000000000
D09 = 0x0000000000000000
D10 = 0x0000000000000000
D11 = 0x0000000000000000
D12 = 0x0000000000000000
D13 = 0x0000000000000000
D14 = 0x0000000000000000
D15 = 0x0000000000000000
D16 = 0x0000000000000000
D17 = 0x0000000000000000
D18 = 0x412b950a00000000
D19 = 0x3fecec093d966384
D20 = 0x0000000000000000
D21 = 0x0000000000000000
D22 = 0x0000005a0000002d
D23 = 0x0000001e0000003c
D24 = 0x000000140000003c
D25 = 0x0000003c0000000a
D26 = 0x0000000400000004
D27 = 0x0000000400000004
D28 = 0x0070156000701210
D29 = 0x007014780070122c
D30 = 0x007003d800701658
D31 = 0x0070157c00701248
RTEMS version: 7.0.0.8f0f451c7aef41953799a3d35948f4f1cbe47742
RTEMS tools: 15.2.0 20250808 (RTEMS 7, RSB 08d2e69f30b61de6bf0f5dbf06946d12d074d60e, Newlib 038afec1)
executing thread ID: 0x0b010001
executing thread name: _main_

@hjunkes

hjunkes commented Jan 25, 2026

Copy link
Copy Markdown

It crashes when registering device support for 'devAiStats'.

Breakpoint 2, initDevSup () at ../misc/iocInit.c:452
452	            dset *pdset = registryDeviceSupportFind(pdevSup->name);
(gdb) print pdevSup->name
$8 = 0x12cde68 "devAiStats"
(gdb) c
Continuing.
[Inferior 1 (process 1) exited normally]

@hjunkes

hjunkes commented Jan 25, 2026

Copy link
Copy Markdown

I have been able to trace this so far to 'memstat_sysctl_uma()':

#0  memstat_sysctl_uma (list=list@entry=0x139de80, flags=flags@entry=0) at ../../freebsd/lib/libmemstat/memstat_uma.c:89
#1  0x00318d5e in memstat_sysctl_all (mtlp=mtlp@entry=0x139de80, flags=flags@entry=0) at ../../freebsd/lib/libmemstat/memstat_all.c:48
#2  0x00107b4c in devIocStatsGetClusterInfo (pool=pool@entry=1, pval=pval@entry=0x83a548 <clustinfo+32>) at ../os/RTEMS/osdClustInfo.c:81
#3  0x0010667a in ai_init (pass=0) at ../devIocStatsAnalog.c:460
#4  ai_init (pass=0) at ../devIocStatsAnalog.c:433
#5  0x00206c7e in dbInitDevSup (pdevSup=<optimized out>, pdset=<optimized out>) at ../dbStatic/dbStaticRun.c:56
#6  0x00208c74 in initDevSup () at ../misc/iocInit.c:458
#7  iocBuild_2 () at ../misc/iocInit.c:173
#8  0x00208f14 in iocBuild () at ../misc/iocInit.c:218
#9  0x0020900a in iocInit () at ../misc/iocInit.c:113
#10 0x002128be in iocInitCallFunc (args=<optimized out>) at ../misc/miscIocRegister.c:26
#11 0x0022f86a in iocshBody (pathname=<optimized out>, commandLine=0x0, macros=<optimized out>) at ../iocsh/iocsh.cpp:1270
#12 0x001052fc in main (argc=<optimized out>, argv=<optimized out>) at ../myExampleMain.cpp:21
(gdb) list
77	 */
78	int
79	memstat_sysctl_uma(struct memory_type_list *list, int flags)
80	{
81		struct uma_stream_header *ushp;
82		struct uma_type_header *uthp;
83		struct uma_percpu_stat *upsp;
84		struct memory_type *mtp;
85		int count, hint_dontsearch, i, j, maxcpus, maxid;
86		char *buffer, *p;
87		size_t size;
88
89		hint_dontsearch = LIST_EMPTY(&list->mtl_list);
(gdb) next
memstat_sysctl_uma (list=list@entry=0x139de80, flags=flags@entry=0) at ../../freebsd/lib/libmemstat/memstat_uma.c:113
113		if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) {
(gdb) next
125		size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) *
(gdb) next
128		buffer = malloc(size);
(gdb) next
134		if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) {
(gdb) next
129		if (buffer == NULL) {
(gdb) next
[Inferior 1 (process 1) exited normally]

@hjunkes

hjunkes commented Jan 26, 2026

Copy link
Copy Markdown

Error in freebsd/sys/vm/uma_core.c,

uma_vm_zone_stats(struct uma_type_header *uth, uma_zone_t z, struct sbuf *sbuf,
struct uma_percpu_stat *ups, bool internal)

uma_zone_t z == 0 ??

(gdb) print z->uz_sleeps
Cannot access memory at address 0x0
(gdb) list 5715
5703		uma_zone_domain_t zdom;
5704		uma_cache_t cache;
5705		int i;
5706
5707		for (i = 0; i < vm_ndomains; i++) {
5708			zdom = ZDOM_GET(z, i);
5709			uth->uth_zone_free += zdom->uzd_nitems;
5710		}
5711		uth->uth_allocs = counter_u64_fetch(z->uz_allocs);
5712		uth->uth_frees = counter_u64_fetch(z->uz_frees);
5713		uth->uth_fails = counter_u64_fetch(z->uz_fails);
5714		uth->uth_xdomain = counter_u64_fetch(z->uz_xdomain);
5715		uth->uth_sleeps = z->uz_sleeps;
5716
5717		for (i = 0; i < mp_maxid + 1; i++) {
5718			bzero(&ups[i], sizeof(*ups));
5719			if (internal || CPU_ABSENT(i))
5720				continue;
5721			cache = &z->uz_cpu[i];
5722			ups[i].ups_cache_free += cache->uc_allocbucket.ucb_cnt;
5723			ups[i].ups_cache_free += cache->uc_freebucket.ucb_cnt;
5724			ups[i].ups_cache_free += cache->uc_crossbucket.ucb_cnt;
5725			ups[i].ups_allocs = cache->uc_allocs;
5726			ups[i].ups_frees = cache->uc_frees;
5727		}
(gdb) bt
#0  sysctl_vm_zone_stats (oidp=0x711d80 <_bsd_sysctl___vm_zone_stats>, arg1=0x0, arg2=0, req=0x8920b0)
    at ../../freebsd/sys/vm/uma_core.c:5743
#1  0x00287442 in sysctl_root_handler_locked (oid=0x711d80 <_bsd_sysctl___vm_zone_stats>, arg1=0x0, arg2=0, req=0x8920b0,
    tracker=<synthetic pointer>) at ../../freebsd/sys/kern/kern_sysctl.c:203
#2  sysctl_root (oidp=0x0, arg1=0x0, arg2=0, req=0x8920b0) at ../../freebsd/sys/kern/kern_sysctl.c:2327
#3  _bsd_kernel_sysctl (td=td@entry=0x0, name=name@entry=0x892118, namelen=<optimized out>, old=old@entry=0x193eb20,
    oldlenp=oldlenp@entry=0x892224, new=new@entry=0x0, newlen=newlen@entry=0, retval=retval@entry=0x892224,
    flags=flags@entry=0) at ../../freebsd/sys/kern/kern_sysctl.c:2050
#4  0x002e4928 in sysctl (name=0x892178, namelen=<optimized out>, oldp=0x193eb20, oldlenp=0x892224, newp=0x0, newlen=0)
    at ../../rtemsbsd/rtems/rtems-bsd-syscall-api.c:858
#5  sysctlbyname (name=name@entry=0x55b5b8 "vm.zone_stats", oldp=oldp@entry=0x193eb20, oldlenp=oldlenp@entry=0x892224,
    newp=newp@entry=0x0, newlen=newlen@entry=0) at ../../rtemsbsd/rtems/rtems-bsd-syscall-api.c:886
#6  0x00318dca in memstat_sysctl_uma (list=list@entry=0x139dc18, flags=flags@entry=0)
    at ../../freebsd/lib/libmemstat/memstat_uma.c:134
#7  0x00318d5e in memstat_sysctl_all (mtlp=mtlp@entry=0x139dc18, flags=flags@entry=0)
    at ../../freebsd/lib/libmemstat/memstat_all.c:48
#8  0x00107b4c in devIocStatsGetClusterInfo (pool=pool@entry=1, pval=pval@entry=0x83a548 <clustinfo+32>)
    at ../os/RTEMS/osdClustInfo.c:81
#9  0x0010667a in ai_init (pass=0) at ../devIocStatsAnalog.c:460
#10 ai_init (pass=0) at ../devIocStatsAnalog.c:433
#11 0x00206c7e in dbInitDevSup (pdevSup=<optimized out>, pdset=<optimized out>) at ../dbStatic/dbStaticRun.c:56
#12 0x00208c74 in initDevSup () at ../misc/iocInit.c:458
#13 iocBuild_2 () at ../misc/iocInit.c:173
#14 0x00208f14 in iocBuild () at ../misc/iocInit.c:218
#15 0x0020900a in iocInit () at ../misc/iocInit.c:113
#16 0x002128be in iocInitCallFunc (args=<optimized out>) at ../misc/miscIocRegister.c:26
#17 0x0022f86a in iocshBody (pathname=<optimized out>, commandLine=0x0, macros=<optimized out>) at ../iocsh/iocsh.cpp:1270
#18 0x001052fc in main (argc=<optimized out>, argv=<optimized out>) at ../myExampleMain.cpp:21

@kiwichris

kiwichris commented Jan 26, 2026 •

Copy link
Copy Markdown
Author

Thanks @hjunkes for the detailed report and debugging. It looks like a bug in the zone allocation port to RTEMS.

I have opened an issue in RTEMS https://gitlab.rtems.org/rtems/pkg/rtems-libbsd/-/issues/74

@hjunkes

hjunkes commented May 29, 2026

Copy link
Copy Markdown

To adapt it to RTEMS7, I had to make a few adjustments.

rtems7.patch

@hjunkes

hjunkes commented Jun 12, 2026

Copy link
Copy Markdown

I’m currently trying to get PVXS running on RTEMS 7 and have come across a crash in iocStats.

diff --git a/devIocStats/os/RTEMS/osdCpuUsage.c b/devIocStats/os/RTEMS/osdCpuUsage.c
index a0941e9..dd7f59f 100644
--- a/devIocStats/os/RTEMS/osdCpuUsage.c
+++ b/devIocStats/os/RTEMS/osdCpuUsage.c
@@ -99,6 +99,13 @@ static void cpu_ticks(double *total, double *idle) {
*total = 0;
*idle = 0;

+#if RTEMS_MAJOR >= 7

  • /* Thread_Control layout changed significantly in RTEMS 7.
    • The cpu_time_used offset compiled as 0xc8 but actual offset differs.
    • CPU usage reporting disabled until iocStats is updated for RTEMS 7. */
  • return;
    +#endif
  • for (x = 1; x <= OBJECTS_APIS_LAST; x++) {
    if (!_Objects_Information_table[x]) {
    continue;

@hjunkes

hjunkes commented Aug 6, 2026

Copy link
Copy Markdown

While working on RTEMS 7 support for iocStats (BeagleBone Black BSP), I found and fixed an off-by-one bug in osdCpuUsage.c's cpu_ticks(): local_table[y] is indexed with a 1-based index without subtracting OBJECTS_INDEX_MINIMUM, so it reads one pointer past the end of the array on every pass. This apparently didn't fault under RTEMS 6's memory layout but crashes under RTEMS 7 (I'd previously misdiagnosed it as a Thread_Control layout change and disabled CPU usage reporting on RTEMS 7 entirely — verified via offsetof/sizeof against the real RTEMS 6 and 7 headers that the layout is actually identical).

Fixed here: hjunkes/iocStats@3bf6951

Also fixed an unrelated clean-build race in iocAdmin/Db/Makefile that surfaces when building from scratch: hjunkes/iocStats@5a112a9

Flagging in case either is relevant to this RTEMS 6/7 net-support work.

@anjohnson anjohnson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments/Q's from today's APS VxWorks to RTEMS meeting.

Comment on lines +86 to +90
#if RTEMS_VERSION_INT < VERSION_INT(6, 0, 0, 0)
#define rtems_bsd_reset() bsp_reset()
#else /* RTEMS_VERSION_INT < VERSION_INT(6, 0, 0, 0) */
#define rtems_bsd_reset() bsp_reset()
#endif /* RTEMS_VERSION_INT < VERSION_INT(6, 0, 0, 0) */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are both arms of this if() statement identical?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question and it has been a while.

It looks like a why to separate the pre-6 functionality from the 6 and later function to call. It can be reverted?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're probably not meant to be identical — looks like a leftover from splitting the #if/#else.

A few lines further down, the RTEMS 6 reboot() redefinition uses the two-argument RTEMS 6 bsp_reset() signature:

static inline void reboot(int val) {
  (void)val;
  bsp_reset(RTEMS_FATAL_SOURCE_APPLICATION, 112233);
}

but the RTEMS-6 arm of rtems_bsd_reset() right above it still calls the old zero-argument form. My guess is the #else branch was meant to be:

#define rtems_bsd_reset() bsp_reset(RTEMS_FATAL_SOURCE_APPLICATION, 112233)

to match reboot(), and got missed when the conditional was split out. Worth double-checking against the actual RTEMS 6 bsp_reset() prototype either way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the name be rtems_bsp_reset() and not rtems_bsd_reset()?

Yes I agree. Thanks for the analysis. I checked and RTEMS 5 and I guess earlier have:

void bsp_reset(void);

and RTEMS 6 and later has:

void bsp_reset( rtems_fatal_source source, rtems_fatal_code code );

Comment on lines +111 to +114
static inline void reboot(int val) {
(void)val;
bsp_reset(RTEMS_FATAL_SOURCE_APPLICATION, 112233);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use the RTEMS higher-level APIs instead of the BSP one?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bsp_reset should be a physical means of reset, ie a register with a signal or triggering a watchdog. It is called at the end of an orderly shutdown. Directly calling it mean you do not have an orderly shutdown. Using exit(something) would be an orderly shutdown however any issues in the exit processing can hang a system.

@thelunatic thelunatic Aug 7, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would rtems_shutdown_executive be appropriate here?

If we set BSP_RESET_BOARD_AT_EXIT in the config.ini file, it will reach bsp_reset(), and we can avoid handling bsp_* functions from EPICS applications/modules.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would rtems_shutdown_executive be appropriate here?

If we set BSP_RESET_BOARD_AT_EXIT in the config.ini file, it will reach bsp_reset(), and we can avoid handling bsp_* functions from EPICS applications/modules.

I see this setting as a per BSP or hardware specific settings combined with the system requirements. I am not comfortable having this setting be made a requirement for EPICS as it makes a fragile link between a BSP configuration, the BSP default and EPICS. And I doubt the calls are consistently implemented in all BSPs so both options work.

The option lets a BSP return to the boot loader or a reset happen. Some BSPs do not have a means to return to a boot loader as the boot process is destructive and others it is easier as a boot loader can handle a reset, ie hardware security reasons.

Should EPICS be consistent in how a device restarts? If yes then what role does a BSP reset have here in iocStats?

As an example the MVME5500 or MVME2700 return the boot loader on exit(). And on the boards I have access to once there they sit. I have no idea if a reset can be scripted and how recovery happens in a real system? Another example a Zynq has a software reset signal that is different to the power on reset (POR) signal and you often need custom hardware to manage this. The bsp_reset() is wired to the software reset.

Comment on lines +68 to +74
getrusage(RUSAGE_SELF, &stats);
curActive = (double)stats.ru_utime.tv_sec + stats.ru_utime.tv_usec / 1e6;
curIdle = (double)stats.ru_stime.tv_sec + stats.ru_stime.tv_usec / 1e6;
*idle = curIdle - oldIdleUsage;
*total = *idle + (curActive - oldActiveUsage);
oldActiveUsage = curActive;
oldIdleUsage = curIdle;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vijay says there may be a proper RTEMS API coming for this, but only for RTEMS-7; if so that would be a good change to make use of for the supported RTEMS version(s).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which API is this?

@thelunatic thelunatic Aug 7, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking about rtems_cpu_task_get_usage MR here: https://gitlab.rtems.org/rtems/rtos/rtems/-/merge_requests/1347

I haven't looked at how well it fits in here, but looks like the rtems API can be used here instead of custom coding it again. This code might get stale again if RTEMS is updated, and it will likely be easier to use an rtems api instead of implementing it here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using rtems_task_iterate() to loop over each task and sum the values of _Thread_Get_CPU_time_used(task)?

Unfortunately, _Thread_Get_CPU_time_used() seems to be a score function, but if there's no alternative yet perhaps its the best option for now. I think its been around since RTEMS 5.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using rtems_task_iterate() to loop over each task and sum the values of _Thread_Get_CPU_time_used(task)?

Yes this is at the core of the approach I used in getusage back in 2024.

Unfortunately, _Thread_Get_CPU_time_used() seems to be a score function, but if there's no alternative yet perhaps its the best option for now. I think its been around since RTEMS 5.

In the early days of EPICS integration we were not strict as everyone worked to get something going. The downside of this is we are still paying the price today as we extract EPICS from deep inside RTEMS. A key part of this effort is epics-base/epics-base#905.

I was talking about rtems_cpu_task_get_usage MR here: https://gitlab.rtems.org/rtems/rtos/rtems/-/merge_requests/1347

Ah OK, the GSoC project. That call fills the gap of getrusage where you are asking about the CPU usage of specific thread that is not the executing thread. I thought iocStats was about the current load on the board and as RTEMS is a single process system calling getrusage with RUSAGE_SELF gives you that value?

I haven't looked at how well it fits in here, but looks like the rtems API can be used here instead of custom coding it again. This code might get stale again if RTEMS is updated, and it will likely be easier to use an rtems api instead of implementing it here.

It is per thread and yes correct.

I am little confused by this discussion as I thought I had done this and exported the result via the standards supported getrusage call back in July 2024?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am little confused by this discussion as I thought I had done this and exported the result via the standards supported getrusage call back in July 2024?

I understand this change a bit more now after your comments. getrusage and the code proposed here looks good to me.

hjunkes added a commit to hjunkes/iocStats-upstream that referenced this pull request Aug 7, 2026
Same RTEMS-Score-API-drift theme, at the libbsd network-stack boundary
this time.

osdClustInfo.c:
- The legacy network stack's `extern struct mbstat mbstat` doesn't
  exist under libbsd. Gated the old code behind
  `#if RTEMS_LIBBSD_STACK` / `#else`, and for the libbsd case query
  the same mbuf/cluster counts through libbsd's portable memstat API
  (memstat_mtl_alloc/memstat_sysctl_all/memstat_mtl_find +
  memstat_get_size/count/free), the same mechanism `netstat -m` uses.
  Also actually implements devIocStatsGetClusterUsage() for the
  libbsd case rather than returning -1 unconditionally.

  (epics-modules#61 took the same memstat approach for its
  RTEMS 6 support, but writes the mbuf_cluster stats into row [0]
  again instead of row [1], clobbering the mbuf row -- fixed that
  here.)

osdIFErrors.c:
- `extern struct ifnet *ifnet` walked via `if_next`, and
  if_ierrors/if_oerrors, are kernel-internal under libbsd (ifnet is a
  CK_STAILQ now, and the counters are behind the if_get_counter KPI) --
  neither is meant to be reachable from outside the kernel proper, so
  `__RTEMS_VIOLATE_KERNEL_VISIBILITY__` doesn't save this approach.
  Switched to getifaddrs()/struct if_data, the portable userspace-
  visible way to read the same per-interface error counters (each
  interface contributes one AF_LINK entry whose ifa_data is its
  struct if_data).

Both compile cleanly against the current RTEMS 7 build. Remaining
unrelated pre-existing issues in this module (devIocStatsOSD.h's
rtemsReboot, and -Wincompatible-pointer-types in the
Analog/String/Waveform DSETs) still untouched -- out of scope here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
hjunkes added a commit to hjunkes/iocStats-upstream that referenced this pull request Aug 7, 2026
Hardware-verified crash: memstat_sysctl_all() (used by the previous
commit's libbsd implementation of devIocStatsGetClusterInfo/Usage)
takes a data abort inside libbsd's UMA per-CPU counter stats path.
Confirmed via addr2line against the actual crash PC/LR from the RTEMS
fatal-exception dump:

  PC  0x8023e148 -> _bsd_counter_u64_alloc
                    (rtems-libbsd/.../freebsd/sys/kern/subr_counter.c:64)
  LR  0x802cc904 -> uma_vm_zone_stats
                    (rtems-libbsd/.../freebsd/sys/vm/uma_core.c:5718)

This is reached from a periodic devIocStats timer callback shortly
after iocInit starts (ai_clusts's driver init registers an
initHookAfterCaServerInit hook), so it crashes essentially every boot
once a CLUST_* record is loaded.

The memstat approach was adapted from epics-modules#61's
(still open, unmerged) RTEMS 6 port, which apparently was never run on
real hardware either -- it also has a row-index bug fixed in the
previous commit, independent of this crash. Something in this
RTEMS-libbsd build's counter(9)/UMA-zone-stats support is broken or
incomplete; root-causing that is future work.

Reverted to reporting "not available" (-1), matching what epics-modules#61 itself
does for the GetClusterUsage case it left unimplemented. CLUST_*
records will show INVALID/alarm rather than a real reading, but the
IOC boots and runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@hjunkes

hjunkes commented Aug 7, 2026

Copy link
Copy Markdown

Hardware finding while porting this PR's osdClustInfo.c approach forward for RTEMS 7 (real BeagleBone Black, RTEMS_LIBBSD_STACK) in #88:

1. Row-index bug in the memstat-based devIocStatsGetClusterInfo(): the mbuf-cluster stats (MBUF_CLUSTER_MEM_NAME) get written into (*pval)[0][...] again instead of (*pval)[1][...], clobbering the mbuf row instead of filling the cluster row.

2. More seriously: memstat_sysctl_all() crashes on real hardware. It's called from a devIocStats periodic timer callback shortly after iocInit starts (registered via initHookAfterCaServerInit), so in practice it crashes on essentially every boot once a CLUST_*-type record is loaded. The RTEMS fatal-exception dump showed a data abort; resolving the PC/LR against the built ELF with addr2line pinned it exactly:

PC  0x8023e148 -> _bsd_counter_u64_alloc
                  (rtems-libbsd/.../freebsd/sys/kern/subr_counter.c:64)
LR  0x802cc904 -> uma_vm_zone_stats
                  (rtems-libbsd/.../freebsd/sys/vm/uma_core.c:5718)

So memstat_sysctl_all() → uma_vm_zone_stats() → _bsd_counter_u64_alloc(), inside libbsd's UMA per-CPU counter-stats path. Something in this RTEMS-libbsd port's counter(9)/UMA-zone-stats support looks broken or incomplete -- I haven't root-caused it further than that.

For now (in #88) I've reverted the libbsd branch of devIocStatsGetClusterInfo/GetClusterUsage to just report "not available" (-1) rather than crash, since a crashing IOC is worse than a CLUST_* PV sitting in INVALID alarm. Wanted to flag both here since this PR is where the approach originated -- happy to share more detail (full register dump, build config) if useful for tracking down the underlying libbsd issue.

@anjohnson

Copy link
Copy Markdown
Member

The mbuf cluster stuff that iocStats purports to show was IIRC only useful with the old IP stack in VxWorks 5.x, in VxWorks 6 they went back to a more conventional IP stack with a single partition for network memory. I think it should be completely removed, I don't think anybody even understands it any more, so I have no problem with it not doing anything on RTEMS.

@kiwichris

Copy link
Copy Markdown
Author

The mbuf cluster stuff that iocStats purports to show was IIRC only useful with the old IP stack in VxWorks 5.x, in VxWorks 6 they went back to a more conventional IP stack with a single partition for network memory. I think it should be completely removed, I don't think anybody even understands it any more, so I have no problem with it not doing anything on RTEMS.

This makes sense to me. I should point out netstat is your friend on LibBSD. An example from a Zynq system with 1G of RAM:

rtems [/] # netstat -m
317/1558/1875 mbufs in use (current/cache/total)
281/1095/1376/16384 mbuf clusters in use (current/cache/total/max)
281/969 mbuf+clusters out of packet secondary zone in use (current/cache)
0/125/125/8192 4k (page size) jumbo clusters in use (current/cache/total/max)
0/0/0/2427 9k jumbo clusters in use (current/cache/total/max)
0/0/0/1365 16k jumbo clusters in use (current/cache/total/max)
641K/3079K/3720K bytes allocated to network (current/cache/total)
0/0/0 requests for mbufs denied (mbufs/clusters/mbuf+clusters)
0/0/0 requests for mbufs delayed (mbufs/clusters/mbuf+clusters)
0/0/0 requests for jumbo clusters delayed (4k/9k/16k)
0/0/0 requests for jumbo clusters denied (4k/9k/16k)

If working with LibBSD shows a need there are options that can be added in.

@kiwichris
kiwichris force-pushed the rtems-6-legacy-libbsd branch from 46633e2 to a5bdfb2 Compare September 25, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants