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