This ensures that lines are output atomically if they are produced by
different other contexts, e.g. interrupts, other processors, other
threads.

Update #3199.
---
 cpukit/include/t.h                 |   2 +
 cpukit/libtest/t-test.c            | 138 ++++++++++++++++++++++++++++++-------
 testsuites/libtests/ttest01/init.c |   4 ++
 3 files changed, 121 insertions(+), 23 deletions(-)

diff --git a/cpukit/include/t.h b/cpukit/include/t.h
index c5e3792ec1..5dbf1e00b5 100644
--- a/cpukit/include/t.h
+++ b/cpukit/include/t.h
@@ -2199,6 +2199,8 @@ typedef void (*T_putchar)(int, void *);
 
 typedef struct {
        const char *name;
+       char *buf;
+       size_t buf_size;
        T_putchar putchar;
        void *putchar_arg;
        T_verbosity verbosity;
diff --git a/cpukit/libtest/t-test.c b/cpukit/libtest/t-test.c
index cf3bcd6a99..881a92efb0 100644
--- a/cpukit/libtest/t-test.c
+++ b/cpukit/libtest/t-test.c
@@ -47,12 +47,16 @@
 #include "t-test-printf.h"
 #endif /* __rtems__ */
 
-#define T_LINE_SIZE 120
+#define T_LINE_SIZE 128
 
 #define T_SCOPE_SIZE 5
 
 typedef struct {
        pthread_spinlock_t lock;
+       char *buf;
+       unsigned int buf_mask;
+       atomic_uint buf_head;
+       atomic_uint buf_tail;
        void (*putchar)(int, void *);
        void *putchar_arg;
        T_verbosity verbosity;
@@ -81,18 +85,6 @@ typedef struct {
 
 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 {
        char *s;
        size_t n;
@@ -101,13 +93,13 @@ typedef struct {
 static void
 T_putchar_string(int c, void *arg)
 {
-       T_putchar_string_context *ctx;
+       T_putchar_string_context *sctx;
        char *s;
        size_t n;
 
-       ctx = arg;
-       s = ctx->s;
-       n = ctx->n;
+       sctx = arg;
+       s = sctx->s;
+       n = sctx->n;
 
        if (n == 1) {
                c = '\0';
@@ -119,8 +111,8 @@ T_putchar_string(int c, void *arg)
                --n;
        }
 
-       ctx->s = s;
-       ctx->n = n;
+       sctx->s = s;
+       sctx->n = n;
 }
 
 int
@@ -128,17 +120,106 @@ T_snprintf(char *s, size_t n, char const *fmt, ...)
 {
        va_list ap;
        int len;
-       T_putchar_string_context ctx = {
+       T_putchar_string_context sctx = {
                .s = s,
                .n = n
        };
 
        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);
 
-       if (ctx.n > 0) {
-               *ctx.s = '\0';
+       if (sctx.n > 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;
@@ -604,6 +685,17 @@ T_do_run_initialize(const T_config *config)
        pthread_spin_init(&ctx->lock, PTHREAD_PROCESS_PRIVATE);
 
        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_arg = config->putchar_arg;
        ctx->verbosity = config->verbosity;
diff --git a/testsuites/libtests/ttest01/init.c 
b/testsuites/libtests/ttest01/init.c
index 51cfa8badb..135dc2b25e 100644
--- a/testsuites/libtests/ttest01/init.c
+++ b/testsuites/libtests/ttest01/init.c
@@ -138,6 +138,8 @@ now(void)
        return t * SBT_1MS;
 }
 
+static char buffer[512];
+
 static const T_action actions[] = {
        T_report_hash_sha256,
        test_action
@@ -145,6 +147,8 @@ static const T_action actions[] = {
 
 static const T_config config = {
        .name = "ttest01",
+       .buf = buffer,
+       .buf_size = sizeof(buffer),
        .putchar = test_putchar,
        .putchar_arg = &test_instance,
        .verbosity = T_VERBOSE,
-- 
2.16.4

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to