/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (C) 2018, 2019 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _RTEMS_RECORD_H #define _RTEMS_RECORD_H #include "recorddata.h" #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct Record_Control { Atomic_Uint head; unsigned int tail; unsigned int mask; Watchdog_Control Watchdog; rtems_record_item Header[ 3 ]; rtems_record_item Items[ RTEMS_ZERO_LENGTH_ARRAY ]; }; typedef struct Record_Control Record_Control; typedef RTEMS_ALIGNED( CPU_CACHE_LINE_BYTES ) struct Record_Configured_control Record_Configured_control; typedef struct { Record_Control *control; unsigned int head; uint32_t now; rtems_interrupt_level level; } rtems_record_context; PER_CPU_DATA_ITEM_DECLARE( Record_Configured_control, _Record_Per_CPU ); extern const unsigned int _Record_Item_count; void _Record_Initialize( void ); bool _Record_Thread_create( struct _Thread_Control *executing, struct _Thread_Control *created ); void _Record_Thread_start( struct _Thread_Control *executing, struct _Thread_Control *started ); void _Record_Thread_restart( struct _Thread_Control *executing, struct _Thread_Control *restarted ); void _Record_Thread_delete( struct _Thread_Control *executing, struct _Thread_Control *deleted ); void _Record_Thread_switch( struct _Thread_Control *executing, struct _Thread_Control *heir ); void _Record_Thread_begin( struct _Thread_Control *executing ); void _Record_Thread_exitted( struct _Thread_Control *executing ); void _Record_Thread_terminate( struct _Thread_Control *executing ); #define RECORD_EXTENSION \ { \ _Record_Thread_create, \ _Record_Thread_start, \ _Record_Thread_restart, \ _Record_Thread_delete, \ _Record_Thread_switch, \ _Record_Thread_begin, \ _Record_Thread_exitted, \ NULL, \ _Record_Thread_terminate \ } RTEMS_INLINE_ROUTINE unsigned int _Record_Index( const Record_Control *control, unsigned int index ) { return index & control->mask; } RTEMS_INLINE_ROUTINE unsigned int _Record_Head( const Record_Control *control ) { return _Atomic_Load_uint( &control->head, ATOMIC_ORDER_RELAXED ); } RTEMS_INLINE_ROUTINE unsigned int _Record_Tail( const Record_Control *control ) { return control->tail; } RTEMS_INLINE_ROUTINE bool _Record_Is_overflow( const Record_Control *control, unsigned int tail, unsigned int head ) { return head - tail >= control->mask + 1U; } RTEMS_INLINE_ROUTINE unsigned int _Record_Capacity( const Record_Control *control, unsigned int tail, unsigned int head ) { return ( tail - head - 1U ) & control->mask; } RTEMS_INLINE_ROUTINE rtems_counter_ticks _Record_Now( void ) { return rtems_counter_read(); } typedef struct RTEMS_PACKED { uint32_t format; uint32_t magic; rtems_record_item Version; rtems_record_item Processor_maximum; rtems_record_item Count; rtems_record_item Frequency; } Record_Stream_header; void _Record_Stream_header_initialize( Record_Stream_header *header ); /** * @addtogroup RTEMSRecord * * @{ */ /** * @brief Prepares to add and commit record items. * * This function disables interrupts. * * @param context The record context which must be used for the following * rtems_record_add() and rtems_record_commit() calls. The record context * may have an arbitrary content at function entry. * * @see rtems_record_produce(). */ RTEMS_INLINE_ROUTINE void rtems_record_prepare( rtems_record_context *context ) { rtems_interrupt_level level; const Per_CPU_Control *cpu_self; Record_Control *control; unsigned int head; rtems_interrupt_local_disable( level ); context->now = RTEMS_RECORD_TIME_EVENT( _Record_Now(), 0 ); context->level = level; cpu_self = _Per_CPU_Get(); control = cpu_self->record; context->control = control; head = _Record_Head( control ); context->head = head; } /** * @brief Adds a record item. * * @param context The record context initialized via rtems_record_prepare(). * @param event The record event without a time stamp for the item. * @param data The record data for the item. */ RTEMS_INLINE_ROUTINE void rtems_record_add( rtems_record_context *context, rtems_record_event event, rtems_record_data data ) { Record_Control *control; rtems_record_item *item; unsigned int head; control = context->control; head = context->head; item = &control->Items[ _Record_Index( control, head ) ]; context->head = head + 1; item->event = context->now | event; item->data = data; } /** * @brief Commits a set of record items. * * @param context The record context initialized via rtems_record_prepare(). */ RTEMS_INLINE_ROUTINE void rtems_record_commit( rtems_record_context *context ) { _Atomic_Store_uint( &context->control->head, context->head, ATOMIC_ORDER_RELEASE ); rtems_interrupt_local_enable( context->level ); } /** * @brief Produces a record item. * * @param event The record event without a time stamp for the item. * @param data The record data for the item. */ void rtems_record_produce( rtems_record_event event, rtems_record_data data ); /** * @brief Produces two record items. * * @param event_0 The record event without a time stamp for the first item. * @param data_0 The record data for the first item. * @param event_1 The record event without a time stamp for the second item. * @param data_1 The record data for the second item. */ void rtems_record_produce_2( rtems_record_event event_0, rtems_record_data data_0, rtems_record_event event_1, rtems_record_data data_1 ); /** * @brief Produces n record items. * * @param item The record items without a time stamps. * @param n The count of record items. */ void rtems_record_produce_n( const rtems_record_item *items, size_t n ); typedef void ( *rtems_record_drain_visitor )( const rtems_record_item *items, size_t count, void *arg ); /** * @brief Drains the record items on all processors. * * Calls the visitor function for each drained item set. * * @param visitor The visitor function. * @param arg The argument for the visitor function. */ void rtems_record_drain( rtems_record_drain_visitor visitor, void *arg ); /** * @brief Drains the record items on all processors an writes them to the file * descriptor. * * @param fd The file descriptor. * @param written Set to true if items were written to the file descriptor, * otherwise set to false. * * @retval The bytes written to the file descriptor. */ ssize_t rtems_record_writev( int fd, bool *written ); /** * @brief Runs a record TCP server loop. * * @param port The TCP port to listen in host byte order. * @param period The drain period in clock ticks. */ void rtems_record_server( uint16_t port, rtems_interval period ); /** * @brief Starts a record TCP server task. * * @param priority The task priority. * @param port The TCP port to listen in host byte order. * @param period The drain period in clock ticks. */ rtems_status_code rtems_record_start_server( rtems_task_priority priority, uint16_t port, rtems_interval period ); /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _RTEMS_RECORD_H */