diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-06-21 06:59:38 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-06-22 07:45:49 +0200 |
commit | 22c3a54b8ba033cd4cfc6aa871b4259719a01a5f (patch) | |
tree | 1f268eb3288d226af01af5307882aa3419330844 /cpukit/libcsupport/src/printertask.c | |
parent | Rename rtems_test_print() into rtems_test_printf() (diff) | |
download | rtems-22c3a54b8ba033cd4cfc6aa871b4259719a01a5f.tar.bz2 |
Add printer task
Diffstat (limited to 'cpukit/libcsupport/src/printertask.c')
-rw-r--r-- | cpukit/libcsupport/src/printertask.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/cpukit/libcsupport/src/printertask.c b/cpukit/libcsupport/src/printertask.c new file mode 100644 index 0000000000..f358f32bb1 --- /dev/null +++ b/cpukit/libcsupport/src/printertask.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/printer.h> + +#include <rtems.h> +#include <rtems/seterr.h> + +#include <unistd.h> + +#define PRINT_TASK_WAKE_UP RTEMS_EVENT_0 + +typedef struct { + rtems_chain_node node; + + enum { + ACTION_WRITE, + ACTION_DRAIN + } action_kind; + + union { + size_t size; + rtems_id task; + } action_data; + + char data[ RTEMS_ZERO_LENGTH_ARRAY ]; +} printer_task_buffer; + +static void printer_task_acquire( + rtems_printer_task_context *ctx, + rtems_interrupt_lock_context *lock_context +) +{ + rtems_interrupt_lock_acquire( &ctx->lock, lock_context ); +} + +static void printer_task_release( + rtems_printer_task_context *ctx, + rtems_interrupt_lock_context *lock_context +) +{ + rtems_interrupt_lock_release( &ctx->lock, lock_context ); +} + +static printer_task_buffer *printer_task_get_buffer( + rtems_printer_task_context *ctx, + rtems_chain_control *chain +) +{ + rtems_interrupt_lock_context lock_context; + printer_task_buffer *buffer; + + printer_task_acquire( ctx, &lock_context ); + buffer = (printer_task_buffer *) rtems_chain_get_unprotected( chain ); + printer_task_release( ctx, &lock_context ); + + return buffer; +} + +static void printer_task_append_buffer( + rtems_printer_task_context *ctx, + rtems_chain_control *chain, + printer_task_buffer *buffer +) +{ + rtems_interrupt_lock_context lock_context; + + printer_task_acquire( ctx, &lock_context ); + rtems_chain_append_unprotected( chain, &buffer->node ); + printer_task_release( ctx, &lock_context ); +} + +static int printer_task_printer( void *context, const char *fmt, va_list ap ) +{ + rtems_printer_task_context *ctx; + printer_task_buffer *buffer; + int n; + + ctx = context; + buffer = printer_task_get_buffer( ctx, &ctx->free_buffers ); + + if ( buffer == NULL ) { + rtems_set_errno_and_return_minus_one( ENOMEM ); + } + + n = vsnprintf( &buffer->data[ 0 ], ctx->buffer_size, fmt, ap ); + + if ( n >= (int) ctx->buffer_size ) { + printer_task_append_buffer( ctx, &ctx->free_buffers, buffer ); + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + buffer->action_kind = ACTION_WRITE; + buffer->action_data.size = (size_t) n; + printer_task_append_buffer( ctx, &ctx->todo_buffers, buffer ); + rtems_event_send( ctx->task, PRINT_TASK_WAKE_UP ); + + return n; +} + +static void printer_task( rtems_task_argument arg ) +{ + rtems_printer_task_context *ctx; + int fd; + + ctx = (rtems_printer_task_context *) arg; + fd = ctx->fd; + + while ( true ) { + rtems_event_set unused; + printer_task_buffer *buffer; + + rtems_event_receive( + PRINT_TASK_WAKE_UP, + RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &unused + ); + + while ( + ( buffer = printer_task_get_buffer( ctx, &ctx->todo_buffers ) ) != NULL + ) { + switch ( buffer->action_kind ) { + case ACTION_WRITE: + write( fd, &buffer->data[ 0 ], buffer->action_data.size ); + printer_task_append_buffer( ctx, &ctx->free_buffers, buffer ); + break; + case ACTION_DRAIN: + fsync(fd); + rtems_event_transient_send( buffer->action_data.task ); + break; + } + } + } +} + +int rtems_print_printer_task( + rtems_printer *printer, + rtems_printer_task_context *ctx +) +{ + rtems_status_code sc; + + if ( ctx->buffer_size < sizeof( printer_task_buffer ) ) { + return EINVAL; + } + + sc = rtems_task_create( + rtems_build_name( 'P', 'R', 'N', 'T'), + ctx->task_priority, + ctx->task_stack_size, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->task + ); + + if ( sc != RTEMS_SUCCESSFUL ) { + return ENOMEM; + } + + rtems_chain_initialize_empty( &ctx->todo_buffers ); + rtems_chain_initialize( + &ctx->free_buffers, + ctx->buffer_table, + ctx->buffer_count, + ctx->buffer_size + ); + ctx->buffer_size -= sizeof( printer_task_buffer ); + + printer->context = ctx; + printer->printer = printer_task_printer; + + rtems_task_start( ctx->task, printer_task, (rtems_task_argument) ctx ); + + return 0; +} + +void rtems_printer_task_drain( rtems_printer_task_context *ctx ) +{ + printer_task_buffer buffer; + + buffer.action_kind = ACTION_DRAIN; + buffer.action_data.task = rtems_task_self(); + + printer_task_append_buffer( ctx, &ctx->todo_buffers, &buffer ); + rtems_event_send( ctx->task, PRINT_TASK_WAKE_UP ); + rtems_event_transient_receive( RTEMS_WAIT, RTEMS_NO_TIMEOUT ); +} |