/*
------------------------------------------------------------------------
Copyright Objective Design Systems Pty Ltd, 2002
All rights reserved Objective Design Systems Pty Ltd, 2002
Chris Johns (ccj@acm.org)
COPYRIGHT (c) 1989-2014.
On-Line Applications Research Corporation (OAR).
The license and distribution terms for this file may be
found in the file LICENSE in this distribution.
This software with is provided ``as is'' and with NO WARRANTY.
------------------------------------------------------------------------
RTEMS Performance Monitoring and Measurement Framework.
This is the Capture Engine component.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <rtems/rtems/tasksimpl.h>
#include "captureimpl.h"
#include <rtems/score/statesimpl.h>
#include <rtems/score/todimpl.h>
/*
* RTEMS Capture User Extension Data.
*/
static rtems_id capture_id;
static bool
rtems_capture_create_task (rtems_tcb* current_task,
rtems_tcb* new_task);
static void
rtems_capture_start_task (rtems_tcb* current_task,
rtems_tcb* started_task);
static void
rtems_capture_restart_task (rtems_tcb* current_task,
rtems_tcb* restarted_task);
static void
rtems_capture_delete_task (rtems_tcb* current_task,
rtems_tcb* deleted_task);
static void
rtems_capture_switch_task (rtems_tcb* current_task,
rtems_tcb* heir_task);
static void
rtems_capture_begin_task (rtems_tcb* begin_task);
static void
rtems_capture_exitted_task (rtems_tcb* exitted_task);
static void
rtems_capture_terminated_task (rtems_tcb* terminated_task);
static const rtems_extensions_table capture_extensions = {
.thread_create = rtems_capture_create_task,
.thread_start = rtems_capture_start_task,
.thread_restart = rtems_capture_restart_task,
.thread_delete = rtems_capture_delete_task,
.thread_switch = rtems_capture_switch_task,
.thread_begin = rtems_capture_begin_task,
.thread_exitted = rtems_capture_exitted_task,
.fatal = NULL,
.thread_terminate = rtems_capture_terminated_task
};
static inline void rtems_capture_record (
rtems_tcb* tcb,
uint32_t events
)
{
rtems_capture_record_t* rec;
void* ptr;
size_t size = sizeof(*rec);
if (rtems_capture_filter( tcb, events) )
return;
if (!rtems_capture_task_recorded (tcb))
rtems_capture_record_task (tcb);
rtems_capture_begin_add_record (tcb, events, size, &ptr);
rtems_capture_end_add_record ( ptr );
}
rtems_status_code rtems_capture_user_extension_open(void)
{
rtems_status_code sc;
rtems_name name;
int index;
/*
* Register the user extension handlers for the CAPture Engine.
*/
name = rtems_build_name ('C', 'A', 'P', 'E');
sc = rtems_extension_create (name, &capture_extensions, &capture_id);
if (sc != RTEMS_SUCCESSFUL)
capture_id = 0;
else {
index = rtems_object_id_get_index (capture_id);
rtems_capture_set_extension_index( index );
}
return sc;
}
rtems_status_code rtems_capture_user_extension_close(void)
{
rtems_status_code sc;
sc = rtems_extension_delete (capture_id);
return sc;
}
/*
* This function is called when a task is created.
*/
static bool
rtems_capture_create_task (rtems_tcb* ct,
rtems_tcb* nt)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (ct))
rtems_capture_initialize_task (ct);
/*
* Create the new task's capture control block.
*/
rtems_capture_initialize_task (nt);
if (rtems_capture_trigger (ct, nt, RTEMS_CAPTURE_CREATE))
{
rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT);
rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT);
}
return 1 == 1;
}
/*
* This function is called when a task is started.
*/
static void
rtems_capture_start_task (rtems_tcb* ct,
rtems_tcb* st)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (ct))
rtems_capture_initialize_task (ct);
if (st != NULL)
rtems_capture_initialize_task (st);
if (rtems_capture_trigger (ct, st, RTEMS_CAPTURE_START))
{
rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT);
rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT);
}
}
/*
* This function is called when a task is restarted.
*/
static void
rtems_capture_restart_task (rtems_tcb* ct,
rtems_tcb* rt)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (ct))
rtems_capture_initialize_task (ct);
if (!rtems_capture_task_initialized (rt))
rtems_capture_initialize_task (rt);
if (rtems_capture_trigger (ct, rt, RTEMS_CAPTURE_RESTART))
{
rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT);
rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT);
}
}
/*
* This function is called when a task is deleted.
*/
static void
rtems_capture_delete_task (rtems_tcb* ct,
rtems_tcb* dt)
{
if (!rtems_capture_task_initialized (ct))
rtems_capture_initialize_task (ct);
if (!rtems_capture_task_initialized (dt))
rtems_capture_initialize_task (dt);
if (rtems_capture_trigger (ct, dt, RTEMS_CAPTURE_DELETE))
{
rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT);
rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT);
}
}
/*
* This function is called when a task is begun.
*/
static void
rtems_capture_begin_task (rtems_tcb* bt)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (bt))
rtems_capture_initialize_task (bt);
if (rtems_capture_trigger (NULL, bt, RTEMS_CAPTURE_BEGIN))
rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT);
}
/*
* This function is called when a task is exitted. That is
* returned rather than was deleted.
*/
static void
rtems_capture_exitted_task (rtems_tcb* et)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (et))
rtems_capture_initialize_task (et);
if (rtems_capture_trigger (NULL, et, RTEMS_CAPTURE_EXITTED))
rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT);
}
/*
* This function is called when a termination request is identified.
*/
static void
rtems_capture_terminated_task (rtems_tcb* tt)
{
/*
* The task pointers may not be known as the task may have
* been created before the capture engine was open. Add them.
*/
if (!rtems_capture_task_initialized (tt))
rtems_capture_initialize_task (tt);
if (rtems_capture_trigger (NULL, tt, RTEMS_CAPTURE_TERMINATED))
rtems_capture_record (tt, RTEMS_CAPTURE_TERMINATED_EVENT);
}
/*
* This function is called when a context is switched.
*/
static void
rtems_capture_switch_task (rtems_tcb* ct,
rtems_tcb* ht)
{
uint32_t flags = rtems_capture_get_flags();
/*
* Only perform context switch trace processing if tracing is
* enabled.
*/
if (flags & RTEMS_CAPTURE_ON)
{
rtems_capture_time_t time;
if (!rtems_capture_task_initialized (ct))
rtems_capture_initialize_task (ct);
if (!rtems_capture_task_initialized (ht))
rtems_capture_initialize_task (ht);
/*
* Update the execution time. Assume the time will not overflow
* for now. This may need to change.
*/
rtems_capture_get_time (&time);
if (rtems_capture_trigger (ct, ht, RTEMS_CAPTURE_SWITCH))
{
rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT);
rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT);
}
}
}