Back to home page

LXR

 
 

    


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

0001 /*
0002  * SPDX-License-Identifier: BSD-2-Clause
0003  *
0004  * Copyright (C) 2018, 2024 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/recordserver.h>
0033 #include <rtems/record.h>
0034 #include <rtems/score/threadimpl.h>
0035 
0036 #include <sys/socket.h>
0037 #include <sys/uio.h>
0038 
0039 #include <stdlib.h>
0040 #include <string.h>
0041 #include <unistd.h>
0042 
0043 #include <netinet/in.h>
0044 
0045 #define WAKEUP_EVENT RTEMS_EVENT_0
0046 
0047 static void wakeup( rtems_id task )
0048 {
0049   (void) rtems_event_send( task, WAKEUP_EVENT );
0050 }
0051 
0052 static void wait( rtems_option options )
0053 {
0054   rtems_event_set events;
0055 
0056   (void) rtems_event_receive(
0057     WAKEUP_EVENT,
0058     RTEMS_EVENT_ANY | options,
0059     RTEMS_NO_TIMEOUT,
0060     &events
0061   );
0062 }
0063 
0064 static void wakeup_timer( rtems_id timer, void *arg )
0065 {
0066   rtems_id *server;
0067 
0068   server = arg;
0069   wakeup( *server );
0070   (void) rtems_timer_reset( timer );
0071 }
0072 
0073 static void send_header( int fd )
0074 {
0075   Record_Stream_header header;
0076   size_t               size;
0077 
0078   size = _Record_Stream_header_initialize( &header );
0079   (void) write( fd, &header, size );
0080 }
0081 
0082 typedef struct {
0083   int fd;
0084   size_t index;
0085   rtems_record_item items[ 128 ];
0086 } thread_names_context;
0087 
0088 static void thread_names_produce(
0089   thread_names_context *ctx,
0090   rtems_record_event    event,
0091   rtems_record_data     data
0092 )
0093 {
0094   size_t i;
0095 
0096   i = ctx->index;
0097   ctx->items[ i ].event = RTEMS_RECORD_TIME_EVENT( 0, event );
0098   ctx->items[ i ].data = data;
0099 
0100   if (i == RTEMS_ARRAY_SIZE(ctx->items) - 1) {
0101     ctx->index = 0;
0102     (void) write( ctx->fd, ctx->items, sizeof( ctx->items ) );
0103   } else {
0104     ctx->index = i + 1;
0105   }
0106 }
0107 
0108 static bool thread_names_visitor( rtems_tcb *tcb, void *arg )
0109 {
0110   thread_names_context *ctx;
0111   char                  name[ 2 * THREAD_DEFAULT_MAXIMUM_NAME_SIZE ];
0112   size_t                n;
0113   size_t                i;
0114   rtems_record_data     data;
0115 
0116   ctx = arg;
0117   thread_names_produce( ctx, RTEMS_RECORD_THREAD_ID, tcb->Object.id );
0118   n = _Thread_Get_name( tcb, name, sizeof( name ) );
0119   i = 0;
0120 
0121   while ( i < n ) {
0122     size_t j;
0123 
0124     data = 0;
0125 
0126     for ( j = 0; i < n && j < sizeof( data ); ++j ) {
0127       rtems_record_data c;
0128 
0129       c = (unsigned char) name[ i ];
0130       data |= c << ( j * 8 );
0131       ++i;
0132     }
0133 
0134     thread_names_produce( ctx, RTEMS_RECORD_THREAD_NAME, data );
0135   }
0136 
0137   return false;
0138 }
0139 
0140 static void send_thread_names( int fd )
0141 {
0142   thread_names_context ctx;
0143 
0144   ctx.fd = fd;
0145   ctx.index = 0;
0146   rtems_task_iterate( thread_names_visitor, &ctx );
0147 
0148   if ( ctx.index > 0 ) {
0149     (void) write( ctx.fd, ctx.items, ctx.index * sizeof( ctx.items[ 0 ] ) );
0150   }
0151 }
0152 
0153 static void fetch_and_write(
0154   int fd,
0155   rtems_record_item *items,
0156   size_t count
0157 )
0158 {
0159   rtems_record_fetch_control control;
0160 
0161   rtems_record_fetch_initialize( &control, items, count );
0162 
0163   while ( true ) {
0164     rtems_record_fetch_status status;
0165 
0166     do {
0167       ssize_t n;
0168 
0169       status = rtems_record_fetch( &control );
0170       n = write(
0171         fd,
0172         control.fetched_items,
0173         control.fetched_count * sizeof( *control.fetched_items )
0174       );
0175 
0176       if ( n <= 0 ) {
0177         return;
0178       }
0179     } while ( status == RTEMS_RECORD_FETCH_CONTINUE );
0180 
0181     wait( RTEMS_WAIT );
0182   }
0183 }
0184 
0185 void rtems_record_server( uint16_t port, rtems_interval period )
0186 {
0187   rtems_status_code sc;
0188   rtems_id self;
0189   rtems_id timer;
0190   struct sockaddr_in addr;
0191   int sd;
0192   int rv;
0193   size_t count;
0194   rtems_record_item *items;
0195 
0196   self = rtems_task_self();
0197 
0198   count = rtems_record_get_item_count_for_fetch();
0199   items = calloc( count, sizeof( *items ) );
0200   if ( items == NULL ) {
0201     return;
0202   }
0203 
0204   sc = rtems_timer_create( rtems_build_name( 'R', 'C', 'R', 'D' ), &timer );
0205   if ( sc != RTEMS_SUCCESSFUL ) {
0206     goto timer_error;
0207   }
0208 
0209   sd = socket( PF_INET, SOCK_STREAM, 0 );
0210   if (sd < 0) {
0211     goto socket_error;
0212   }
0213 
0214   memset( &addr, 0, sizeof( addr ) );
0215   addr.sin_family = AF_INET;
0216   addr.sin_port = htons( port );
0217   addr.sin_addr.s_addr = htonl( INADDR_ANY );
0218 
0219   rv = bind( sd, (const struct sockaddr *) &addr, sizeof( addr ) );
0220   if (rv != 0) {
0221     goto error;
0222   }
0223 
0224   rv = listen( sd, 0 );
0225   if (rv != 0) {
0226     goto error;
0227   }
0228 
0229   while ( true ) {
0230     int cd;
0231 
0232     cd = accept( sd, NULL, NULL );
0233 
0234     if ( cd < 0 ) {
0235       break;
0236     }
0237 
0238     wait( RTEMS_NO_WAIT );
0239     (void) rtems_timer_fire_after( timer, period, wakeup_timer, &self );
0240     send_header( cd );
0241     send_thread_names( cd );
0242     fetch_and_write( cd, items, count );
0243     (void) rtems_timer_cancel( timer );
0244     (void) close( cd );
0245   }
0246 
0247 error:
0248 
0249   (void) close( sd );
0250 
0251 socket_error:
0252 
0253   (void) rtems_timer_delete( timer );
0254 
0255 timer_error:
0256 
0257   free( items );
0258 }
0259 
0260 typedef struct {
0261   rtems_id       task;
0262   uint16_t       port;
0263   rtems_interval period;
0264 } server_arg;
0265 
0266 static void server( rtems_task_argument arg )
0267 {
0268   server_arg     *sarg;
0269   uint16_t        port;
0270   rtems_interval  period;
0271 
0272   sarg = (server_arg *) arg;
0273   port = sarg->port;
0274   period = sarg->period;
0275   wakeup(sarg->task);
0276   rtems_record_server( port, period );
0277   rtems_task_exit();
0278 }
0279 
0280 rtems_status_code rtems_record_start_server(
0281   rtems_task_priority priority,
0282   uint16_t            port,
0283   rtems_interval      period
0284 )
0285 {
0286   rtems_status_code sc;
0287   rtems_id          id;
0288   server_arg        sarg;
0289 
0290   sarg.port = port;
0291   sarg.period = period;
0292   sarg.task = rtems_task_self();
0293 
0294   sc = rtems_task_create(
0295     rtems_build_name( 'R', 'C', 'R', 'D' ),
0296     priority,
0297     RTEMS_MINIMUM_STACK_SIZE,
0298     RTEMS_DEFAULT_MODES,
0299     RTEMS_DEFAULT_ATTRIBUTES,
0300     &id
0301   );
0302   if ( sc != RTEMS_SUCCESSFUL ) {
0303     return sc;
0304   }
0305 
0306   (void) rtems_task_start( id, server, (rtems_task_argument) &sarg );
0307   wait( RTEMS_WAIT );
0308 
0309   return RTEMS_SUCCESSFUL;
0310 }