summaryrefslogtreecommitdiffstats
path: root/cpukit/libcsupport/src/printertask.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libcsupport/src/printertask.c')
-rw-r--r--cpukit/libcsupport/src/printertask.c203
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 );
+}