File indexing completed on 2025-05-11 08:24:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031
0032 #include <rtems/printer.h>
0033
0034 #include <rtems.h>
0035 #include <rtems/seterr.h>
0036
0037 #include <unistd.h>
0038
0039 #define PRINT_TASK_WAKE_UP RTEMS_EVENT_0
0040
0041 typedef struct {
0042 rtems_chain_node node;
0043
0044 enum {
0045 ACTION_WRITE,
0046 ACTION_DRAIN
0047 } action_kind;
0048
0049 union {
0050 size_t size;
0051 rtems_id task;
0052 } action_data;
0053
0054 char data[ RTEMS_ZERO_LENGTH_ARRAY ];
0055 } printer_task_buffer;
0056
0057 static void printer_task_acquire(
0058 rtems_printer_task_context *ctx,
0059 rtems_interrupt_lock_context *lock_context
0060 )
0061 {
0062 rtems_interrupt_lock_acquire( &ctx->lock, lock_context );
0063 }
0064
0065 static void printer_task_release(
0066 rtems_printer_task_context *ctx,
0067 rtems_interrupt_lock_context *lock_context
0068 )
0069 {
0070 rtems_interrupt_lock_release( &ctx->lock, lock_context );
0071 }
0072
0073 static printer_task_buffer *printer_task_get_buffer(
0074 rtems_printer_task_context *ctx,
0075 rtems_chain_control *chain
0076 )
0077 {
0078 rtems_interrupt_lock_context lock_context;
0079 printer_task_buffer *buffer;
0080
0081 printer_task_acquire( ctx, &lock_context );
0082 buffer = (printer_task_buffer *) rtems_chain_get_unprotected( chain );
0083 printer_task_release( ctx, &lock_context );
0084
0085 return buffer;
0086 }
0087
0088 static void printer_task_append_buffer(
0089 rtems_printer_task_context *ctx,
0090 rtems_chain_control *chain,
0091 printer_task_buffer *buffer
0092 )
0093 {
0094 rtems_interrupt_lock_context lock_context;
0095
0096 printer_task_acquire( ctx, &lock_context );
0097 rtems_chain_append_unprotected( chain, &buffer->node );
0098 printer_task_release( ctx, &lock_context );
0099 }
0100
0101 static int printer_task_printer( void *context, const char *fmt, va_list ap )
0102 {
0103 rtems_printer_task_context *ctx;
0104 printer_task_buffer *buffer;
0105 int n;
0106
0107 ctx = context;
0108 buffer = printer_task_get_buffer( ctx, &ctx->free_buffers );
0109
0110 if ( buffer == NULL ) {
0111 rtems_set_errno_and_return_minus_one( ENOMEM );
0112 }
0113
0114 n = vsnprintf( &buffer->data[ 0 ], ctx->buffer_size, fmt, ap );
0115
0116 if ( n >= (int) ctx->buffer_size ) {
0117 printer_task_append_buffer( ctx, &ctx->free_buffers, buffer );
0118 rtems_set_errno_and_return_minus_one( EINVAL );
0119 }
0120
0121 buffer->action_kind = ACTION_WRITE;
0122 buffer->action_data.size = (size_t) n;
0123 printer_task_append_buffer( ctx, &ctx->todo_buffers, buffer );
0124 rtems_event_send( ctx->task, PRINT_TASK_WAKE_UP );
0125
0126 return n;
0127 }
0128
0129 static void printer_task( rtems_task_argument arg )
0130 {
0131 rtems_printer_task_context *ctx;
0132 int fd;
0133 int err;
0134 rtems_status_code sc;
0135
0136 ctx = (rtems_printer_task_context *) arg;
0137 fd = ctx->fd;
0138
0139 while ( true ) {
0140 rtems_event_set unused;
0141 printer_task_buffer *buffer;
0142
0143 rtems_event_receive(
0144 PRINT_TASK_WAKE_UP,
0145 RTEMS_EVENT_ALL | RTEMS_WAIT,
0146 RTEMS_NO_TIMEOUT,
0147 &unused
0148 );
0149
0150 while (
0151 ( buffer = printer_task_get_buffer( ctx, &ctx->todo_buffers ) ) != NULL
0152 ) {
0153 switch ( buffer->action_kind ) {
0154 case ACTION_WRITE:
0155 write( fd, &buffer->data[ 0 ], buffer->action_data.size );
0156 printer_task_append_buffer( ctx, &ctx->free_buffers, buffer );
0157 break;
0158 case ACTION_DRAIN:
0159 err = fsync(fd);
0160 _Assert_Unused_variable_equals(err, 0);
0161 sc = rtems_event_transient_send( buffer->action_data.task );
0162 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0163 break;
0164 }
0165 }
0166 }
0167 }
0168
0169 int rtems_print_printer_task(
0170 rtems_printer *printer,
0171 rtems_printer_task_context *ctx
0172 )
0173 {
0174 rtems_status_code sc;
0175
0176 if ( ctx->buffer_size < sizeof( printer_task_buffer ) ) {
0177 return EINVAL;
0178 }
0179
0180 sc = rtems_task_create(
0181 rtems_build_name( 'P', 'R', 'N', 'T'),
0182 ctx->task_priority,
0183 ctx->task_stack_size,
0184 RTEMS_DEFAULT_MODES,
0185 RTEMS_DEFAULT_ATTRIBUTES,
0186 &ctx->task
0187 );
0188
0189 if ( sc != RTEMS_SUCCESSFUL ) {
0190 return ENOMEM;
0191 }
0192
0193 rtems_chain_initialize_empty( &ctx->todo_buffers );
0194 rtems_chain_initialize(
0195 &ctx->free_buffers,
0196 ctx->buffer_table,
0197 ctx->buffer_count,
0198 ctx->buffer_size
0199 );
0200 ctx->buffer_size -= sizeof( printer_task_buffer );
0201
0202 printer->context = ctx;
0203 printer->printer = printer_task_printer;
0204
0205 sc = rtems_task_start( ctx->task, printer_task, (rtems_task_argument) ctx );
0206 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0207
0208 return 0;
0209 }
0210
0211 void rtems_printer_task_drain( rtems_printer_task_context *ctx )
0212 {
0213 printer_task_buffer buffer;
0214
0215 rtems_chain_initialize_node( &buffer.node );
0216 buffer.action_kind = ACTION_DRAIN;
0217 buffer.action_data.task = rtems_task_self();
0218
0219 printer_task_append_buffer( ctx, &ctx->todo_buffers, &buffer );
0220 rtems_event_send( ctx->task, PRINT_TASK_WAKE_UP );
0221 rtems_event_transient_receive( RTEMS_WAIT, RTEMS_NO_TIMEOUT );
0222 }