Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2016 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
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 }