[rtems commit] Add printer task

Sebastian Huber sebh at rtems.org
Wed Jun 22 05:46:10 UTC 2016


Module:    rtems
Branch:    master
Commit:    22c3a54b8ba033cd4cfc6aa871b4259719a01a5f
Changeset: http://git.rtems.org/rtems/commit/?id=22c3a54b8ba033cd4cfc6aa871b4259719a01a5f

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Jun 21 06:59:38 2016 +0200

Add printer task

---

 cpukit/include/rtems/printer.h       | 106 ++++++++++++++++++
 cpukit/libcsupport/Makefile.am       |   1 +
 cpukit/libcsupport/src/printertask.c | 203 +++++++++++++++++++++++++++++++++++
 3 files changed, 310 insertions(+)

diff --git a/cpukit/include/rtems/printer.h b/cpukit/include/rtems/printer.h
index 2ed6b6a..28b0b25 100644
--- a/cpukit/include/rtems/printer.h
+++ b/cpukit/include/rtems/printer.h
@@ -19,6 +19,9 @@
 #define _RTEMS_PRINTER_H
 
 #include <rtems/print.h>
+#include <rtems/chain.h>
+#include <rtems/rtems/intr.h>
+#include <rtems/rtems/tasks.h>
 
 #include <stdio.h>
 
@@ -110,6 +113,109 @@ extern void rtems_print_printer_printf(rtems_printer *printer);
  */
 extern void rtems_print_printer_fprintf(rtems_printer *printer, FILE *file);
 
+typedef struct {
+  rtems_id                     task;
+  RTEMS_INTERRUPT_LOCK_MEMBER( lock )
+  rtems_chain_control          free_buffers;
+  rtems_chain_control          todo_buffers;
+  size_t                       task_stack_size;
+  rtems_task_priority          task_priority;
+  int                          fd;
+  void                        *buffer_table;
+  size_t                       buffer_count;
+  size_t                       buffer_size;
+} rtems_printer_task_context;
+
+static inline void rtems_printer_task_initialize(
+  rtems_printer_task_context *context
+)
+{
+  memset( context, 0, sizeof( *context ) );
+}
+
+static inline void rtems_printer_task_set_stack_size(
+  rtems_printer_task_context *context,
+  size_t                    stack_size
+)
+{
+  context->task_stack_size = stack_size;
+}
+
+static inline void rtems_printer_task_set_priority(
+  rtems_printer_task_context *context,
+  rtems_task_priority       priority
+)
+{
+  context->task_priority = priority;
+}
+
+static inline void rtems_printer_task_set_file_descriptor(
+  rtems_printer_task_context *context,
+  int                       fd
+)
+{
+  context->fd = fd;
+}
+
+static inline void rtems_printer_task_set_buffer_table(
+  rtems_printer_task_context *context,
+  void                     *buffer_table
+)
+{
+  context->buffer_table = buffer_table;
+}
+
+static inline void rtems_printer_task_set_buffer_count(
+  rtems_printer_task_context *context,
+  size_t                    buffer_count
+)
+{
+  context->buffer_count = buffer_count;
+}
+
+static inline void rtems_printer_task_set_buffer_size(
+  rtems_printer_task_context *context,
+  size_t                    buffer_size
+)
+{
+  context->buffer_size = buffer_size;
+}
+
+/**
+ * @brief Creates a printer task.
+ *
+ * Print requests via rtems_printf() or rtems_vprintf() using a printer task
+ * printer are output to a buffer and then placed on a work queue in FIFO
+ * order.  The work queue is emptied by the printer task.  The printer task
+ * writes the buffer content to the file descriptor specified by the context.
+ * Buffers are allocated from a pool of buffers as specified by the context.
+ *
+ * @param[in] printer Pointer to the printer structure.
+ * @param[in] context The initialized printer task context.
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Invalid context parameters.
+ * @retval ENOMEM Not enough resources.
+ */
+int rtems_print_printer_task(
+  rtems_printer              *printer,
+  rtems_printer_task_context *context
+);
+
+/**
+ * @brief Drains the work queue of the printer task.
+ *
+ * Waits until all output buffers in the work queue at the time of this
+ * function call are written to the file descriptor and an fsync() completed.
+ *
+ * The printer task must be successfully started via rtems_print_printer_task()
+ * before this function can be used.  Otherwise, the behaviour is undefined.
+ *
+ * @param[in] context The printer task context of a successfully started
+ *   printer task.
+ */
+void rtems_printer_task_drain(rtems_printer_task_context *context);
+
 /** @} */
 
 #ifdef __cplusplus
diff --git a/cpukit/libcsupport/Makefile.am b/cpukit/libcsupport/Makefile.am
index f047cfc..99dc2e1 100644
--- a/cpukit/libcsupport/Makefile.am
+++ b/cpukit/libcsupport/Makefile.am
@@ -128,6 +128,7 @@ libcsupport_a_SOURCES = src/gxx_wrappers.c src/getchark.c src/printk.c \
     src/resource_snapshot.c \
     $(BSD_LIBC_C_FILES) $(BASE_FS_C_FILES) $(MALLOC_C_FILES) \
     $(ERROR_C_FILES) $(ASSOCIATION_C_FILES)
+libcsupport_a_SOURCES += src/printertask.c
 
 libcsupport_a_SOURCES += $(LIBC_GLUE_C_FILES) $(PASSWORD_GROUP_C_FILES) \
     $(TERMINAL_IDENTIFICATION_C_FILES) $(SYSTEM_CALL_C_FILES) \
diff --git a/cpukit/libcsupport/src/printertask.c b/cpukit/libcsupport/src/printertask.c
new file mode 100644
index 0000000..f358f32
--- /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 at 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 );
+}



More information about the vc mailing list