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:
Peter Bigot 2020-11-08 19:57:52 -06:00 committed by Anas Nashif
parent 18851d8ef9
commit bb99422c8a
5 changed files with 54 additions and 302 deletions

View file

@ -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

View file

@ -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"

View file

@ -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';

View file

@ -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");
}

View file

@ -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