Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/rtapi/uspace_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@ int rtapi_shmem_delete(int handle, int module_id)

void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap);

/* An error or a warning is a line of its own. The default handlers end
one that lacks the newline, so that the next message does not run on
behind it. The other levels may print a line in parts. */
static inline int rtapi_msg_needs_newline(msg_level_t level, const char *msg)
{
size_t n = strlen(msg);
return (level == RTAPI_MSG_ERR || level == RTAPI_MSG_WARN)
&& n > 0 && msg[n - 1] != '\n';
}

static rtapi_msg_handler_t rtapi_msg_handler = default_rtapi_msg_handler;

rtapi_msg_handler_t rtapi_get_msg_handler(void) {
Expand Down
16 changes: 15 additions & 1 deletion src/rtapi/uspace_rtapi_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1708,9 +1708,23 @@ void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) {
message_t m;
m.level = level;
vsnprintf(m.msg, sizeof(m.msg), fmt, ap);
if (rtapi_msg_needs_newline(level, m.msg)) {
size_t n = strlen(m.msg);
if (n == sizeof(m.msg) - 1)
n--; /* truncated: the newline replaces the last character */
m.msg[n] = '\n';
m.msg[n + 1] = '\0';
}
rtapi_msg_queue.push(m);
} else {
vfprintf(level == RTAPI_MSG_ALL ? stdout : stderr, fmt, ap);
FILE *f = level == RTAPI_MSG_ALL ? stdout : stderr;
char *msg;
if (vasprintf(&msg, fmt, ap) < 0)
return;
fputs(msg, f);
if (rtapi_msg_needs_newline(level, msg))
fputc('\n', f);
free(msg);
}
}

Expand Down
16 changes: 9 additions & 7 deletions src/rtapi/uspace_ulapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ void rtapi_delay(long ns) {
}

void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) {
if(level == RTAPI_MSG_ALL) {
vfprintf(stdout, fmt, ap);
fflush(stdout);
} else {
vfprintf(stderr, fmt, ap);
fflush(stderr);
}
FILE *f = level == RTAPI_MSG_ALL ? stdout : stderr;
char *msg;
if (vasprintf(&msg, fmt, ap) < 0)
return;
fputs(msg, f);
if (rtapi_msg_needs_newline(level, msg))
fputc('\n', f);
fflush(f);
free(msg);
}
1 change: 1 addition & 0 deletions tests/rtapi-msg-newline/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
halrun.out
9 changes: 9 additions & 0 deletions tests/rtapi-msg-newline/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Errors and warnings whose text lacks the newline are still lines of
their own (#4689).

msgline prints two errors without a newline from its setup, which runs
in the main thread of rtapi_app, and an error and a warning without a
newline from its function, whose messages rtapi_app queues and prints
from another thread. Each must be a line of its own in the output. An
info message printed in two parts must stay one line: the levels other
than errors and warnings may build a line from several messages.
5 changes: 5 additions & 0 deletions tests/rtapi-msg-newline/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
msgline: error at load
msgline: error at load
msgline: error in the thread
msgline: warning in the thread
msgline: info in parts
29 changes: 29 additions & 0 deletions tests/rtapi-msg-newline/msgline.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
component msgline "Test component for tests/rtapi-msg-newline: prints messages that lack a newline";

pin io bool print "set to print the messages from the realtime thread once; cleared by the function";

function _;
option extra_setup;
option period no;
license "GPL";
author "Luca Toniolo";
;;
EXTRA_SETUP() {
(void)__comp_inst;
(void)prefix;
(void)extra_arg;
rtapi_print_msg(RTAPI_MSG_ERR, "msgline: error at load");
rtapi_print_msg(RTAPI_MSG_ERR, "msgline: error at load");
return 0;
}

FUNCTION(_) {
if (!print)
return;
print_set(0);
rtapi_print_msg(RTAPI_MSG_ERR, "msgline: error in the thread");
rtapi_print_msg(RTAPI_MSG_WARN, "msgline: warning in the thread");
/* the other levels may print a line in parts */
rtapi_print_msg(RTAPI_MSG_INFO, "msgline: info ");
rtapi_print_msg(RTAPI_MSG_INFO, "in parts\n");
}
6 changes: 6 additions & 0 deletions tests/rtapi-msg-newline/msgline.hal
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
loadrt threads name1=t period1=1000000
loadrt msgline
addf msgline.0 t
debug 3
start
loadusr -w ./print.py
15 changes: 15 additions & 0 deletions tests/rtapi-msg-newline/print.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env python3
# Make msgline print from the realtime thread and wait until it has.
# A wait that takes more than 10 s of wall time means the machine is
# dying; the test then aborts.

import hal
import sys
import time

hal.set_p("msgline.0.print", "1")
deadline = time.monotonic() + 10
while hal.get_p("msgline.0.print"):
if time.monotonic() > deadline:
sys.exit("FAIL: the thread did not run msgline.0 in 10 s")
time.sleep(0.01)
4 changes: 4 additions & 0 deletions tests/rtapi-msg-newline/skip
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
# Builds a realtime component with halcompile, which needs the build
# tree. Skip when testing installed packages.
[ -z "$SYSTEM_BUILD" ]
6 changes: 6 additions & 0 deletions tests/rtapi-msg-newline/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
halcompile --install msgline.comp >/dev/null
timeout -k 5 60 halrun -f msgline.hal > halrun.out 2>&1
# the messages of msgline, each on a line of its own
grep '^msgline:' halrun.out
Loading