forked from Imagelibrary/rtems
libtest: Do all output in test runner
This ensures that lines are output atomically if they are produced by different other contexts, e.g. interrupts, other processors, other threads. Update #3199.
This commit is contained in:
@@ -2199,6 +2199,8 @@ typedef void (*T_putchar)(int, void *);
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
char *buf;
|
||||||
|
size_t buf_size;
|
||||||
T_putchar putchar;
|
T_putchar putchar;
|
||||||
void *putchar_arg;
|
void *putchar_arg;
|
||||||
T_verbosity verbosity;
|
T_verbosity verbosity;
|
||||||
|
|||||||
@@ -47,12 +47,16 @@
|
|||||||
#include "t-test-printf.h"
|
#include "t-test-printf.h"
|
||||||
#endif /* __rtems__ */
|
#endif /* __rtems__ */
|
||||||
|
|
||||||
#define T_LINE_SIZE 120
|
#define T_LINE_SIZE 128
|
||||||
|
|
||||||
#define T_SCOPE_SIZE 5
|
#define T_SCOPE_SIZE 5
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pthread_spinlock_t lock;
|
pthread_spinlock_t lock;
|
||||||
|
char *buf;
|
||||||
|
unsigned int buf_mask;
|
||||||
|
atomic_uint buf_head;
|
||||||
|
atomic_uint buf_tail;
|
||||||
void (*putchar)(int, void *);
|
void (*putchar)(int, void *);
|
||||||
void *putchar_arg;
|
void *putchar_arg;
|
||||||
T_verbosity verbosity;
|
T_verbosity verbosity;
|
||||||
@@ -81,18 +85,6 @@ typedef struct {
|
|||||||
|
|
||||||
static T_context T_instance;
|
static T_context T_instance;
|
||||||
|
|
||||||
static int
|
|
||||||
T_do_vprintf(T_context *ctx, char const *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
return _IO_Vprintf(ctx->putchar, ctx->putchar_arg, fmt, ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
T_vprintf(char const *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
return T_do_vprintf(&T_instance, fmt, ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *s;
|
char *s;
|
||||||
size_t n;
|
size_t n;
|
||||||
@@ -101,13 +93,13 @@ typedef struct {
|
|||||||
static void
|
static void
|
||||||
T_putchar_string(int c, void *arg)
|
T_putchar_string(int c, void *arg)
|
||||||
{
|
{
|
||||||
T_putchar_string_context *ctx;
|
T_putchar_string_context *sctx;
|
||||||
char *s;
|
char *s;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
ctx = arg;
|
sctx = arg;
|
||||||
s = ctx->s;
|
s = sctx->s;
|
||||||
n = ctx->n;
|
n = sctx->n;
|
||||||
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
c = '\0';
|
c = '\0';
|
||||||
@@ -119,8 +111,8 @@ T_putchar_string(int c, void *arg)
|
|||||||
--n;
|
--n;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->s = s;
|
sctx->s = s;
|
||||||
ctx->n = n;
|
sctx->n = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -128,17 +120,106 @@ T_snprintf(char *s, size_t n, char const *fmt, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int len;
|
int len;
|
||||||
T_putchar_string_context ctx = {
|
T_putchar_string_context sctx = {
|
||||||
.s = s,
|
.s = s,
|
||||||
.n = n
|
.n = n
|
||||||
};
|
};
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = _IO_Vprintf(T_putchar_string, &ctx, fmt, ap);
|
len = _IO_Vprintf(T_putchar_string, &sctx, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if (ctx.n > 0) {
|
if (sctx.n > 0) {
|
||||||
*ctx.s = '\0';
|
*sctx.s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
T_vprintf_direct(char const *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
T_context *ctx;
|
||||||
|
unsigned int head;
|
||||||
|
unsigned int tail;
|
||||||
|
|
||||||
|
ctx = &T_instance;
|
||||||
|
|
||||||
|
head = atomic_load_explicit(&ctx->buf_head, memory_order_acquire);
|
||||||
|
tail = atomic_load_explicit(&ctx->buf_tail, memory_order_relaxed);
|
||||||
|
|
||||||
|
while (head != tail) {
|
||||||
|
(*ctx->putchar)(ctx->buf[tail], ctx->putchar_arg);
|
||||||
|
tail = (tail + 1) & ctx->buf_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_store_explicit(&ctx->buf_tail, tail, memory_order_relaxed);
|
||||||
|
|
||||||
|
return _IO_Vprintf(ctx->putchar, ctx->putchar_arg, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
T_vprintf_buffered(char const *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
T_context *ctx;
|
||||||
|
char buf[T_LINE_SIZE];
|
||||||
|
T_putchar_string_context sctx = {
|
||||||
|
.s = buf,
|
||||||
|
.n = sizeof(buf)
|
||||||
|
};
|
||||||
|
unsigned int head;
|
||||||
|
unsigned int tail;
|
||||||
|
unsigned int mask;
|
||||||
|
unsigned int capacity;
|
||||||
|
|
||||||
|
len = (unsigned int)_IO_Vprintf(T_putchar_string, &sctx, fmt, ap);
|
||||||
|
|
||||||
|
if (len >= sizeof(buf)) {
|
||||||
|
len = sizeof(buf) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = &T_instance;
|
||||||
|
pthread_spin_lock(&ctx->lock);
|
||||||
|
head = atomic_load_explicit(&ctx->buf_head, memory_order_relaxed);
|
||||||
|
tail = atomic_load_explicit(&ctx->buf_tail, memory_order_relaxed);
|
||||||
|
mask = ctx->buf_mask;
|
||||||
|
capacity = (tail - head - 1) & mask;
|
||||||
|
|
||||||
|
if (len <= capacity) {
|
||||||
|
unsigned int todo;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
todo = len;
|
||||||
|
c = buf;
|
||||||
|
|
||||||
|
while (todo > 0) {
|
||||||
|
ctx->buf[head] = *c;
|
||||||
|
head = (head + 1) & mask;
|
||||||
|
--todo;
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_store_explicit(&ctx->buf_head, head,
|
||||||
|
memory_order_release);
|
||||||
|
} else {
|
||||||
|
/* If it does not fit into the buffer, discard everything */
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_spin_unlock(&ctx->lock);
|
||||||
|
return (int)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
T_vprintf(char const *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (T_is_runner()) {
|
||||||
|
len = T_vprintf_direct(fmt, ap);
|
||||||
|
} else {
|
||||||
|
len = T_vprintf_buffered(fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -604,6 +685,17 @@ T_do_run_initialize(const T_config *config)
|
|||||||
pthread_spin_init(&ctx->lock, PTHREAD_PROCESS_PRIVATE);
|
pthread_spin_init(&ctx->lock, PTHREAD_PROCESS_PRIVATE);
|
||||||
|
|
||||||
ctx->config = config;
|
ctx->config = config;
|
||||||
|
ctx->buf = config->buf;
|
||||||
|
|
||||||
|
if (config->buf_size > 0 &&
|
||||||
|
(config->buf_size & (config->buf_size - 1)) == 0) {
|
||||||
|
ctx->buf_mask = config->buf_size - 1;
|
||||||
|
} else {
|
||||||
|
ctx->buf_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_store_explicit(&ctx->buf_head, 0, memory_order_relaxed);
|
||||||
|
ctx->buf_tail = 0;
|
||||||
ctx->putchar = config->putchar;
|
ctx->putchar = config->putchar;
|
||||||
ctx->putchar_arg = config->putchar_arg;
|
ctx->putchar_arg = config->putchar_arg;
|
||||||
ctx->verbosity = config->verbosity;
|
ctx->verbosity = config->verbosity;
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ now(void)
|
|||||||
return t * SBT_1MS;
|
return t * SBT_1MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char buffer[512];
|
||||||
|
|
||||||
static const T_action actions[] = {
|
static const T_action actions[] = {
|
||||||
T_report_hash_sha256,
|
T_report_hash_sha256,
|
||||||
test_action
|
test_action
|
||||||
@@ -145,6 +147,8 @@ static const T_action actions[] = {
|
|||||||
|
|
||||||
static const T_config config = {
|
static const T_config config = {
|
||||||
.name = "ttest01",
|
.name = "ttest01",
|
||||||
|
.buf = buffer,
|
||||||
|
.buf_size = sizeof(buffer),
|
||||||
.putchar = test_putchar,
|
.putchar = test_putchar,
|
||||||
.putchar_arg = &test_instance,
|
.putchar_arg = &test_instance,
|
||||||
.verbosity = T_VERBOSE,
|
.verbosity = T_VERBOSE,
|
||||||
|
|||||||
Reference in New Issue
Block a user