File indexing completed on 2025-05-11 08:24:21
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/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 }