Hi,

I would like to better integrate rtdk and the posix skin by forcibly 
wrapping the calls to malloc/free and also wrap printf to call 
rt_printf.

However, currently, rt_printf can not really be used as a drop-in 
replacement of printf:
- it is necessary to call rt_printf_auto_init, we can do it in the 
library init code;
- the first rt_printf causes a memory allocation, so a potential switch 
to secondary mode, which is what using rt_printf was trying to avoid in
the first place.

In order to solve this second issue, and to avoid forcibly creating a 
buffer for each thread, which would be wasteful, here is a patch, which, 
following an idea of Philippe, creates a pool of pre-allocated buffers. 
The pool is handled in a lockless fashion, using xnarch_atomic_cmpxchg 
(so, will only work with CONFIG_XENO_FASTSYNCH).

diff --git a/src/rtdk/rt_print.c b/src/rtdk/rt_print.c
index 93b711a..2ed2209 100644
--- a/src/rtdk/rt_print.c
+++ b/src/rtdk/rt_print.c
@@ -30,6 +30,8 @@
 #include <rtdk.h>
 #include <asm/xenomai/system.h>
 #include <asm-generic/stack.h>
+#include <asm/xenomai/atomic.h>
+#include <asm-generic/bits/current.h>
 
 #define RT_PRINT_BUFFER_ENV            "RT_PRINT_BUFFER"
 #define RT_PRINT_DEFAULT_BUFFER                16*1024
@@ -37,6 +39,9 @@
 #define RT_PRINT_PERIOD_ENV            "RT_PRINT_PERIOD"
 #define RT_PRINT_DEFAULT_PERIOD                100 /* ms */
 
+#define RT_PRINT_BUFFERS_COUNT_ENV      "RT_PRINT_BUFFERS_COUNT"
+#define RT_PRINT_DEFAULT_BUFFERS_COUNT  4
+
 #define RT_PRINT_LINE_BREAK            256
 
 #define RT_PRINT_SYSLOG_STREAM         NULL
@@ -63,6 +68,9 @@ struct print_buffer {
         * caching on SMP.
         */
        off_t read_pos;
+#ifdef CONFIG_XENO_FASTSYNCH
+       struct print_buffer *pool_next;
+#endif /* CONFIG_XENO_FASTSYNCH */
 };
 
 static struct print_buffer *first_buffer;
@@ -75,6 +83,17 @@ static pthread_mutex_t buffer_lock;
 static pthread_cond_t printer_wakeup;
 static pthread_key_t buffer_key;
 static pthread_t printer_thread;
+#ifdef CONFIG_XENO_FASTSYNCH
+static xnarch_atomic_t buffer_pool;
+static unsigned pool_capacity;
+static xnarch_atomic_t pool_count;
+
+#define buf_pool_set(buf) xnarch_atomic_set(&buffer_pool, (unsigned long)buf)
+#define buf_pool_get() (struct print_buffer *)xnarch_atomic_get(&buffer_pool)
+#define buf_pool_cmpxchg(oldval, newval) \
+       ((struct print_buffer *)xnarch_atomic_cmpxchg                   \
+        (&buffer_pool, (unsigned long)oldval, (unsigned long)newval))
+#endif /* CONFIG_XENO_FASTSYNCH */
 
 static void cleanup_buffer(struct print_buffer *buffer);
 static void print_buffers(void);
@@ -243,43 +262,28 @@ static void set_buffer_name(struct print_buffer *buffer, 
const char *name)
        }
 }
 
