forked from Imagelibrary/rtems
Add printer task
This commit is contained in:
@@ -19,6 +19,9 @@
|
|||||||
#define _RTEMS_PRINTER_H
|
#define _RTEMS_PRINTER_H
|
||||||
|
|
||||||
#include <rtems/print.h>
|
#include <rtems/print.h>
|
||||||
|
#include <rtems/chain.h>
|
||||||
|
#include <rtems/rtems/intr.h>
|
||||||
|
#include <rtems/rtems/tasks.h>
|
||||||
|
|
||||||
#include <stdio.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);
|
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
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ libcsupport_a_SOURCES = src/gxx_wrappers.c src/getchark.c src/printk.c \
|
|||||||
src/resource_snapshot.c \
|
src/resource_snapshot.c \
|
||||||
$(BSD_LIBC_C_FILES) $(BASE_FS_C_FILES) $(MALLOC_C_FILES) \
|
$(BSD_LIBC_C_FILES) $(BASE_FS_C_FILES) $(MALLOC_C_FILES) \
|
||||||
$(ERROR_C_FILES) $(ASSOCIATION_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) \
|
libcsupport_a_SOURCES += $(LIBC_GLUE_C_FILES) $(PASSWORD_GROUP_C_FILES) \
|
||||||
$(TERMINAL_IDENTIFICATION_C_FILES) $(SYSTEM_CALL_C_FILES) \
|
$(TERMINAL_IDENTIFICATION_C_FILES) $(SYSTEM_CALL_C_FILES) \
|
||||||
|
|||||||
203
cpukit/libcsupport/src/printertask.c
Normal file
203
cpukit/libcsupport/src/printertask.c
Normal file
@@ -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 );
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user