lib/os: replace z_vprintk with cbprintf
Using the same implementation as the rest of Zephyr reduces code size. Update options and expected results for formatting test. Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
parent
18851d8ef9
commit
bb99422c8a
|
@ -65,9 +65,6 @@ extern __printf_like(3, 4) int snprintk(char *str, size_t size,
|
|||
extern __printf_like(3, 0) int vsnprintk(char *str, size_t size,
|
||||
const char *fmt, va_list ap);
|
||||
|
||||
extern __printf_like(3, 0) void z_vprintk(int (*out)(int f, void *c), void *ctx,
|
||||
const char *fmt, va_list ap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -47,21 +47,9 @@ config SYS_HEAP_ALLOC_LOOPS
|
|||
is useful in locked or ISR contexts.
|
||||
|
||||
config PRINTK64
|
||||
bool
|
||||
prompt "Enable 64 bit printk conversions" if !64BIT
|
||||
default y
|
||||
bool "Enable 64 bit printk conversions (DEPRECATED)"
|
||||
help
|
||||
When true, 64 bit values will be printable on 32 bit systems
|
||||
using the "ll" flag to the %d, %i, %u, %x and %X specifiers.
|
||||
When false, these values will be correctly parsed from the
|
||||
function arguments, but will print "ERR" if their value is
|
||||
unrepresentable in 32 bits. This setting is always true on
|
||||
64 bit systems. Note that setting this =n does not produce
|
||||
significant code savings within the printk library code
|
||||
itself. Instead, it suppresses the use of the
|
||||
toolchain-provided 64 bit division implementation, which may
|
||||
reduce code size if it is unused elsewhere in the
|
||||
application. Most apps should leave this set to y.
|
||||
Replace with CBPRINTF_FULL_INTEGRAL.
|
||||
|
||||
config PRINTK_SYNC
|
||||
bool "Serialize printk() calls"
|
||||
|
|
256
lib/os/printk.c
256
lib/os/printk.c
|
@ -19,29 +19,9 @@
|
|||
#include <linker/sections.h>
|
||||
#include <syscall_handler.h>
|
||||
#include <logging/log.h>
|
||||
#include <sys/cbprintf.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef int (*out_func_t)(int c, void *ctx);
|
||||
|
||||
enum pad_type {
|
||||
PAD_NONE,
|
||||
PAD_ZERO_BEFORE,
|
||||
PAD_SPACE_BEFORE,
|
||||
PAD_SPACE_AFTER,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PRINTK64
|
||||
typedef uint64_t printk_val_t;
|
||||
#else
|
||||
typedef uint32_t printk_val_t;
|
||||
#endif
|
||||
|
||||
/* Maximum number of digits in a printed decimal value (hex is always
|
||||
* less, obviously). Funny formula produces 10 max digits for 32 bit,
|
||||
* 21 for 64.
|
||||
*/
|
||||
#define DIGITS_BUFLEN (11U * (sizeof(printk_val_t) / 4U) - 1U)
|
||||
|
||||
#ifdef CONFIG_PRINTK_SYNC
|
||||
static struct k_spinlock lock;
|
||||
#endif
|
||||
|
@ -96,232 +76,6 @@ void *__printk_get_hook(void)
|
|||
}
|
||||
#endif /* CONFIG_PRINTK */
|
||||
|
||||
static void print_digits(out_func_t out, void *ctx, printk_val_t num, unsigned int base,
|
||||
bool pad_before, char pad_char, int min_width)
|
||||
{
|
||||
char buf[DIGITS_BUFLEN];
|
||||
unsigned int i;
|
||||
|
||||
/* Print it backwards into the end of the buffer, low digits first */
|
||||
for (i = DIGITS_BUFLEN - 1U; num != 0U; i--) {
|
||||
buf[i] = "0123456789abcdef"[num % base];
|
||||
num /= base;
|
||||
}
|
||||
|
||||
if (i == DIGITS_BUFLEN - 1U) {
|
||||
buf[i] = '0';
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
|
||||
int pad = MAX(min_width - (int)(DIGITS_BUFLEN - i), 0);
|
||||
|
||||
for (/**/; pad > 0 && pad_before; pad--) {
|
||||
out(pad_char, ctx);
|
||||
}
|
||||
for (/**/; i < DIGITS_BUFLEN; i++) {
|
||||
out(buf[i], ctx);
|
||||
}
|
||||
for (/**/; pad > 0; pad--) {
|
||||
out(pad_char, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_hex(out_func_t out, void *ctx, printk_val_t num,
|
||||
enum pad_type padding, int min_width)
|
||||
{
|
||||
print_digits(out, ctx, num, 16U, padding != PAD_SPACE_AFTER,
|
||||
padding == PAD_ZERO_BEFORE ? '0' : ' ', min_width);
|
||||
}
|
||||
|
||||
static void print_dec(out_func_t out, void *ctx, printk_val_t num,
|
||||
enum pad_type padding, int min_width)
|
||||
{
|
||||
print_digits(out, ctx, num, 10U, padding != PAD_SPACE_AFTER,
|
||||
padding == PAD_ZERO_BEFORE ? '0' : ' ', min_width);
|
||||
}
|
||||
|
||||
static bool ok64(out_func_t out, void *ctx, long long val)
|
||||
{
|
||||
if (sizeof(printk_val_t) < 8U && val != (long) val) {
|
||||
out('E', ctx);
|
||||
out('R', ctx);
|
||||
out('R', ctx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool negative(printk_val_t val)
|
||||
{
|
||||
const printk_val_t hibit = ~(((printk_val_t) ~1) >> 1U);
|
||||
|
||||
return (val & hibit) != 0U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Printk internals
|
||||
*
|
||||
* See printk() for description.
|
||||
* @param fmt Format string
|
||||
* @param ap Variable parameters
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||
{
|
||||
int might_format = 0; /* 1 if encountered a '%' */
|
||||
enum pad_type padding = PAD_NONE;
|
||||
int min_width = -1;
|
||||
char length_mod = 0;
|
||||
|
||||
/* fmt has already been adjusted if needed */
|
||||
|
||||
while (*fmt) {
|
||||
if (!might_format) {
|
||||
if (*fmt != '%') {
|
||||
out((int)*fmt, ctx);
|
||||
} else {
|
||||
might_format = 1;
|
||||
min_width = -1;
|
||||
padding = PAD_NONE;
|
||||
length_mod = 0;
|
||||
}
|
||||
} else {
|
||||
switch (*fmt) {
|
||||
case '-':
|
||||
padding = PAD_SPACE_AFTER;
|
||||
goto still_might_format;
|
||||
case '0':
|
||||
if (min_width < 0 && padding == PAD_NONE) {
|
||||
padding = PAD_ZERO_BEFORE;
|
||||
goto still_might_format;
|
||||
}
|
||||
__fallthrough;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (min_width < 0) {
|
||||
min_width = *fmt - '0';
|
||||
} else {
|
||||
min_width = 10 * min_width + *fmt - '0';
|
||||
}
|
||||
|
||||
if (padding == PAD_NONE) {
|
||||
padding = PAD_SPACE_BEFORE;
|
||||
}
|
||||
goto still_might_format;
|
||||
case 'h':
|
||||
case 'l':
|
||||
case 'z':
|
||||
if (*fmt == 'h' && length_mod == 'h') {
|
||||
length_mod = 'H';
|
||||
} else if (*fmt == 'l' && length_mod == 'l') {
|
||||
length_mod = 'L';
|
||||
} else if (length_mod == 0) {
|
||||
length_mod = *fmt;
|
||||
} else {
|
||||
out((int)'%', ctx);
|
||||
out((int)*fmt, ctx);
|
||||
break;
|
||||
}
|
||||
goto still_might_format;
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u': {
|
||||
printk_val_t d;
|
||||
|
||||
if (length_mod == 'z') {
|
||||
d = va_arg(ap, ssize_t);
|
||||
} else if (length_mod == 'l') {
|
||||
d = va_arg(ap, long);
|
||||
} else if (length_mod == 'L') {
|
||||
long long lld = va_arg(ap, long long);
|
||||
if (!ok64(out, ctx, lld)) {
|
||||
break;
|
||||
}
|
||||
d = (printk_val_t) lld;
|
||||
} else if (*fmt == 'u') {
|
||||
d = va_arg(ap, unsigned int);
|
||||
} else {
|
||||
d = va_arg(ap, int);
|
||||
}
|
||||
|
||||
if (*fmt != 'u' && negative(d)) {
|
||||
out((int)'-', ctx);
|
||||
d = -d;
|
||||
min_width--;
|
||||
}
|
||||
print_dec(out, ctx, d, padding, min_width);
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
out('0', ctx);
|
||||
out('x', ctx);
|
||||
/* left-pad pointers with zeros */
|
||||
padding = PAD_ZERO_BEFORE;
|
||||
min_width = sizeof(void *) * 2U;
|
||||
__fallthrough;
|
||||
case 'x':
|
||||
case 'X': {
|
||||
printk_val_t x;
|
||||
|
||||
if (*fmt == 'p') {
|
||||
x = (uintptr_t)va_arg(ap, void *);
|
||||
} else if (length_mod == 'l') {
|
||||
x = va_arg(ap, unsigned long);
|
||||
} else if (length_mod == 'L') {
|
||||
x = va_arg(ap, unsigned long long);
|
||||
} else {
|
||||
x = va_arg(ap, unsigned int);
|
||||
}
|
||||
|
||||
print_hex(out, ctx, x, padding, min_width);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
char *s = va_arg(ap, char *);
|
||||
char *start = s;
|
||||
|
||||
while (*s) {
|
||||
out((int)(*s++), ctx);
|
||||
}
|
||||
|
||||
if (padding == PAD_SPACE_AFTER) {
|
||||
int remaining = min_width - (s - start);
|
||||
while (remaining-- > 0) {
|
||||
out(' ', ctx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
int c = va_arg(ap, int);
|
||||
|
||||
out(c, ctx);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
out((int)'%', ctx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out((int)'%', ctx);
|
||||
out((int)*fmt, ctx);
|
||||
break;
|
||||
}
|
||||
might_format = 0;
|
||||
}
|
||||
still_might_format:
|
||||
++fmt;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PRINTK
|
||||
#ifdef CONFIG_USERSPACE
|
||||
|
@ -369,7 +123,7 @@ void vprintk(const char *fmt, va_list ap)
|
|||
if (_is_user_context()) {
|
||||
struct buf_out_context ctx = { 0 };
|
||||
|
||||
z_vprintk(buf_char_out, &ctx, fmt, ap);
|
||||
cbvprintf(buf_char_out, &ctx, fmt, ap);
|
||||
|
||||
if (ctx.buf_count) {
|
||||
buf_flush(&ctx);
|
||||
|
@ -380,7 +134,7 @@ void vprintk(const char *fmt, va_list ap)
|
|||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
#endif
|
||||
|
||||
z_vprintk(char_out, &ctx, fmt, ap);
|
||||
cbvprintf(char_out, &ctx, fmt, ap);
|
||||
|
||||
#ifdef CONFIG_PRINTK_SYNC
|
||||
k_spin_unlock(&lock, key);
|
||||
|
@ -395,7 +149,7 @@ void vprintk(const char *fmt, va_list ap)
|
|||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
#endif
|
||||
|
||||
z_vprintk(char_out, &ctx, fmt, ap);
|
||||
cbvprintf(char_out, &ctx, fmt, ap);
|
||||
|
||||
#ifdef CONFIG_PRINTK_SYNC
|
||||
k_spin_unlock(&lock, key);
|
||||
|
@ -503,7 +257,7 @@ int vsnprintk(char *str, size_t size, const char *fmt, va_list ap)
|
|||
{
|
||||
struct str_context ctx = { str, size, 0 };
|
||||
|
||||
z_vprintk((out_func_t)str_out, &ctx, fmt, ap);
|
||||
cbvprintf(str_out, &ctx, fmt, ap);
|
||||
|
||||
if (ctx.count < ctx.max) {
|
||||
str[ctx.count] = '\0';
|
||||
|
|
|
@ -15,21 +15,7 @@ void __printk_hook_install(int (*fn)(int));
|
|||
void *__printk_get_hook(void);
|
||||
int (*_old_char_out)(int);
|
||||
|
||||
#ifndef CONFIG_PRINTK64
|
||||
|
||||
char *expected = "22 113 10000 32768 40000 22\n"
|
||||
"p 112 -10000 -32768 -40000 -22\n"
|
||||
"0x1 0x01 0x0001 0x00000001 0x0000000000000001\n"
|
||||
"0x1 0x 1 0x 1 0x 1\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"-42 -42 -042 -0000042\n"
|
||||
"42 42 42 42\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"255 42 abcdef 42\n"
|
||||
"ERR -1 ERR ffffffffffffffff\n"
|
||||
;
|
||||
#else
|
||||
|
||||
#if defined(CONFIG_CBPRINTF_FULL_INTEGRAL)
|
||||
char *expected = "22 113 10000 32768 40000 22\n"
|
||||
"p 112 -10000 -32768 -40000 -22\n"
|
||||
"0x1 0x01 0x0001 0x00000001 0x0000000000000001\n"
|
||||
|
@ -40,17 +26,34 @@ char *expected = "22 113 10000 32768 40000 22\n"
|
|||
"42 42 0042 00000042\n"
|
||||
"255 42 abcdef 42\n"
|
||||
"68719476735 -1 18446744073709551615 ffffffffffffffff\n"
|
||||
"0xcafebabe 0xbeef 0x2a\n"
|
||||
;
|
||||
#elif defined(CONFIG_CBPRINTF_COMPLETE)
|
||||
char *expected = "22 113 10000 32768 40000 %llu\n"
|
||||
"p 112 -10000 -32768 -40000 %lld\n"
|
||||
"0x1 0x01 0x0001 0x00000001 0x0000000000000001\n"
|
||||
"0x1 0x 1 0x 1 0x 1\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"-42 -42 -042 -0000042\n"
|
||||
"42 42 42 42\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"255 42 abcdef 42\n"
|
||||
"%lld %lld %llu %llx\n"
|
||||
"0xcafebabe 0xbeef 0x2a\n"
|
||||
;
|
||||
#elif defined(CONFIG_CBPRINTF_NANO)
|
||||
char *expected = "22 113 10000 32768 40000 22\n"
|
||||
"p 112 -10000 -32768 -40000 -22\n"
|
||||
"0x1 0x01 0x0001 0x00000001 0x0000000000000001\n"
|
||||
"0x1 0x 1 0x 1 0x 1\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"-42 -42 -042 -0000042\n"
|
||||
"42 42 42 42\n"
|
||||
"42 42 0042 00000042\n"
|
||||
"255 42 abcdef 42\n"
|
||||
"ERR -1 4294967295 ffffffff\n"
|
||||
"0xcafebabe 0xbeef 0x2a\n"
|
||||
;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
|
||||
char *expected2 = "0xcafebabe 0x0000beef 0x0000002a\n";
|
||||
|
||||
#else
|
||||
|
||||
char *expected2 = "0xcafebabe 0x000000000000beef 0x000000000000002a\n";
|
||||
|
||||
#endif
|
||||
|
||||
size_t stv = 22;
|
||||
|
@ -110,19 +113,11 @@ void test_printk(void)
|
|||
printk("%u %02u %04u %08u\n", 42, 42, 42, 42);
|
||||
printk("%-8u%-6d%-4x %8d\n", 0xFF, 42, 0xABCDEF, 42);
|
||||
printk("%lld %lld %llu %llx\n", 0xFFFFFFFFFULL, -1LL, -1ULL, -1ULL);
|
||||
printk("0x%x %p %-2p\n", hex, ptr, (char *)42);
|
||||
|
||||
pk_console[pos] = '\0';
|
||||
zassert_true((strcmp(pk_console, expected) == 0), "printk failed");
|
||||
|
||||
/*
|
||||
* Test %p separately as its width depends on sizeof(void *)
|
||||
* regardless of CONFIG_PRINTK64.
|
||||
*/
|
||||
pos = 0;
|
||||
printk("0x%x %p %-2p\n", hex, ptr, (char *)42);
|
||||
pk_console[pos] = '\0';
|
||||
zassert_true((strcmp(pk_console, expected2) == 0), "printk failed");
|
||||
|
||||
(void)memset(pk_console, 0, sizeof(pk_console));
|
||||
count = 0;
|
||||
|
||||
|
@ -149,6 +144,8 @@ void test_printk(void)
|
|||
count += snprintk(pk_console + count, sizeof(pk_console) - count,
|
||||
"%lld %lld %llu %llx\n",
|
||||
0xFFFFFFFFFULL, -1LL, -1ULL, -1ULL);
|
||||
count += snprintk(pk_console + count, sizeof(pk_console) - count,
|
||||
"0x%x %p %-2p\n", hex, ptr, (char *)42);
|
||||
pk_console[count] = '\0';
|
||||
zassert_true((strcmp(pk_console, expected) == 0), "snprintk failed");
|
||||
}
|
||||
|
|
|
@ -17,3 +17,19 @@ tests:
|
|||
filter: not ((CONFIG_I2C or CONFIG_SPI) and CONFIG_USERSPACE)
|
||||
extra_configs:
|
||||
- CONFIG_MISRA_SANE=y
|
||||
kernel.common.nano32:
|
||||
tags: kernel userspace
|
||||
build_on_all: true
|
||||
min_flash: 33
|
||||
filter: not CONFIG_KERNEL_COHERENCE
|
||||
extra_configs:
|
||||
- CONFIG_CBPRINTF_NANO=y
|
||||
- CONFIG_CBPRINTF_REDUCED_INTEGRAL=y
|
||||
kernel.common.nano64:
|
||||
tags: kernel userspace
|
||||
build_on_all: true
|
||||
min_flash: 33
|
||||
filter: not CONFIG_KERNEL_COHERENCE
|
||||
extra_configs:
|
||||
- CONFIG_CBPRINTF_NANO=y
|
||||
- CONFIG_CBPRINTF_FULL_INTEGRAL=y
|
||||
|
|
Loading…
Reference in a new issue