mirror of
https://git.rtems.org/rtems-tools/
synced 2025-05-14 06:29:26 +08:00
321 lines
10 KiB
Python
321 lines
10 KiB
Python
# RTEMS Tools Project (http://www.rtems.org/)
|
|
# Copyright 2010-2015 Chris Johns (chrisj@rtems.org)
|
|
# All rights reserved.
|
|
#
|
|
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
|
#
|
|
# 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 HOLDER 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.
|
|
#
|
|
|
|
#
|
|
# RTEMS Threads Support
|
|
#
|
|
|
|
import gdb
|
|
|
|
import chains
|
|
import objects
|
|
import percpu
|
|
import rbtrees
|
|
import time
|
|
|
|
def task_chain(chain):
|
|
tasks = []
|
|
if not chain.empty():
|
|
node = chain.first()
|
|
while not node.null():
|
|
t = control(node.cast('Thread_Control'))
|
|
tasks.append(t)
|
|
node = node(node.next())
|
|
return tasks
|
|
|
|
def task_tree(tree):
|
|
tasks = []
|
|
node = tree.first(rbtrees.rbt_left)
|
|
while not node.null():
|
|
tasks.append(control(node.cast('Thread_Control')))
|
|
node = node.next(rbtrees.rbt_left)
|
|
return tasks
|
|
|
|
class state():
|
|
|
|
ALL_SET = 0x000fffff
|
|
READY = 0x00000000
|
|
DORMANT = 0x00000001
|
|
SUSPENDED = 0x00000002
|
|
TRANSIENT = 0x00000004
|
|
DELAYING = 0x00000008
|
|
WAITING_FOR_TIME = 0x00000010
|
|
WAITING_FOR_BUFFER = 0x00000020
|
|
WAITING_FOR_SEGMENT = 0x00000040
|
|
WAITING_FOR_MESSAGE = 0x00000080
|
|
WAITING_FOR_EVENT = 0x00000100
|
|
WAITING_FOR_SEMAPHORE = 0x00000200
|
|
WAITING_FOR_MUTEX = 0x00000400
|
|
WAITING_FOR_CONDITION_VARIABLE = 0x00000800
|
|
WAITING_FOR_JOIN_AT_EXIT = 0x00001000
|
|
WAITING_FOR_RPC_REPLY = 0x00002000
|
|
WAITING_FOR_PERIOD = 0x00004000
|
|
WAITING_FOR_SIGNAL = 0x00008000
|
|
WAITING_FOR_BARRIER = 0x00010000
|
|
WAITING_FOR_RWLOCK = 0x00020000
|
|
INTERRUPTIBLE_BY_SIGNAL = 0x10000000
|
|
LOCALLY_BLOCKED = \
|
|
WAITING_FOR_BUFFER | \
|
|
WAITING_FOR_SEGMENT | \
|
|
WAITING_FOR_MESSAGE | \
|
|
WAITING_FOR_SEMAPHORE | \
|
|
WAITING_FOR_MUTEX | \
|
|
WAITING_FOR_CONDITION_VARIABLE | \
|
|
WAITING_FOR_JOIN_AT_EXIT | \
|
|
WAITING_FOR_SIGNAL | \
|
|
WAITING_FOR_BARRIER | \
|
|
WAITING_FOR_RWLOCK
|
|
WAITING_ON_THREAD_QUEUE = \
|
|
LOCALLY_BLOCKED | WAITING_FOR_RPC_REPLY
|
|
BLOCKED = \
|
|
DELAYING | \
|
|
WAITING_FOR_TIME | \
|
|
WAITING_FOR_PERIOD | \
|
|
WAITING_FOR_EVENT | \
|
|
WAITING_ON_THREAD_QUEUE | \
|
|
INTERRUPTIBLE_BY_SIGNAL
|
|
|
|
masks = {
|
|
ALL_SET : 'all-set',
|
|
READY : 'ready',
|
|
DORMANT : 'dormant',
|
|
SUSPENDED : 'suspended',
|
|
TRANSIENT : 'transient',
|
|
DELAYING : 'delaying',
|
|
WAITING_FOR_TIME : 'waiting-for-time',
|
|
WAITING_FOR_BUFFER : 'waiting-for-buffer',
|
|
WAITING_FOR_SEGMENT : 'waiting-for-segment',
|
|
WAITING_FOR_MESSAGE : 'waiting-for-message',
|
|
WAITING_FOR_EVENT : 'waiting-for-event',
|
|
WAITING_FOR_SEMAPHORE : 'waiting-for-semaphore',
|
|
WAITING_FOR_MUTEX : 'waiting-for-mutex',
|
|
WAITING_FOR_CONDITION_VARIABLE : 'waiting-for-condition-variable',
|
|
WAITING_FOR_JOIN_AT_EXIT : 'waiting-for-join-at-exit',
|
|
WAITING_FOR_RPC_REPLY : 'waiting-for-rpc-reply',
|
|
WAITING_FOR_PERIOD : 'waiting-for-period',
|
|
WAITING_FOR_SIGNAL : 'waiting-for-signal',
|
|
WAITING_FOR_BARRIER : 'waiting-for-barrier',
|
|
WAITING_FOR_RWLOCK : 'waiting-for-rwlock'
|
|
}
|
|
|
|
def __init__(self, s):
|
|
self.s = s
|
|
|
|
def to_string(self):
|
|
if (self.s & self.LOCALLY_BLOCKED) == self.LOCALLY_BLOCKED:
|
|
return 'locally-blocked'
|
|
if (self.s & self.WAITING_ON_THREAD_QUEUE) == self.WAITING_ON_THREAD_QUEUE:
|
|
return 'waiting-on-thread-queue'
|
|
if (self.s & self.BLOCKED) == self.BLOCKED:
|
|
return 'blocked'
|
|
s = ','
|
|
for m in self.masks:
|
|
if (self.s & m) == m:
|
|
s = self.masks[m] + ','
|
|
return s[:-1]
|
|
|
|
class cpu_usage():
|
|
|
|
def __init__(self, time_):
|
|
self.time = time.time(time_)
|
|
|
|
def __str__(self):
|
|
return self.time.tostring()
|
|
|
|
def get(self):
|
|
return self.time.get()
|
|
|
|
class wait_info():
|
|
|
|
def __init__(self, info):
|
|
self.info = info
|
|
|
|
def id(self):
|
|
return self.info['id']
|
|
|
|
def count(self):
|
|
return self.info['count']
|
|
|
|
def return_arg(self):
|
|
return self.info['return_argument']
|
|
|
|
def option(self):
|
|
return self.info['option']
|
|
|
|
def block2n(self):
|
|
return task_chain(chains.control(self.info['Block2n']))
|
|
|
|
def queue(self):
|
|
return task_chain(chains.control(self.info['queue']))
|
|
|
|
class registers():
|
|
|
|
def __init__(self, regs):
|
|
self.regs = regs
|
|
|
|
def names(self):
|
|
return [field.name for field in self.regs.type.fields()]
|
|
|
|
def get(self, reg):
|
|
t = str(self.regs[reg].type)
|
|
if t in ['double']:
|
|
return float(self.regs[reg])
|
|
return int(self.regs[reg])
|
|
|
|
def format(self, reg):
|
|
t = self.regs[reg].type
|
|
if t in ['uint32_t', 'unsigned', 'unsigned long']:
|
|
return '%08x (%d)' % (val)
|
|
|
|
class control():
|
|
'''
|
|
Thread_Control has the following fields:
|
|
Object Objects_Control
|
|
RBNode RBTree_Node
|
|
current_state States_Control
|
|
current_priority Priority_Control
|
|
real_priority Priority_Control
|
|
resource_count uint32_t
|
|
Wait Thread_Wait_information
|
|
Timer Watchdog_Control
|
|
receive_packet MP_packet_Prefix* X
|
|
lock_mutex Chain_Control X
|
|
Resource_node Resource_Node X
|
|
is_global bool X
|
|
is_preemptible bool
|
|
Scheduler Thread_Scheduler_control
|
|
rtems_ada_self void* X
|
|
cpu_time_budget uint32_t
|
|
budget_algorithm Thread_CPU_budget_algorithms
|
|
budget_callout Thread_CPU_budget_algorithm_callout
|
|
cpu_time_used Thread_CPU_usage_t
|
|
Start Thread_Start_information
|
|
Post_switch_actions Thread_Action_control
|
|
Registers Context_Control
|
|
fp_context Context_Control_fp* X
|
|
libc_reent struct _reent*
|
|
API_Extensions void*[THREAD_API_LAST + 1]
|
|
task_variables rtems_task_variable_t* X
|
|
Key_Chain Chain_Control
|
|
Life Thread_Life_control
|
|
extensions void*[RTEMS_ZERO_LENGTH_ARRAY]
|
|
|
|
where 'X' means the field is condition and may no exist.
|
|
'''
|
|
|
|
def __init__(self, ctrl):
|
|
if ctrl.type.code == gdb.TYPE_CODE_PTR:
|
|
self.reference = ctrl
|
|
self.ctrl = ctrl.dereference()
|
|
else:
|
|
self.ctrl = ctrl
|
|
self.reference = ctrl.address
|
|
self.object = objects.control(ctrl['Object'])
|
|
self._executing = percpu.thread_active(self.reference)
|
|
self._heir = percpu.thread_heir(self.reference)
|
|
|
|
def id(self):
|
|
return self.object.id()
|
|
|
|
def name(self):
|
|
val = self.object.name()
|
|
if val == "":
|
|
val = '*'
|
|
return val
|
|
|
|
def executing(self):
|
|
return self._executing
|
|
|
|
def heir(self):
|
|
return self._heir
|
|
|
|
def current_state(self):
|
|
return state(self.ctrl['current_state']).to_string()
|
|
|
|
def current_priority(self):
|
|
return self.ctrl['current_priority']
|
|
|
|
def real_priority(self):
|
|
return self.ctrl['real_priority']
|
|
|
|
def resource_count(self):
|
|
return self.ctrl['resource_count']
|
|
|
|
def cpu_time_budget(self):
|
|
return self.ctrl['cpu_time_budget']
|
|
|
|
def cpu_time_used(self):
|
|
return cpu_usage(self.ctrl['cpu_time_used'])
|
|
|
|
def preemptible(self):
|
|
return self.ctrl['is_preemptible']
|
|
|
|
def cpu_time_budget(self):
|
|
return self.ctrl['cpu_time_budget']
|
|
|
|
def wait_info(self):
|
|
return wait_info(self.ctrl['Wait'])
|
|
|
|
def registers(self):
|
|
return registers(self.ctrl['Registers'])
|
|
|
|
def is_idle(self):
|
|
return (self.id() & 0xff000000) == 0x90000000
|
|
|
|
def brief(self):
|
|
return "'%s' (c:%d, r:%d)" % \
|
|
(self.name(), self.current_priority(), self.real_priority())
|
|
|
|
class queue():
|
|
"""Manage the Thread_queue_Control."""
|
|
|
|
def __init__(self, que):
|
|
if que.type.code == gdb.TYPE_CODE_PTR:
|
|
self.reference = que
|
|
self.que = que.dereference()
|
|
else:
|
|
self.que = que
|
|
self.reference = que.address
|
|
|
|
def fifo(self):
|
|
return str(self.que['discipline']) == 'THREAD_QUEUE_DISCIPLINE_FIFO'
|
|
|
|
def priority(self):
|
|
return str(self.que['discipline']) == 'THREAD_QUEUE_DISCIPLINE_PRIORITY'
|
|
|
|
def state(self):
|
|
return state(self.que['state']).to_string()
|
|
|
|
def tasks(self):
|
|
if self.fifo():
|
|
t = task_chain(chains.control(self.que['Queues']['Fifo']))
|
|
else:
|
|
t = task_tree(rbtrees.control(self.que['Queues']['Priority']))
|
|
return t
|