-int rt_print_init(size_t buffer_size, const char *buffer_name)
+static struct print_buffer *rt_print_init_inner(size_t size)
 {
-       struct print_buffer *buffer = pthread_getspecific(buffer_key);
-       size_t size = buffer_size;
-
-       if (!size)
-               size = default_buffer_size;
-       else if (size < RT_PRINT_LINE_BREAK)
-               return EINVAL;
+       struct print_buffer *buffer;
 
-       if (buffer) {
-               /* Only set name if buffer size is unchanged or default */
-               if (size == buffer->size || !buffer_size) {
-                       set_buffer_name(buffer, buffer_name);
-                       return 0;
-               }
-               cleanup_buffer(buffer);
-       }
+       assert_nrt();
 
        buffer = malloc(sizeof(*buffer));
        if (!buffer)
-               return ENOMEM;
+               return NULL;
 
        buffer->ring = malloc(size);
        if (!buffer->ring) {
                free(buffer);
-               return ENOMEM;
+               return NULL;
        }
+       buffer->size = size;
+
        memset(buffer->ring, 0, size);
 
        buffer->read_pos  = 0;
        buffer->write_pos = 0;
 
-       buffer->size = size;
-
-       set_buffer_name(buffer, buffer_name);
-
        buffer->prev = NULL;
 
        pthread_mutex_lock(&buffer_lock);
@@ -294,6 +298,52 @@ int rt_print_init(size_t buffer_size, const char 
*buffer_name)
 
        pthread_mutex_unlock(&buffer_lock);
 
+       return buffer;
+}
+
+int rt_print_init(size_t buffer_size, const char *buffer_name)
+{
+       struct print_buffer *buffer = pthread_getspecific(buffer_key);
+       size_t size = buffer_size;
+
+       if (!size)
+               size = default_buffer_size;
+       else if (size < RT_PRINT_LINE_BREAK)
+               return EINVAL;
+
+       if (buffer) {
+               /* Only set name if buffer size is unchanged or default */
+               if (size == buffer->size || !buffer_size) {
+                       set_buffer_name(buffer, buffer_name);
+                       return 0;
+               }
+               cleanup_buffer(buffer);
+               buffer = NULL;
+       }
+
+#ifdef CONFIG_XENO_FASTSYNCH
+       if (xeno_get_current() != XN_NO_HANDLE &&
+           !(xeno_get_current_mode() & XNRELAX) && buf_pool_get()) {
+               struct print_buffer *old;
+
+               old = buf_pool_get();
+               while (old != buffer) {
+                       buffer = old;
+                       old = buf_pool_cmpxchg(buffer, buffer->pool_next);
+               }
+               if (buffer)
+                       xnarch_atomic_dec(&pool_count);
+       }
+#endif /* CONFIG_XENO_FASTSYNCH */
+
+       if (!buffer)
+               buffer = rt_print_init_inner(size);
+
+       if (!buffer)
+               return ENOMEM;
+
+       set_buffer_name(buffer, buffer_name);
+
        pthread_setspecific(buffer_key, buffer);
 
        return 0;
@@ -346,12 +396,36 @@ static void cleanup_buffer(struct print_buffer *buffer)
 {
        struct print_buffer *prev, *next;
 
+       assert_nrt();
+
        pthread_setspecific(buffer_key, NULL);
 
        pthread_mutex_lock(&buffer_lock);
 
        print_buffers();
 
+       pthread_mutex_unlock(&buffer_lock);
+
+#ifdef CONFIG_XENO_FASTSYNCH
+       {
+               struct print_buffer *old;
+
+               old = buf_pool_get();
+               buffer->pool_next = buffer;
+               while (old != buffer->next
+                      && xnarch_atomic_get(&pool_count) < pool_capacity) {
+                       buffer->next = old;
+                       old = buf_pool_cmpxchg(buffer->pool_next, buffer);
+               }
+               if (old == buffer->pool_next) {
+                       xnarch_atomic_inc(&pool_count);
+                       return;
+               }
+       }
+#endif /* CONFIG_XENO_FASTSYNCH */
+
+       pthread_mutex_lock(&buffer_lock);
+
        prev = buffer->prev;
        next = buffer->next;
 
@@ -523,6 +597,39 @@ void __rt_print_init(void)
        print_period.tv_sec  = period / 1000;
        print_period.tv_nsec = (period % 1000) * 1000000;
 
+#ifdef CONFIG_XENO_FASTSYNCH
+       {
+               unsigned i;
+
+               pool_capacity = RT_PRINT_DEFAULT_BUFFERS_COUNT;
+
+               value_str = getenv(RT_PRINT_BUFFERS_COUNT_ENV);
+               if (value_str) {
+                       errno = 0;
+                       pool_capacity = strtoul(value_str, NULL, 0);
+                       if (errno) {
+                               fprintf(stderr, "Invalid %s\n",
+                                       RT_PRINT_BUFFERS_COUNT_ENV);
+                               exit(1);
+                       }
+               }
+               for (i = 0; i < pool_capacity; i++) {
+                       struct print_buffer *buffer;
+
+                       buffer = rt_print_init_inner(default_buffer_size);
+                       if (!buffer) {
+                               fprintf(stderr, "Error allocating rt_printf "
+                                       "buffer\n");
+                               exit(1);
+                       }
+
+                       buffer->pool_next = buf_pool_get();
+                       buf_pool_set(buffer);
+               }
+               xnarch_atomic_set(&pool_count, pool_capacity);
+       }
+#endif /* CONFIG_XENO_FASTSYNCH */
+
        pthread_mutex_init(&buffer_lock, NULL);
        pthread_key_create(&buffer_key, (void (*)(void*))cleanup_buffer);
 


-- 
                                                                Gilles.

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to