source: rtems/cpukit/libtrace/record/record-server.c @ d91951fb

5
Last change on this file since d91951fb was d91951fb, checked in by Sebastian Huber <sebastian.huber@…>, on 03/12/19 at 07:15:19

record: Rename internal per-CPU events

Update #3665.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2018, 2019 embedded brains GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#if HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <rtems/record.h>
33#include <rtems.h>
34
35#include <sys/endian.h>
36#include <sys/socket.h>
37#include <sys/uio.h>
38
39#include <string.h>
40#include <unistd.h>
41
42#include <netinet/in.h>
43
44#ifdef RTEMS_SMP
45#define CHUNKS (3 * CPU_MAXIMUM_PROCESSORS)
46#else
47#define CHUNKS 4
48#endif
49
50typedef struct {
51  int           available;
52  struct iovec *current;
53  struct iovec  iov[CHUNKS];
54} writev_visitor_context;
55
56static void writev_visitor(
57  const rtems_record_item *items,
58  size_t                   count,
59  void                    *arg
60)
61{
62  writev_visitor_context *ctx;
63
64  ctx = arg;
65
66  if ( ctx->available > 0 ) {
67    ctx->current->iov_base = RTEMS_DECONST( rtems_record_item *, items );
68    ctx->current->iov_len = count * sizeof( *items );
69    --ctx->available;
70    ++ctx->current;
71  }
72}
73
74ssize_t rtems_record_writev( int fd, bool *written )
75{
76  writev_visitor_context ctx;
77  int n;
78
79  ctx.available = CHUNKS;
80  ctx.current = &ctx.iov[ 0 ];
81  rtems_record_drain( writev_visitor, &ctx );
82  n = CHUNKS - ctx.available;
83
84  if ( n > 0 ) {
85    *written = true;
86    return writev( fd, &ctx.iov[ 0 ], n );
87  } else {
88    *written = false;
89    return 0;
90  }
91}
92
93#define WAKEUP_EVENT RTEMS_EVENT_0
94
95static void wakeup( rtems_id task )
96{
97  (void) rtems_event_send( task, WAKEUP_EVENT );
98}
99
100static void wait( rtems_option options )
101{
102  rtems_event_set events;
103
104  (void) rtems_event_receive(
105    WAKEUP_EVENT,
106    RTEMS_EVENT_ANY | options,
107    RTEMS_NO_TIMEOUT,
108    &events
109  );
110}
111
112static void wakeup_timer( rtems_id timer, void *arg )
113{
114  rtems_id *server;
115
116  server = arg;
117  wakeup( *server );
118  (void) rtems_timer_reset( timer );
119}
120
121void _Record_Stream_header_initialize( Record_Stream_header *header )
122{
123#if BYTE_ORDER == LITTLE_ENDIAN
124#if __INTPTR_WIDTH__ == 32
125  header->format = RTEMS_RECORD_FORMAT_LE_32,
126#elif __INTPTR_WIDTH__ == 64
127  header->format = RTEMS_RECORD_FORMAT_LE_64,
128#else
129#error "unexpected __INTPTR_WIDTH__"
130#endif
131#elif BYTE_ORDER == BIG_ENDIAN
132#if __INTPTR_WIDTH__ == 32
133  header->format = RTEMS_RECORD_FORMAT_BE_32,
134#elif __INTPTR_WIDTH__ == 64
135  header->format = RTEMS_RECORD_FORMAT_BE_64,
136#else
137#error "unexpected __INTPTR_WIDTH__"
138#endif
139#else
140#error "unexpected BYTE_ORDER"
141#endif
142
143  header->magic = RTEMS_RECORD_MAGIC;
144
145  header->Version.event = RTEMS_RECORD_TIME_EVENT( 0, RTEMS_RECORD_VERSION );
146  header->Version.data = RTEMS_RECORD_THE_VERSION;
147
148  header->Processor_maximum.event =
149    RTEMS_RECORD_TIME_EVENT( 0, RTEMS_RECORD_PROCESSOR_MAXIMUM );
150  header->Processor_maximum.data = rtems_get_processor_count() - 1;
151
152  header->Count.event = RTEMS_RECORD_TIME_EVENT( 0, RTEMS_RECORD_PER_CPU_COUNT );
153  header->Count.data = _Record_Item_count;
154
155  header->Frequency.event =
156    RTEMS_RECORD_TIME_EVENT( 0, RTEMS_RECORD_FREQUENCY );
157  header->Frequency.data = rtems_counter_frequency();
158}
159
160static void send_header( int fd )
161{
162  Record_Stream_header header;
163
164  _Record_Stream_header_initialize( &header );
165  (void) write( fd, &header, sizeof( header ) );
166}
167
168void rtems_record_server( uint16_t port, rtems_interval period )
169{
170  rtems_status_code sc;
171  rtems_id self;
172  rtems_id timer;
173  struct sockaddr_in addr;
174  int sd;
175  int rv;
176
177  sd = -1;
178  self = rtems_task_self();
179
180  sc = rtems_timer_create( rtems_build_name( 'R', 'C', 'R', 'D' ), &timer );
181  if ( sc != RTEMS_SUCCESSFUL ) {
182    return;
183  }
184
185  sd = socket( PF_INET, SOCK_STREAM, 0 );
186  if (sd < 0) {
187    goto error;
188  }
189
190  memset( &addr, 0, sizeof( addr ) );
191  addr.sin_family = AF_INET;
192  addr.sin_port = htons( port );
193  addr.sin_addr.s_addr = htonl( INADDR_ANY );
194
195  rv = bind( sd, (const struct sockaddr *) &addr, sizeof( addr ) );
196  if (rv != 0) {
197    goto error;
198  }
199
200  rv = listen( sd, 0 );
201  if (rv != 0) {
202    goto error;
203  }
204
205  while ( true ) {
206    int cd;
207    bool written;
208    ssize_t n;
209
210    cd = accept( sd, NULL, NULL );
211
212    if ( cd < 0 ) {
213      break;
214    }
215
216    wait( RTEMS_NO_WAIT );
217    (void) rtems_timer_fire_after( timer, period, wakeup_timer, &self );
218    send_header( cd );
219
220    while ( true ) {
221      n = rtems_record_writev( cd, &written );
222
223      if ( written && n <= 0 ) {
224        break;
225      }
226
227      wait( RTEMS_WAIT );
228    }
229
230    (void) rtems_timer_cancel( timer );
231    (void) close( cd );
232  }
233
234error:
235
236  (void) close( sd );
237  (void) rtems_timer_delete( timer );
238}
239
240typedef struct {
241  rtems_id       task;
242  uint16_t       port;
243  rtems_interval period;
244} server_arg;
245
246static void server( rtems_task_argument arg )
247{
248  server_arg     *sarg;
249  uint16_t        port;
250  rtems_interval  period;
251
252  sarg = (server_arg *) arg;
253  port = sarg->port;
254  period = sarg->period;
255  wakeup(sarg->task);
256  rtems_record_server( port, period );
257  rtems_task_exit();
258}
259
260rtems_status_code rtems_record_start_server(
261  rtems_task_priority priority,
262  uint16_t            port,
263  rtems_interval      period
264)
265{
266  rtems_status_code sc;
267  rtems_id          id;
268  server_arg        sarg;
269
270  sarg.port = port;
271  sarg.period = period;
272  sarg.task = rtems_task_self();
273
274  sc = rtems_task_create(
275    rtems_build_name( 'R', 'C', 'R', 'D' ),
276    priority,
277    RTEMS_MINIMUM_STACK_SIZE,
278    RTEMS_DEFAULT_MODES,
279    RTEMS_DEFAULT_ATTRIBUTES,
280    &id
281  );
282  if ( sc != RTEMS_SUCCESSFUL ) {
283    return sc;
284  }
285
286  (void) rtems_task_start( id, server, (rtems_task_argument) &sarg );
287  wait( RTEMS_WAIT );
288
289  return RTEMS_SUCCESSFUL;
290}
Note: See TracBrowser for help on using the repository browser.