Bug Summary

File:/home/joel/rtems-4.11-work/build/rtems/c/src/../../cpukit/libmisc/capture/capture.c
Location:line 1088, column 3
Description:Value stored to 'records' is never read

Annotated Source Code

1/*
2 ------------------------------------------------------------------------
3 $Id: capture.c,v 1.20 2009/11/29 12:12:39 ralf Exp $
4 ------------------------------------------------------------------------
5
6 Copyright Objective Design Systems Pty Ltd, 2002
7 All rights reserved Objective Design Systems Pty Ltd, 2002
8 Chris Johns (ccj@acm.org)
9
10 COPYRIGHT (c) 1989-2009.
11 On-Line Applications Research Corporation (OAR).
12
13 The license and distribution terms for this file may be
14 found in the file LICENSE in this distribution.
15
16 This software with is provided ``as is'' and with NO WARRANTY.
17
18 ------------------------------------------------------------------------
19
20 RTEMS Performance Monitoring and Measurement Framework.
21
22 This is the Capture Engine component.
23
24*/
25
26#ifdef HAVE_CONFIG_H1
27#include "config.h"
28#endif
29
30#include <stdlib.h>
31#include <string.h>
32
33#include "capture.h"
34#include <rtems/score/states.inl>
35#include <rtems/score/wkspace.h>
36#include <rtems/score/wkspace.inl>
37
38/*
39 * These events are always recorded and are not part of the
40 * watch filters.
41 *
42 * This feature has been disabled as it becomes confusing when
43 * setting up filters and some event leak.
44 */
45#if defined (RTEMS_CAPTURE_ENGINE_ALLOW_RELATED_EVENTS)
46#define RTEMS_CAPTURE_RECORD_EVENTS(0) (RTEMS_CAPTURE_CREATED_BY_EVENT0x00010000U | \
47 RTEMS_CAPTURE_CREATED_EVENT0x00020000U | \
48 RTEMS_CAPTURE_STARTED_BY_EVENT0x00040000U | \
49 RTEMS_CAPTURE_STARTED_EVENT0x00080000U | \
50 RTEMS_CAPTURE_RESTARTED_BY_EVENT0x00100000U | \
51 RTEMS_CAPTURE_RESTARTED_EVENT0x00200000U | \
52 RTEMS_CAPTURE_DELETED_BY_EVENT0x00400000U | \
53 RTEMS_CAPTURE_DELETED_EVENT0x00800000U | \
54 RTEMS_CAPTURE_BEGIN_EVENT0x01000000U | \
55 RTEMS_CAPTURE_EXITTED_EVENT0x02000000U)
56#else
57#define RTEMS_CAPTURE_RECORD_EVENTS(0) (0)
58#endif
59
60/*
61 * Global capture flags.
62 */
63#define RTEMS_CAPTURE_ON(1 << 0) (1 << 0)
64#define RTEMS_CAPTURE_NO_MEMORY(1 << 1) (1 << 1)
65#define RTEMS_CAPTURE_OVERFLOW(1 << 2) (1 << 2)
66#define RTEMS_CAPTURE_TRIGGERED(1 << 3) (1 << 3)
67#define RTEMS_CAPTURE_READER_ACTIVE(1 << 4) (1 << 4)
68#define RTEMS_CAPTURE_READER_WAITING(1 << 5) (1 << 5)
69#define RTEMS_CAPTURE_GLOBAL_WATCH(1 << 6) (1 << 6)
70#define RTEMS_CAPTURE_ONLY_MONITOR(1 << 7) (1 << 7)
71
72/*
73 * RTEMS Capture Data.
74 */
75static rtems_capture_record_t* capture_records;
76static uint32_t capture_size;
77static uint32_t capture_count;
78static rtems_capture_record_t* capture_in;
79static uint32_t capture_out;
80static uint32_t capture_flags;
81static rtems_capture_task_t* capture_tasks;
82static rtems_capture_control_t* capture_controls;
83static int capture_extension_index;
84static rtems_id capture_id;
85static rtems_capture_timestamp capture_timestamp;
86static rtems_task_priority capture_ceiling;
87static rtems_task_priority capture_floor;
88static uint32_t capture_tick_period;
89static rtems_id capture_reader;
90
91/*
92 * RTEMS Event text.
93 */
94static const char* capture_event_text[] =
95{
96 "CREATED_BY",
97 "CREATED",
98 "STARTED_BY",
99 "STARTED",
100 "RESTARTED_BY",
101 "RESTARTED",
102 "DELETED_BY",
103 "DELETED",
104 "BEGIN",
105 "EXITTED",
106 "SWITCHED_OUT",
107 "SWITCHED_IN",
108 "TIMESTAMP"
109};
110
111/*
112 * rtems_capture_get_time
113 *
114 * DESCRIPTION:
115 *
116 * This function returns the current time. If a handler is provided
117 * by the user get the time from that.
118 */
119static inline void rtems_capture_get_time (uint32_t* ticks,
120 uint32_t* tick_offset)
121{
122 if (capture_timestamp)
123 capture_timestamp (ticks, tick_offset);
124 else
125 {
126 *ticks = _Watchdog_Ticks_since_boot;
127 *tick_offset = 0;
128 }
129}
130
131/*
132 * rtems_capture_match_names
133 *
134 * DESCRIPTION:
135 *
136 * This function compares rtems_names. It protects the
137 * capture engine from a change to the way names are supported
138 * in RTEMS.
139 *
140 */
141static inline bool_Bool
142rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
143{
144 return lhs == rhs;
145}
146
147/*
148 * rtems_capture_match_id
149 *
150 * DESCRIPTION:
151 *
152 * This function compares rtems_ids. It protects the
153 * capture engine from a change to the way id are supported
154 * in RTEMS.
155 *
156 */
157static inline bool_Bool
158rtems_capture_match_ids (rtems_id lhs, rtems_id rhs)
159{
160 return lhs == rhs;
161}
162
163/*
164 * rtems_capture_match_name_id
165 *
166 * DESCRIPTION:
167 *
168 * This function matches a name and/or id.
169 */
170static inline bool_Bool
171rtems_capture_match_name_id (rtems_name lhs_name,
172 rtems_id lhs_id,
173 rtems_name rhs_name,
174 rtems_id rhs_id)
175{
176 /*
177 * The left hand side name or id could be 0 which means a wildcard.
178 */
179 if ((lhs_name == 0) && (lhs_id == rhs_id))
180 return 1;
181 else if ((lhs_id == 0) || (lhs_id == rhs_id))
182 {
183 if (rtems_capture_match_names (lhs_name, rhs_name))
184 return 1;
185 }
186 return 0;
187}
188
189/*
190 * rtems_capture_dup_name
191 *
192 * DESCRIPTION:
193 *
194 * This function duplicates an rtems_names. It protects the
195 * capture engine from a change to the way names are supported
196 * in RTEMS.
197 *
198 */
199static inline void
200rtems_capture_dup_name (rtems_name* dst, rtems_name src)
201{
202 *dst = src;
203}
204
205/*
206 * rtems_capture_by_in_to
207 *
208 * DESCRIPTION:
209 *
210 * This function sees if a BY control is in the BY names. The use
211 * of the valid_mask in this way assumes the number of trigger
212 * tasks is the number of bits in uint32_t.
213 *
214 */
215static inline bool_Bool
216rtems_capture_by_in_to (uint32_t events,
217 rtems_capture_task_t* by,
218 rtems_capture_control_t* to)
219{
220 uint32_t valid_mask = RTEMS_CAPTURE_CONTROL_FROM_MASK (0)(1U << ((32) - ((0) + 1)));
221 uint32_t valid_remainder = 0xffffffff;
222 int i;
223
224 for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS(32); i++)
225 {
226 /*
227 * If there are no more valid BY entries then
228 * we are finished.
229 */
230 if ((valid_remainder & to->by_valid) == 0)
231 break;
232
233 /*
234 * Is the froby entry valid and does its name or id match.
235 */
236 if ((valid_mask & to->by_valid) &&
237 (to->by[i].trigger & events))
238 {
239 /*
240 * We have the BY task on the right hand side so we
241 * match with id's first then labels if the id's are
242 * not set.
243 */
244 if (rtems_capture_match_name_id (to->by[i].name, to->by[i].id,
245 by->name, by->id))
246 return 1;
247 }
248
249 valid_mask >>= 1;
250 valid_remainder >>= 1;
251 }
252
253 return 0;
254}
255
256/*
257 * rtems_capture_refcount_up
258 *
259 * DESCRIPTION:
260 *
261 * This function raises the reference count.
262 *
263 */
264static inline void
265rtems_capture_refcount_up (rtems_capture_task_t* task)
266{
267 task->refcount++;
268}
269
270/*
271 * rtems_capture_refcount_down
272 *
273 * DESCRIPTION:
274 *
275 * This function lowers the reference count and if the count
276 * reaches 0 the task control block is returned to the heap.
277 *
278 */
279static inline void
280rtems_capture_refcount_down (rtems_capture_task_t* task)
281{
282 if (task->refcount)
283 task->refcount--;
284}
285
286/*
287 * rtems_capture_init_stack_usage
288 *
289 * DESCRIPTION:
290 *
291 * This function setups a stack so its usage can be monitored.
292 */
293static inline void
294rtems_capture_init_stack_usage (rtems_capture_task_t* task)
295{
296 if (task->tcb)
297 {
298 uint32_t* s;
299 uint32_t i;
300
301 task->stack_size = task->tcb->Start.Initial_stack.size;
302 task->stack_clean = task->stack_size;
303
304 s = task->tcb->Start.Initial_stack.area;
305
306 for (i = 0; i < (task->stack_size - 128); i += 4)
307 *(s++) = 0xdeaddead;
308 }
309}
310
311/*
312 * rtems_capture_find_control
313 *
314 * DESCRIPTION:
315 *
316 * This function searches for a trigger given a name.
317 *
318 */
319static inline rtems_capture_control_t*
320rtems_capture_find_control (rtems_name name, rtems_id id)
321{
322 rtems_capture_control_t* control;
323
324 for (control = capture_controls; control != NULL((void*)0); control = control->next)
325 if (rtems_capture_match_name_id (name, id, control->name, control->id))
326 break;
327 return control;
328}
329
330/*
331 * rtems_capture_create_control
332 *
333 * DESCRIPTION:
334 *
335 * This function creates a capture control for the capture engine.
336 *
337 */
338static inline rtems_capture_control_t*
339rtems_capture_create_control (rtems_name name, rtems_id id)
340{
341 rtems_interrupt_level level;
342 rtems_capture_control_t* control;
343 rtems_capture_task_t* task;
344
345 if ((name == 0) && (id == 0))
346 return NULL((void*)0);
347
348 control = rtems_capture_find_control (name, id);
349
350 if (control == NULL((void*)0))
351 {
352 control = _Workspace_Allocate (sizeof (rtems_capture_control_t));
353
354 if (control == NULL((void*)0))
355 {
356 capture_flags |= RTEMS_CAPTURE_NO_MEMORY(1 << 1);
357 return NULL((void*)0);
358 }
359
360 control->name = name;
361 control->id = id;
362 control->flags = 0;
363 control->to_triggers = 0;
364 control->from_triggers = 0;
365 control->by_valid = 0;
366
367 memset (control->by, 0, sizeof (control->by));
368
369 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
370
371 control->next = capture_controls;
372 capture_controls = control;
373
374 /*
375 * We need to scan the task list as set the control to the
376 * tasks.
377 */
378 for (task = capture_tasks; task != NULL((void*)0); task = task->forw)
379 if (rtems_capture_match_name_id (name, id, task->name, task->id))
380 task->control = control;
381
382 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
383 }
384
385 return control;
386}
387
388/*
389 * rtems_capture_create_capture_task
390 *
391 * DESCRIPTION:
392 *
393 * This function create the task control.
394 *
395 */
396static inline rtems_capture_task_t*
397rtems_capture_create_capture_task (rtems_tcb* new_task)
398{
399 rtems_interrupt_level level;
400 rtems_capture_task_t* task;
401 rtems_capture_control_t* control;
402 rtems_name name;
403
404 task = _Workspace_Allocate (sizeof (rtems_capture_task_t));
405
406 if (task == NULL((void*)0))
407 {
408 capture_flags |= RTEMS_CAPTURE_NO_MEMORY(1 << 1);
409 return NULL((void*)0);
410 }
411
412 /*
413 * Check the type of name the object has.
414 */
415
416 rtems_object_get_classic_name( new_task->Object.id, &name );
417
418 rtems_capture_dup_name (&task->name, name);
419
420 task->id = new_task->Object.id;
421 task->flags = 0;
422 task->in = 0;
423 task->refcount = 0;
424 task->out = 0;
425 task->tcb = new_task;
426 task->ticks = 0;
427 task->tick_offset = 0;
428 task->ticks_in = 0;
429 task->tick_offset_in = 0;
430 task->control = 0;
431 task->last_ticks = 0;
432 task->last_tick_offset = 0;
433
434 task->tcb->extensions[capture_extension_index] = task;
435
436 task->start_priority = new_task->Start.initial_priority;
437 task->stack_size = new_task->Start.Initial_stack.size;
438 task->stack_clean = task->stack_size;
439
440 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
441
442 task->forw = capture_tasks;
443 if (task->forw)
444 task->forw->back = task;
445 task->back = NULL((void*)0);
446 capture_tasks = task;
447
448 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
449
450 /*
451 * We need to scan the default control list to initialise
452 * this control.
453 */
454
455 for (control = capture_controls; control != NULL((void*)0); control = control->next)
456 if (rtems_capture_match_name_id (control->name, control->id,
457 task->name, task->id))
458 task->control = control;
459
460 return task;
461}
462
463/*
464 * rtems_capture_destroy_capture_task
465 *
466 * DESCRIPTION:
467 *
468 * This function destroy the task structure if the reference count
469 * is 0 and the tcb has been cleared signalling the task has been
470 * deleted.
471 *
472 */
473static inline void
474rtems_capture_destroy_capture_task (rtems_capture_task_t* task)
475{
476 if (task)
477 {
478 rtems_interrupt_level level;
479
480 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
481
482 if (task->tcb || task->refcount)
483 task = 0;
484
485 if (task)
486 {
487 if (task->forw)
488 task->forw->back = task->back;
489 if (task->back)
490 task->back->forw = task->forw;
491 else
492 capture_tasks = task->forw;
493 }
494
495 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
496
497 if (task)
498 _Workspace_Free (task);
499 }
500}
501
502/*
503 * rtems_capture_record
504 *
505 * DESCRIPTION:
506 *
507 * This function records a capture record into the capture buffer.
508 *
509 */
510static inline void
511rtems_capture_record (rtems_capture_task_t* task,
512 uint32_t events)
513{
514 /*
515 * Check the watch state if we have a task control, and
516 * the task's real priority is lower or equal to the ceiling.
517 */
518 if (task &&
519 ((capture_flags &
520 (RTEMS_CAPTURE_TRIGGERED(1 << 3) | RTEMS_CAPTURE_ONLY_MONITOR(1 << 7))) ==
521 RTEMS_CAPTURE_TRIGGERED(1 << 3)))
522 {
523 rtems_capture_control_t* control;
524
525 control = task->control;
526
527 /*
528 * Capure the record if we have an event that is always
529 * captured, or the task's real priority is greater than the
530 * watch ceiling, and the global watch or task watch is enabled.
531 */
532
533 if ((events & RTEMS_CAPTURE_RECORD_EVENTS(0)) ||
534 ((task->tcb->real_priority >= capture_ceiling) &&
535 (task->tcb->real_priority <= capture_floor) &&
536 ((capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH(1 << 6)) ||
537 (control && (control->flags & RTEMS_CAPTURE_WATCH(1 << 0))))))
538 {
539 rtems_interrupt_level level;
540
541 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
542
543 if (capture_count < capture_size)
544 {
545 capture_count++;
546 capture_in->task = task;
547 capture_in->events = (events |
548 (task->tcb->real_priority) |
549 (task->tcb->current_priority << 8));
550
551 if ((events & RTEMS_CAPTURE_RECORD_EVENTS(0)) == 0)
552 task->flags |= RTEMS_CAPTURE_TRACED(1 << 0);
553
554 rtems_capture_get_time (&capture_in->ticks, &capture_in->tick_offset);
555
556 if (capture_in == &capture_records[capture_size - 1])
557 capture_in = capture_records;
558 else
559 capture_in++;
560
561 rtems_capture_refcount_up (task);
562 }
563 else
564 capture_flags |= RTEMS_CAPTURE_OVERFLOW(1 << 2);
565 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
566 }
567 }
568}
569
570/*
571 * rtems_capture_trigger
572 *
573 * DESCRIPTION:
574 *
575 * See if we have triggered and if not see if this event is a
576 * cause of a trigger.
577 */
578bool_Bool
579rtems_capture_trigger (rtems_capture_task_t* ft,
580 rtems_capture_task_t* tt,
581 uint32_t events)
582{
583 /*
584 * If we have not triggered then see if this is a trigger condition.
585 */
586 if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED(1 << 3)))
587 {
588 rtems_capture_control_t* fc = NULL((void*)0);
589 rtems_capture_control_t* tc = NULL((void*)0);
590 uint32_t from_events = 0;
591 uint32_t to_events = 0;
592 uint32_t from_to_events = 0;
593
594 if (ft)
595 {
596 fc = ft->control;
597 if (fc)
598 from_events = fc->from_triggers & events;
599 }
600
601 if (tt)
602 {
603 tc = tt->control;
604 if (tc)
605 {
606 to_events = tc->to_triggers & events;
607 if (ft && tc->by_valid)
608 from_to_events = tc->by_triggers & events;
609 }
610 }
611
612 /*
613 * Check if we have any from or to events. These are the
614 * from any or to any type triggers. All from/to triggers are
615 * listed in the to's control with the from in the from list.
616 *
617 * The masking above means any flag set is a trigger.
618 */
619 if (from_events || to_events)
620 {
621 capture_flags |= RTEMS_CAPTURE_TRIGGERED(1 << 3);
622 return 1;
623 }
624
625 /*
626 * Check the from->to events.
627 */
628 if (from_to_events)
629 {
630 if (rtems_capture_by_in_to (events, ft, tc))
631 {
632 capture_flags |= RTEMS_CAPTURE_TRIGGERED(1 << 3);
633 return 1;
634 }
635 }
636
637 return 0;
638 }
639
640 return 1;
641}
642
643/*
644 * rtems_capture_create_task
645 *
646 * DESCRIPTION:
647 *
648 * This function is called when a task is created.
649 *
650 */
651static bool_Bool
652rtems_capture_create_task (rtems_tcb* current_task,
653 rtems_tcb* new_task)
654{
655 rtems_capture_task_t* ct;
656 rtems_capture_task_t* nt;
657
658 ct = current_task->extensions[capture_extension_index];
659
660 /*
661 * The task pointers may not be known as the task may have
662 * been created before the capture engine was open. Add them.
663 */
664
665 if (ct == NULL((void*)0))
666 ct = rtems_capture_create_capture_task (current_task);
667
668 /*
669 * Create the new task's capture control block.
670 */
671 nt = rtems_capture_create_capture_task (new_task);
672
673 if (rtems_capture_trigger (ct, nt, RTEMS_CAPTURE_CREATE(1 << 1)))
674 {
675 rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT0x00010000U);
676 rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT0x00020000U);
677 }
678
679 return 1 == 1;
680}
681
682/*
683 * rtems_capture_start_task
684 *
685 * DESCRIPTION:
686 *
687 * This function is called when a task is started.
688 *
689 */
690static void
691rtems_capture_start_task (rtems_tcb* current_task,
692 rtems_tcb* started_task)
693{
694 /*
695 * Get the capture task control block so we can trace this
696 * event.
697 */
698 rtems_capture_task_t* ct;
699 rtems_capture_task_t* st;
700
701 ct = current_task->extensions[capture_extension_index];
702 st = started_task->extensions[capture_extension_index];
703
704 /*
705 * The task pointers may not be known as the task may have
706 * been created before the capture engine was open. Add them.
707 */
708
709 if (ct == NULL((void*)0))
710 ct = rtems_capture_create_capture_task (current_task);
711
712 if (st == NULL((void*)0))
713 st = rtems_capture_create_capture_task (started_task);
714
715 if (rtems_capture_trigger (ct, st, RTEMS_CAPTURE_START(1 << 2)))
716 {
717 rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT0x00040000U);
718 rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT0x00080000U);
719 }
720
721 rtems_capture_init_stack_usage (st);
722}
723
724/*
725 * rtems_capture_restart_task
726 *
727 * DESCRIPTION:
728 *
729 * This function is called when a task is restarted.
730 *
731 */
732static void
733rtems_capture_restart_task (rtems_tcb* current_task,
734 rtems_tcb* restarted_task)
735{
736 /*
737 * Get the capture task control block so we can trace this
738 * event.
739 */
740 rtems_capture_task_t* ct;
741 rtems_capture_task_t* rt;
742
743 ct = current_task->extensions[capture_extension_index];
744 rt = restarted_task->extensions[capture_extension_index];
745
746 /*
747 * The task pointers may not be known as the task may have
748 * been created before the capture engine was open. Add them.
749 */
750
751 if (ct == NULL((void*)0))
752 ct = rtems_capture_create_capture_task (current_task);
753
754 if (rt == NULL((void*)0))
755 rt = rtems_capture_create_capture_task (restarted_task);
756
757 if (rtems_capture_trigger (ct, rt, RTEMS_CAPTURE_RESTART(1 << 3)))
758 {
759 rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT0x00100000U);
760 rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT0x00200000U);
761 }
762
763 rtems_capture_task_stack_usage (rt);
764 rtems_capture_init_stack_usage (rt);
765}
766
767/*
768 * rtems_capture_delete_task
769 *
770 * DESCRIPTION:
771 *
772 * This function is called when a task is deleted.
773 *
774 */
775static void
776rtems_capture_delete_task (rtems_tcb* current_task,
777 rtems_tcb* deleted_task)
778{
779 /*
780 * Get the capture task control block so we can trace this
781 * event.
782 */
783 rtems_capture_task_t* ct;
784 rtems_capture_task_t* dt;
785
786 /*
787 * The task pointers may not be known as the task may have
788 * been created before the capture engine was open. Add them.
789 */
790
791 ct = current_task->extensions[capture_extension_index];
792 dt = deleted_task->extensions[capture_extension_index];
793
794 if (ct == NULL((void*)0))
795 ct = rtems_capture_create_capture_task (current_task);
796
797 if (dt == NULL((void*)0))
798 dt = rtems_capture_create_capture_task (deleted_task);
799
800 if (rtems_capture_trigger (ct, dt, RTEMS_CAPTURE_DELETE(1 << 4)))
801 {
802 rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT0x00400000U);
803 rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT0x00800000U);
804 }
805
806 rtems_capture_task_stack_usage (dt);
807
808 /*
809 * This task's tcb will be invalid. This signals the
810 * task has been deleted.
811 */
812 dt->tcb = 0;
813
814 rtems_capture_destroy_capture_task (dt);
815}
816
817/*
818 * rtems_capture_begin_task
819 *
820 * DESCRIPTION:
821 *
822 * This function is called when a task is begun.
823 *
824 */
825static void
826rtems_capture_begin_task (rtems_tcb* begin_task)
827{
828 /*
829 * Get the capture task control block so we can trace this
830 * event.
831 */
832 rtems_capture_task_t* bt;
833
834 bt = begin_task->extensions[capture_extension_index];
835
836 /*
837 * The task pointers may not be known as the task may have
838 * been created before the capture engine was open. Add them.
839 */
840
841 if (bt == NULL((void*)0))
842 bt = rtems_capture_create_capture_task (begin_task);
843
844 if (rtems_capture_trigger (NULL((void*)0), bt, RTEMS_CAPTURE_BEGIN(1 << 5)))
845 rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT0x01000000U);
846}
847
848/*
849 * rtems_capture_exitted_task
850 *
851 * DESCRIPTION:
852 *
853 * This function is called when a task is exitted. That is
854 * returned rather than was deleted.
855 *
856 */
857static void
858rtems_capture_exitted_task (rtems_tcb* exitted_task)
859{
860 /*
861 * Get the capture task control block so we can trace this
862 * event.
863 */
864 rtems_capture_task_t* et;
865
866 et = exitted_task->extensions[capture_extension_index];
867
868 /*
869 * The task pointers may not be known as the task may have
870 * been created before the capture engine was open. Add them.
871 */
872
873 if (et == NULL((void*)0))
874 et = rtems_capture_create_capture_task (exitted_task);
875
876 if (rtems_capture_trigger (NULL((void*)0), et, RTEMS_CAPTURE_EXITTED(1 << 6)))
877 rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT0x02000000U);
878
879 rtems_capture_task_stack_usage (et);
880}
881
882/*
883 * rtems_capture_switch_task
884 *
885 * DESCRIPTION:
886 *
887 * This function is called when a context is switched.
888 *
889 */
890static void
891rtems_capture_switch_task (rtems_tcb* current_task,
892 rtems_tcb* heir_task)
893{
894 /*
895 * Only perform context switch trace processing if tracing is
896 * enabled.
897 */
898 if (capture_flags & RTEMS_CAPTURE_ON(1 << 0))
899 {
900 uint32_t ticks;
901 uint32_t tick_offset;
902
903 /*
904 * Get the cpature task control block so we can update the
905 * reference and perform any watch or trigger functions.
906 * The task pointers may not be known as the task may have
907 * been created before the capture engine was open. Add them.
908 */
909 rtems_capture_task_t* ct;
910 rtems_capture_task_t* ht;
911
912 if (_States_Is_transient (current_task->current_state))
913 {
914 rtems_id ct_id = current_task->Object.id;
915
916 for (ct = capture_tasks; ct; ct = ct->forw)
917 if (ct->id == ct_id)
918 break;
919 }
920 else
921 {
922 ct = current_task->extensions[capture_extension_index];
923
924 if (ct == NULL((void*)0))
925 ct = rtems_capture_create_capture_task (current_task);
926 }
927
928 ht = heir_task->extensions[capture_extension_index];
929
930 if (ht == NULL((void*)0))
931 ht = rtems_capture_create_capture_task (heir_task);
932
933 /*
934 * Update the execution time. Assume the tick will not overflow
935 * for now. This may need to change.
936 */
937 rtems_capture_get_time (&ticks, &tick_offset);
938
939 /*
940 * We could end up with null pointers for both the current task
941 * and the heir task.
942 */
943
944 if (ht)
945 {
946 ht->in++;
947 ht->ticks_in = ticks;
948 ht->tick_offset_in = tick_offset;
949 }
950
951 if (ct)
952 {
953 ct->out++;
954 ct->ticks += ticks - ct->ticks_in;
955
956 if (capture_timestamp)
957 {
958 tick_offset += capture_tick_period - ct->tick_offset_in;
959
960 if (tick_offset < capture_tick_period)
961 ct->tick_offset = tick_offset;
962 else
963 {
964 ct->ticks++;
965 ct->tick_offset = tick_offset - capture_tick_period;
966 }
967 }
968 else
969 {
970 ct->tick_offset += 100;
971 }
972 }
973
974 if (rtems_capture_trigger (ct, ht, RTEMS_CAPTURE_SWITCH(1 << 0)))
975 {
976 rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT0x04000000U);
977 rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT0x08000000U);
978 }
979 }
980}
981
982/*
983 * rtems_capture_open
984 *
985 * DESCRIPTION:
986 *
987 * This function initialises the realtime capture engine allocating the trace
988 * buffer. It is assumed we have a working heap at stage of initialisation.
989 *
990 */
991rtems_status_code
992rtems_capture_open (uint32_t size, rtems_capture_timestamp timestamp __attribute__((unused)))
993{
994 rtems_extensions_table capture_extensions;
995 rtems_name name;
996 rtems_status_code sc;
997
998 /*
999 * See if the capture engine is already open.
1000 */
1001
1002 if (capture_records)
1003 return RTEMS_RESOURCE_IN_USE;
1004
1005 capture_records = malloc (size * sizeof (rtems_capture_record_t));
1006
1007 if (capture_records == NULL((void*)0))
1008 return RTEMS_NO_MEMORY;
1009
1010 capture_size = size;
1011 capture_count = 0;
1012 capture_in = capture_records;
1013 capture_out = 0;
1014 capture_flags = 0;
1015 capture_tasks = NULL((void*)0);
1016 capture_ceiling = 0;
1017 capture_floor = 255;
1018
1019 /*
1020 * Create the extension table. This is copied so we
1021 * can create it as a local.
1022 */
1023 capture_extensions.thread_create = rtems_capture_create_task;
1024 capture_extensions.thread_start = rtems_capture_start_task;
1025 capture_extensions.thread_restart = rtems_capture_restart_task;
1026 capture_extensions.thread_delete = rtems_capture_delete_task;
1027 capture_extensions.thread_switch = rtems_capture_switch_task;
1028 capture_extensions.thread_begin = rtems_capture_begin_task;
1029 capture_extensions.thread_exitted = rtems_capture_exitted_task;
1030 capture_extensions.fatal = NULL((void*)0);
1031
1032 /*
1033 * Get the tick period from the BSP Configuration Table.
1034 */
1035 capture_tick_period = Configuration.microseconds_per_tick;
1036
1037 /*
1038 * Register the user extension handlers for the CAPture Engine.
1039 */
1040 name = rtems_build_name ('C', 'A', 'P', 'E')( (uint32_t)('C') << 24 | (uint32_t)('A') << 16 |
(uint32_t)('P') << 8 | (uint32_t)('E') )
;
1041 sc = rtems_extension_create (name, &capture_extensions, &capture_id);
1042
1043 if (sc != RTEMS_SUCCESSFUL)
1044 {
1045 capture_id = 0;
1046 free (capture_records);
1047 capture_records = NULL((void*)0);
1048 }
1049 else
1050 {
1051 capture_extension_index = rtems_object_id_get_index (capture_id)_Objects_Get_index( capture_id );;
1052 }
1053
1054 /*
1055 * Iterate over the list of existing tasks.
1056 */
1057
1058 return sc;
1059}
1060
1061/*
1062 * rtems_capture_close
1063 *
1064 * DESCRIPTION:
1065 *
1066 * This function shutdowns the capture engine and release any claimed
1067 * resources.
1068 */
1069rtems_status_code
1070rtems_capture_close (void)
1071{
1072 rtems_interrupt_level level;
1073 rtems_capture_task_t* task;
1074 rtems_capture_control_t* control;
1075 rtems_capture_record_t* records;
1076 rtems_status_code sc;
1077
1078 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1079
1080 if (!capture_records)
1081 {
1082 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1083 return RTEMS_SUCCESSFUL;
1084 }
1085
1086 capture_flags &= ~(RTEMS_CAPTURE_ON(1 << 0) | RTEMS_CAPTURE_ONLY_MONITOR(1 << 7));
1087
1088 records = capture_records;
Value stored to 'records' is never read
1089 capture_records = NULL((void*)0);
1090
1091 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1092
1093 /*
1094 * Delete the extension first. This means we are now able to
1095 * release the resources we have without them being used.
1096 */
1097
1098 sc = rtems_extension_delete (capture_id);
1099
1100 if (sc != RTEMS_SUCCESSFUL)
1101 return sc;
1102
1103 task = capture_tasks;
1104
1105 while (task)
1106 {
1107 rtems_capture_task_t* delete = task;
1108 task = task->forw;
1109 _Workspace_Free (delete);
1110 }
1111
1112 capture_tasks = NULL((void*)0);
1113
1114 control = capture_controls;
1115
1116 while (control)
1117 {
1118 rtems_capture_control_t* delete = control;
1119 control = control->next;
1120 _Workspace_Free (delete);
1121 }
1122
1123 capture_controls = NULL((void*)0);
1124
1125 if (capture_records)
1126 {
1127 free (capture_records);
1128 capture_records = NULL((void*)0);
1129 }
1130
1131 return RTEMS_SUCCESSFUL;
1132}
1133
1134/*
1135 * rtems_capture_control
1136 *
1137 * DESCRIPTION:
1138 *
1139 * This function allows control of tracing at a global level.
1140 */
1141rtems_status_code
1142rtems_capture_control (bool_Bool enable)
1143{
1144 rtems_interrupt_level level;
1145
1146 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1147
1148 if (!capture_records)
1149 {
1150 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1151 return RTEMS_UNSATISFIED;
1152 }
1153
1154 if (enable)
1155 capture_flags |= RTEMS_CAPTURE_ON(1 << 0);
1156 else
1157 capture_flags &= ~RTEMS_CAPTURE_ON(1 << 0);
1158
1159 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1160
1161 return RTEMS_SUCCESSFUL;
1162}
1163
1164/*
1165 * rtems_capture_monitor
1166 *
1167 * DESCRIPTION:
1168 *
1169 * This function enable the monitor mode. When in the monitor mode
1170 * the tasks are monitored but no data is saved. This can be used
1171 * to profile the load on a system.
1172 */
1173rtems_status_code
1174rtems_capture_monitor (bool_Bool enable)
1175{
1176 rtems_interrupt_level level;
1177
1178 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1179
1180 if (!capture_records)
1181 {
1182 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1183 return RTEMS_UNSATISFIED;
1184 }
1185
1186 if (enable)
1187 capture_flags |= RTEMS_CAPTURE_ONLY_MONITOR(1 << 7);
1188 else
1189 capture_flags &= ~RTEMS_CAPTURE_ONLY_MONITOR(1 << 7);
1190
1191 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1192
1193 return RTEMS_SUCCESSFUL;
1194}
1195
1196/*
1197 * rtems_capture_flush
1198 *
1199 * DESCRIPTION:
1200 *
1201 * This function flushes the capture buffer. The prime parameter allows the
1202 * capture engine to also be primed again.
1203 */
1204rtems_status_code
1205rtems_capture_flush (bool_Bool prime)
1206{
1207 rtems_interrupt_level level;
1208 rtems_capture_task_t* task;
1209
1210 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1211
1212 for (task = capture_tasks; task != NULL((void*)0); task = task->forw)
1213 {
1214 task->flags &= ~RTEMS_CAPTURE_TRACED(1 << 0);
1215 task->refcount = 0;
1216 }
1217
1218 if (prime)
1219 capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED(1 << 3) | RTEMS_CAPTURE_OVERFLOW(1 << 2));
1220 else
1221 capture_flags &= ~RTEMS_CAPTURE_OVERFLOW(1 << 2);
1222
1223 capture_count = 0;
1224 capture_in = capture_records;
1225 capture_out = 0;
1226
1227 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1228
1229 task = capture_tasks;
1230
1231 while (task)
1232 {
1233 rtems_capture_task_t* check = task;
1234 task = task->forw;
1235 rtems_capture_destroy_capture_task (check);
1236 }
1237
1238 return RTEMS_SUCCESSFUL;
1239}
1240
1241/*
1242 * rtems_capture_watch_add
1243 *
1244 * DESCRIPTION:
1245 *
1246 * This function defines a watch for a specific task given a name. A watch
1247 * causes it to be traced either in or out of context. The watch can be
1248 * optionally enabled or disabled with the set routine. It is disabled by
1249 * default.
1250 */
1251rtems_status_code
1252rtems_capture_watch_add (rtems_name name, rtems_id id)
1253{
1254 rtems_capture_control_t* control;
1255
1256 if ((name == 0) && (id == 0))
1257 return RTEMS_UNSATISFIED;
1258
1259 control = rtems_capture_find_control (name, id);
1260
1261 if (control && !id)
1262 return RTEMS_TOO_MANY;
1263
1264 if (!control)
1265 control = rtems_capture_create_control (name, id);
1266
1267 if (!control)
1268 return RTEMS_NO_MEMORY;
1269
1270 return RTEMS_SUCCESSFUL;
1271}
1272
1273/*
1274 * rtems_capture_watch_del
1275 *
1276 * DESCRIPTION:
1277 *
1278 * This function removes a watch for a specific task given a name. The task
1279 * description will still exist if referenced by a trace record in the trace
1280 * buffer or a global watch is defined.
1281 */
1282rtems_status_code
1283rtems_capture_watch_del (rtems_name name, rtems_id id)
1284{
1285 rtems_interrupt_level level;
1286 rtems_capture_control_t* control;
1287 rtems_capture_control_t** prev_control;
1288 rtems_capture_task_t* task;
1289 bool_Bool found = false0;
1290
1291 /*
1292 * Should this test be for wildcards ?
1293 */
1294
1295 for (prev_control = &capture_controls, control = capture_controls;
1296 control != NULL((void*)0); )
1297 {
1298 if (rtems_capture_match_name_id (control->name, control->id, name, id))
1299 {
1300 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1301
1302 for (task = capture_tasks; task != NULL((void*)0); task = task->forw)
1303 if (task->control == control)
1304 task->control = 0;
1305
1306 *prev_control = control->next;
1307
1308 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1309
1310 _Workspace_Free (control);
1311
1312 control = *prev_control;
1313
1314 found = true1;
1315 }
1316 else
1317 {
1318 prev_control = &control->next;
1319 control = control->next;
1320 }
1321 }
1322
1323 if (found)
1324 return RTEMS_SUCCESSFUL;
1325
1326 return RTEMS_INVALID_NAME;
1327}
1328
1329/*
1330 * rtems_capture_watch_set
1331 *
1332 * DESCRIPTION:
1333 *
1334 * This function allows control of a watch. The watch can be enabled or
1335 * disabled.
1336 */
1337rtems_status_code
1338rtems_capture_watch_ctrl (rtems_name name, rtems_id id, bool_Bool enable)
1339{
1340 rtems_interrupt_level level;
1341 rtems_capture_control_t* control;
1342 bool_Bool found = false0;
1343
1344 /*
1345 * Find the control and then set the watch. It must exist before it can
1346 * be controlled.
1347 */
1348 for (control = capture_controls; control != NULL((void*)0); control = control->next)
1349 {
1350 if (rtems_capture_match_name_id (control->name, control->id, name, id))
1351 {
1352 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1353
1354 if (enable)
1355 control->flags |= RTEMS_CAPTURE_WATCH(1 << 0);
1356 else
1357 control->flags &= ~RTEMS_CAPTURE_WATCH(1 << 0);
1358
1359 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1360
1361 found = true1;
1362 }
1363 }
1364
1365 if (found)
1366 return RTEMS_SUCCESSFUL;
1367
1368 return RTEMS_INVALID_NAME;
1369}
1370
1371/*
1372 * rtems_capture_watch_global
1373 *
1374 * DESCRIPTION:
1375 *
1376 * This function allows control of a global watch. The watch can be enabled or
1377 * disabled. A global watch configures all tasks below the ceiling and above
1378 * the floor to be traced.
1379 */
1380rtems_status_code
1381rtems_capture_watch_global (bool_Bool enable)
1382{
1383 rtems_interrupt_level level;
1384
1385 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1386
1387 /*
1388 * We need to keep specific and global watches separate so
1389 * a global enable/disable does not lose a specific watch.
1390 */
1391 if (enable)
1392 capture_flags |= RTEMS_CAPTURE_GLOBAL_WATCH(1 << 6);
1393 else
1394 capture_flags &= ~RTEMS_CAPTURE_GLOBAL_WATCH(1 << 6);
1395
1396 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1397
1398 return RTEMS_SUCCESSFUL;
1399}
1400
1401/*
1402 * rtems_capture_watch_global_on
1403 *
1404 * DESCRIPTION:
1405 *
1406 * This function returns the global watch state.
1407 */
1408bool_Bool
1409rtems_capture_watch_global_on (void)
1410{
1411 return capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH(1 << 6) ? 1 : 0;
1412}
1413
1414/*
1415 * rtems_capture_watch_ceiling
1416 *
1417 * DESCRIPTION:
1418 *
1419 * This function sets a watch ceiling. Tasks at or greating that the
1420 * ceiling priority are not watched. This is a simple way to monitor
1421 * an application and exclude system tasks running at a higher
1422 * priority level.
1423 */
1424rtems_status_code
1425rtems_capture_watch_ceiling (rtems_task_priority ceiling)
1426{
1427 capture_ceiling = ceiling;
1428 return RTEMS_SUCCESSFUL;
1429}
1430
1431/*
1432 * rtems_capture_watch_get_ceiling
1433 *
1434 * DESCRIPTION:
1435 *
1436 * This function gets the watch ceiling.
1437 */
1438rtems_task_priority
1439rtems_capture_watch_get_ceiling (void)
1440{
1441 return capture_ceiling;
1442}
1443
1444/*
1445 * rtems_capture_watch_floor
1446 *
1447 * DESCRIPTION:
1448 *
1449 * This function sets a watch floor. Tasks at or less that the
1450 * floor priority are not watched. This is a simple way to monitor
1451 * an application and exclude system tasks running at a lower
1452 * priority level.
1453 */
1454rtems_status_code
1455rtems_capture_watch_floor (rtems_task_priority floor)
1456{
1457 capture_floor = floor;
1458 return RTEMS_SUCCESSFUL;
1459}
1460
1461/*
1462 * rtems_capture_watch_get_floor
1463 *
1464 * DESCRIPTION:
1465 *
1466 * This function gets the watch floor.
1467 */
1468rtems_task_priority
1469rtems_capture_watch_get_floor (void)
1470{
1471 return capture_floor;
1472}
1473
1474/*
1475 * rtems_capture_map_trigger
1476 *
1477 * DESCRIPTION:
1478 *
1479 * Map the trigger to a bit mask.
1480 *
1481 */
1482uint32_t
1483rtems_capture_map_trigger (rtems_capture_trigger_t trigger)
1484{
1485 /*
1486 * Transform the mode and trigger to a bit map.
1487 */
1488 switch (trigger)
1489 {
1490 case rtems_capture_switch:
1491 return RTEMS_CAPTURE_SWITCH(1 << 0);
1492 case rtems_capture_create:
1493 return RTEMS_CAPTURE_CREATE(1 << 1);
1494 case rtems_capture_start:
1495 return RTEMS_CAPTURE_START(1 << 2);
1496 case rtems_capture_restart:
1497 return RTEMS_CAPTURE_RESTART(1 << 3);
1498 case rtems_capture_delete:
1499 return RTEMS_CAPTURE_DELETE(1 << 4);
1500 case rtems_capture_begin:
1501 return RTEMS_CAPTURE_BEGIN(1 << 5);
1502 case rtems_capture_exitted:
1503 return RTEMS_CAPTURE_EXITTED(1 << 6);
1504 default:
1505 break;
1506 }
1507 return 0;
1508}
1509
1510/*
1511 * rtems_capture_set_trigger
1512 *
1513 * DESCRIPTION:
1514 *
1515 * This function sets a trigger.
1516 *
1517 * This set trigger routine will create a capture control for the
1518 * target task. The task list is searched and any existing tasks
1519 * are linked to the new control.
1520 *
1521 * We can have a number of tasks that have the same name so we
1522 * search using names. This means a number of tasks can be
1523 * linked to single control.
1524 */
1525rtems_status_code
1526rtems_capture_set_trigger (rtems_name from_name,
1527 rtems_id from_id,
1528 rtems_name to_name,
1529 rtems_id to_id,
1530 rtems_capture_trigger_mode_t mode,
1531 rtems_capture_trigger_t trigger)
1532{
1533 rtems_capture_control_t* control;
1534 uint32_t flags;
1535
1536 flags = rtems_capture_map_trigger (trigger);
1537
1538 /*
1539 * The mode sets the opposite type of trigger. For example
1540 * FROM ANY means trigger when the event happens TO this
1541 * task. TO ANY means FROM this task.
1542 */
1543
1544 if (mode == rtems_capture_to_any)
1545 {
1546 control = rtems_capture_create_control (from_name, from_id);
1547 if (control == NULL((void*)0))
1548 return RTEMS_NO_MEMORY;
1549 control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS((1 << 0) | (1 << 1) | (1 << 2) | (1 <<
3) | (1 << 4))
;
1550 }
1551 else
1552 {
1553 control = rtems_capture_create_control (to_name, to_id);
1554 if (control == NULL((void*)0))
1555 return RTEMS_NO_MEMORY;
1556 if (mode == rtems_capture_from_any)
1557 control->to_triggers |= flags;
1558 else
1559 {
1560 bool_Bool done = false0;
1561 int i;
1562
1563 control->by_triggers |= flags;
1564
1565 for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS(32); i++)
1566 {
1567 if (rtems_capture_control_by_valid (control, i) &&
1568 ((control->by[i].name == from_name) ||
1569 (from_id && (control->by[i].id == from_id))))
1570 {
1571 control->by[i].trigger |= flags;
1572 done = true1;
1573 break;
1574 }
1575 }
1576
1577 if (!done)
1578 {
1579 for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS(32); i++)
1580 {
1581 if (!rtems_capture_control_by_valid (control, i))
1582 {
1583 control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i)(1U << ((32) - ((i) + 1)));
1584 control->by[i].name = from_name;
1585 control->by[i].id = from_id;
1586 control->by[i].trigger = flags;
1587 done = true1;
1588 break;
1589 }
1590 }
1591 }
1592
1593 if (!done)
1594 return RTEMS_TOO_MANY;
1595 }
1596 }
1597 return RTEMS_SUCCESSFUL;
1598}
1599
1600/*
1601 * rtems_capture_clear_trigger
1602 *
1603 * DESCRIPTION:
1604 *
1605 * This function clear a trigger.
1606 */
1607rtems_status_code
1608rtems_capture_clear_trigger (rtems_name from_name,
1609 rtems_id from_id,
1610 rtems_name to_name,
1611 rtems_id to_id,
1612 rtems_capture_trigger_mode_t mode,
1613 rtems_capture_trigger_t trigger)
1614{
1615 rtems_capture_control_t* control;
1616 uint32_t flags;
1617
1618 flags = rtems_capture_map_trigger (trigger);
1619
1620 if (mode == rtems_capture_to_any)
1621 {
1622 control = rtems_capture_find_control (from_name, from_id);
1623 if (control == NULL((void*)0))
1624 {
1625 if (from_id)
1626 return RTEMS_INVALID_ID;
1627 return RTEMS_INVALID_NAME;
1628 }
1629 control->from_triggers &= ~flags;
1630 }
1631 else
1632 {
1633 control = rtems_capture_find_control (to_name, to_id);
1634 if (control == NULL((void*)0))
1635 {
1636 if (to_id)
1637 return RTEMS_INVALID_ID;
1638 return RTEMS_INVALID_NAME;
1639 }
1640 if (mode == rtems_capture_from_any)
1641 control->to_triggers &= ~flags;
1642 else
1643 {
1644 bool_Bool done = false0;
1645 int i;
1646
1647 control->by_triggers &= ~flags;
1648
1649 for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS(32); i++)
1650 {
1651 if (rtems_capture_control_by_valid (control, i) &&
1652 ((control->by[i].name == from_name) ||
1653 (control->by[i].id == from_id)))
1654 {
1655 control->by[i].trigger &= ~trigger;
1656 if (control->by[i].trigger == 0)
1657 control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i)(1U << ((32) - ((i) + 1)));
1658 done = true1;
1659 break;
1660 }
1661 }
1662
1663 if (!done)
1664 {
1665 if (from_id)
1666 return RTEMS_INVALID_ID;
1667 return RTEMS_INVALID_NAME;
1668 }
1669 }
1670 }
1671 return RTEMS_SUCCESSFUL;
1672}
1673
1674/*
1675 * rtems_capture_read
1676 *
1677 * DESCRIPTION:
1678 *
1679 * This function reads a number of records from the capture buffer.
1680 * The user can optionally block and wait until the buffer as a
1681 * specific number of records available or a specific time has
1682 * elasped.
1683 *
1684 * The function returns the number of record that is has that are
1685 * in a continous block of memory. If the number of available records
1686 * wrap then only those records are provided. This removes the need for
1687 * caller to be concerned about buffer wrappings. If the number of
1688 * requested records cannot be met due to the wrapping of the records
1689 * less than the specified number will be returned.
1690 *
1691 * The user must release the records. This is achieved with a call to
1692 * rtems_capture_release. Calls this function without a release will
1693 * result in at least the same number of records being released.
1694 *
1695 * The 'threshold' parameter is the number of records that must be
1696 * captured before returning. If a timeout period is specified (non-0)
1697 * any captured records will be returned. These parameters stop
1698 * thrashing occuring for a small number of records, yet allows
1699 * a user configured latiency to be applied for single events.
1700 *
1701 * The 'timeout' parameter is in micro-seconds. A value of 0 will disable
1702 * the timeout.
1703 *
1704 */
1705rtems_status_code
1706rtems_capture_read (uint32_t threshold,
1707 uint32_t timeout,
1708 uint32_t* read,
1709 rtems_capture_record_t** recs)
1710{
1711 rtems_interrupt_level level;
1712 rtems_status_code sc = RTEMS_SUCCESSFUL;
1713 uint32_t count;
1714
1715 *read = 0;
1716 *recs = NULL((void*)0);
1717
1718 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1719
1720 /*
1721 * Only one reader is allowed.
1722 */
1723
1724 if (capture_flags & RTEMS_CAPTURE_READER_ACTIVE(1 << 4))
1725 {
1726 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1727 return RTEMS_RESOURCE_IN_USE;
1728 }
1729
1730 capture_flags |= RTEMS_CAPTURE_READER_ACTIVE(1 << 4);
1731 *read = count = capture_count;
1732
1733 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1734
1735 *recs = &capture_records[capture_out];
1736
1737 for (;;)
1738 {
1739 /*
1740 * See if the count wraps the end of the record buffer.
1741 */
1742 if (count && ((capture_out + count) >= capture_size))
1743 *read = capture_size - capture_out;
1744
1745 /*
1746 * Do we have a threshold and the current count has not wrapped
1747 * around the end of the capture record buffer ?
1748 */
1749 if ((*read == count) && threshold)
1750 {
1751 /*
1752 * Do we have enough records ?
1753 */
1754 if (*read < threshold)
1755 {
1756 rtems_event_set event_out;
1757
1758 rtems_task_ident (RTEMS_SELF((Objects_Id) 0), RTEMS_LOCAL0x00000000, &capture_reader);
1759
1760 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1761
1762 capture_flags |= RTEMS_CAPTURE_READER_WAITING(1 << 5);
1763
1764 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1765
1766 sc = rtems_event_receive (RTEMS_EVENT_00x00000001,
1767 RTEMS_WAIT0x00000000 | RTEMS_EVENT_ANY0x00000002,
1768 RTEMS_MICROSECONDS_TO_TICKS (timeout)((timeout) / (Configuration.microseconds_per_tick)),
1769 &event_out);
1770
1771 /*
1772 * Let the user handle all other sorts of errors. This may
1773 * not be the best solution, but oh well, it will do for
1774 * now.
1775 */
1776 if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
1777 break;
1778
1779 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1780
1781 *read = count = capture_count;
1782
1783 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1784
1785 continue;
1786 }
1787 }
1788
1789 /*
1790 * Always out if we reach here. To loop use continue.
1791 */
1792 break;
1793 }
1794
1795 return sc;
1796}
1797
1798/*
1799 * rtems_capture_release
1800 *
1801 * DESCRIPTION:
1802 *
1803 * This function releases the requested number of record slots back
1804 * to the capture engine. The count must match the number read.
1805 */
1806rtems_status_code
1807rtems_capture_release (uint32_t count)
1808{
1809 rtems_capture_record_t* rec;
1810 uint32_t counted;
1811
1812 rtems_interrupt_level level;
1813
1814 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1815
1816 if (count > capture_count)
1817 count = capture_count;
1818
1819 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1820
1821 counted = count;
1822
1823 rec = &capture_records[capture_out];
1824
1825 while (counted--)
1826 {
1827 rtems_capture_refcount_down (rec->task);
1828 rtems_capture_destroy_capture_task (rec->task);
1829 rec++;
1830 }
1831
1832 rtems_interrupt_disable (level)do { (level) = sparc_disable_interrupts(); asm volatile("" ::
: "memory"); } while (0)
;
1833
1834 capture_count -= count;
1835
1836 capture_out = (capture_out + count) % capture_size;
1837
1838 capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE(1 << 4);
1839
1840 rtems_interrupt_enable (level)do { asm volatile("" ::: "memory"); sparc_enable_interrupts( level
); } while (0)
;
1841
1842 return RTEMS_SUCCESSFUL;
1843}
1844
1845/*
1846 * rtems_capture_tick_time
1847 *
1848 * DESCRIPTION:
1849 *
1850 * This function returns the tick period in nano-seconds.
1851 */
1852uint32_t
1853rtems_capture_tick_time (void)
1854{
1855 return capture_tick_period;
1856}
1857
1858/*
1859 * rtems_capture_event_text
1860 *
1861 * DESCRIPTION:
1862 *
1863 * This function returns a string for an event based on the bit in the
1864 * event. The functions takes the bit offset as a number not the bit
1865 * set in a bit map.
1866 */
1867const char*
1868rtems_capture_event_text (int event)
1869{
1870 if ((event < RTEMS_CAPTURE_EVENT_START(16)) || (event > RTEMS_CAPTURE_EVENT_END(28)))
1871 return "invalid event id";
1872 return capture_event_text[event - RTEMS_CAPTURE_EVENT_START(16)];
1873}
1874
1875/*
1876 * rtems_capture_get_task_list
1877 *
1878 * DESCRIPTION:
1879 *
1880 * This function returns the head of the list of tasks that the
1881 * capture engine has detected.
1882 */
1883rtems_capture_task_t*
1884rtems_capture_get_task_list (void)
1885{
1886 return capture_tasks;
1887}
1888
1889/*
1890 * rtems_capture_task_stack_usage
1891 *
1892 * DESCRIPTION:
1893 *
1894 * This function updates the stack usage. The task control block
1895 * is updated.
1896 */
1897uint32_t
1898rtems_capture_task_stack_usage (rtems_capture_task_t* task)
1899{
1900 if (task->tcb)
1901 {
1902 uint32_t* st;
1903 uint32_t* s;
1904
1905 /*
1906 * @todo: Assumes all stacks move the same way.
1907 */
1908 st = task->tcb->Start.Initial_stack.area + task->stack_size;
1909 s = task->tcb->Start.Initial_stack.area;
1910
1911 while (s < st)
1912 {
1913 if (*s != 0xdeaddead)
1914 break;
1915 s++;
1916 }
1917
1918 task->stack_clean =
1919 s - (uint32_t*) task->tcb->Start.Initial_stack.area;
1920 }
1921
1922 return task->stack_clean;
1923}
1924
1925/*
1926 * rtems_capture_get_control_list
1927 *
1928 * DESCRIPTION:
1929 *
1930 * This function returns the head of the list of control in the
1931 * capture engine.
1932 */
1933rtems_capture_control_t*
1934rtems_capture_get_control_list (void)
1935{
1936 return capture_controls;
1937}