1126 lines
35 KiB
C
1126 lines
35 KiB
C
/*
|
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2006-04-30 Bernard first implementation
|
|
* 2006-05-04 Bernard add list_thread,
|
|
* list_sem,
|
|
* list_timer
|
|
* 2006-05-20 Bernard add list_mutex,
|
|
* list_mailbox,
|
|
* list_msgqueue,
|
|
* list_event,
|
|
* list_fevent,
|
|
* list_mempool
|
|
* 2006-06-03 Bernard display stack information in list_thread
|
|
* 2006-08-10 Bernard change version to invoke rt_show_version
|
|
* 2008-09-10 Bernard update the list function for finsh syscall
|
|
* list and sysvar list
|
|
* 2009-05-30 Bernard add list_device
|
|
* 2010-04-21 yi.qiu add list_module
|
|
* 2012-04-29 goprife improve the command line auto-complete feature.
|
|
* 2012-06-02 lgnq add list_memheap
|
|
* 2012-10-22 Bernard add MS VC++ patch.
|
|
* 2016-06-02 armink beautify the list_thread command
|
|
* 2018-11-22 Jesven list_thread add smp support
|
|
* 2018-12-27 Jesven Fix the problem that disable interrupt too long in list_thread
|
|
* Provide protection for the "first layer of objects" when list_*
|
|
* 2020-04-07 chenhui add clear
|
|
* 2022-07-02 Stanley Lwin add list command
|
|
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
|
|
* 2024-02-09 Bernard fix the version command
|
|
*/
|
|
|
|
#include <rthw.h>
|
|
#include <rtthread.h>
|
|
#include <string.h>
|
|
|
|
#ifdef RT_USING_FINSH
|
|
#include <finsh.h>
|
|
|
|
#define LIST_DFS_OPT_ID 0x100
|
|
#define LIST_FIND_OBJ_NR 8
|
|
|
|
static long clear(void)
|
|
{
|
|
rt_kprintf("\x1b[2J\x1b[H");
|
|
|
|
return 0;
|
|
}
|
|
MSH_CMD_EXPORT(clear, clear the terminal screen);
|
|
|
|
static long version(void)
|
|
{
|
|
rt_show_version();
|
|
|
|
return 0;
|
|
}
|
|
MSH_CMD_EXPORT(version, show RT-Thread version information);
|
|
|
|
rt_inline void object_split(int len)
|
|
{
|
|
while (len--) rt_kprintf("-");
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
rt_list_t *list;
|
|
rt_list_t **array;
|
|
rt_uint8_t type;
|
|
int nr; /* input: max nr, can't be 0 */
|
|
int nr_out; /* out: got nr */
|
|
} list_get_next_t;
|
|
|
|
static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
|
|
{
|
|
struct rt_object_information *info;
|
|
rt_list_t *list;
|
|
|
|
info = rt_object_get_information((enum rt_object_class_type)type);
|
|
list = &info->object_list;
|
|
|
|
p->list = list;
|
|
p->type = type;
|
|
p->array = array;
|
|
p->nr = nr;
|
|
p->nr_out = 0;
|
|
}
|
|
|
|
static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
|
|
{
|
|
int first_flag = 0;
|
|
rt_base_t level;
|
|
rt_list_t *node, *list;
|
|
rt_list_t **array;
|
|
struct rt_object_information *info;
|
|
int nr;
|
|
|
|
arg->nr_out = 0;
|
|
|
|
if (!arg->nr || !arg->type)
|
|
{
|
|
return (rt_list_t *)RT_NULL;
|
|
}
|
|
|
|
list = arg->list;
|
|
info = rt_list_entry(list, struct rt_object_information, object_list);
|
|
|
|
if (!current) /* find first */
|
|
{
|
|
node = list;
|
|
first_flag = 1;
|
|
}
|
|
else
|
|
{
|
|
node = current;
|
|
}
|
|
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
|
|
if (!first_flag)
|
|
{
|
|
struct rt_object *obj;
|
|
/* The node in the list? */
|
|
obj = rt_list_entry(node, struct rt_object, list);
|
|
if ((obj->type & ~RT_Object_Class_Static) != arg->type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
return (rt_list_t *)RT_NULL;
|
|
}
|
|
}
|
|
|
|
nr = 0;
|
|
array = arg->array;
|
|
while (1)
|
|
{
|
|
node = node->next;
|
|
|
|
if (node == list)
|
|
{
|
|
node = (rt_list_t *)RT_NULL;
|
|
break;
|
|
}
|
|
nr++;
|
|
*array++ = node;
|
|
if (nr == arg->nr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
arg->nr_out = nr;
|
|
return node;
|
|
}
|
|
|
|
long list_thread(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
const char *item_title = "thread";
|
|
const size_t tcb_strlen = sizeof(void *) * 2 + 2;
|
|
int maxlen;
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Thread, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
#ifdef RT_USING_SMP
|
|
rt_kprintf("%-*.*s cpu bind pri status sp stack size max used left tick error tcb addr\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" --- ---- --- ------- ---------- ---------- ------ ---------- -------");
|
|
rt_kprintf(" ");
|
|
object_split(tcb_strlen);
|
|
rt_kprintf("\n");
|
|
#else
|
|
rt_kprintf("%-*.*s pri status sp stack size max used left tick error tcb addr\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" --- ------- ---------- ---------- ------ ---------- -------");
|
|
rt_kprintf(" ");
|
|
object_split(tcb_strlen);
|
|
rt_kprintf("\n");
|
|
#endif /*RT_USING_SMP*/
|
|
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_thread thread_info, *thread;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
/* copy info */
|
|
rt_memcpy(&thread_info, obj, sizeof thread_info);
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
thread = (struct rt_thread *)obj;
|
|
{
|
|
rt_uint8_t stat;
|
|
rt_uint8_t *ptr;
|
|
|
|
#ifdef RT_USING_SMP
|
|
/* no synchronization applied since it's only for debug */
|
|
if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED)
|
|
rt_kprintf("%-*.*s %3d %3d %4d ", maxlen, RT_NAME_MAX,
|
|
thread->parent.name, RT_SCHED_CTX(thread).oncpu,
|
|
RT_SCHED_CTX(thread).bind_cpu,
|
|
RT_SCHED_PRIV(thread).current_priority);
|
|
else
|
|
rt_kprintf("%-*.*s N/A %3d %4d ", maxlen, RT_NAME_MAX,
|
|
thread->parent.name,
|
|
RT_SCHED_CTX(thread).bind_cpu,
|
|
RT_SCHED_PRIV(thread).current_priority);
|
|
|
|
#else
|
|
/* no synchronization applied since it's only for debug */
|
|
rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->parent.name, RT_SCHED_PRIV(thread).current_priority);
|
|
#endif /*RT_USING_SMP*/
|
|
stat = (RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK);
|
|
if (stat == RT_THREAD_READY) rt_kprintf(" ready ");
|
|
else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
|
|
else if (stat == RT_THREAD_INIT) rt_kprintf(" init ");
|
|
else if (stat == RT_THREAD_CLOSE) rt_kprintf(" close ");
|
|
else if (stat == RT_THREAD_RUNNING) rt_kprintf(" running");
|
|
|
|
#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
|
|
ptr = (rt_uint8_t *)thread->stack_addr + thread->stack_size - 1;
|
|
while (*ptr == '#')ptr --;
|
|
|
|
rt_kprintf(" 0x%08x 0x%08x %02d%% 0x%08x %s %p\n",
|
|
((rt_ubase_t)thread->sp - (rt_ubase_t)thread->stack_addr),
|
|
thread->stack_size,
|
|
((rt_ubase_t)ptr - (rt_ubase_t)thread->stack_addr) * 100 / thread->stack_size,
|
|
thread->remaining_tick,
|
|
rt_strerror(thread->error),
|
|
thread);
|
|
#else
|
|
ptr = (rt_uint8_t *)thread->stack_addr;
|
|
while (*ptr == '#') ptr ++;
|
|
rt_kprintf(" 0x%08x 0x%08x %02d%% 0x%08x %s %p\n",
|
|
thread->stack_size + ((rt_ubase_t)thread->stack_addr - (rt_ubase_t)thread->sp),
|
|
thread->stack_size,
|
|
(thread->stack_size - ((rt_ubase_t) ptr - (rt_ubase_t) thread->stack_addr)) * 100
|
|
/ thread->stack_size,
|
|
RT_SCHED_PRIV(thread).remaining_tick,
|
|
rt_strerror(thread->error),
|
|
thread);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef RT_USING_SEMAPHORE
|
|
long list_sem(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "semaphore";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Semaphore, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s v suspend thread\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" --- --------------\n");
|
|
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_semaphore *sem;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
sem = (struct rt_semaphore *)obj;
|
|
if (!rt_list_isempty(&sem->parent.suspend_thread))
|
|
{
|
|
rt_kprintf("%-*.*s %03d %d:",
|
|
maxlen, RT_NAME_MAX,
|
|
sem->parent.parent.name,
|
|
sem->value,
|
|
rt_list_len(&sem->parent.suspend_thread));
|
|
rt_susp_list_print(&(sem->parent.suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s %03d %d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
sem->parent.parent.name,
|
|
sem->value,
|
|
rt_list_len(&sem->parent.suspend_thread));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_SEMAPHORE */
|
|
|
|
#ifdef RT_USING_EVENT
|
|
long list_event(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "event";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Event, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s set suspend thread\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---------- --------------\n");
|
|
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_event *e;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
e = (struct rt_event *)obj;
|
|
if (!rt_list_isempty(&e->parent.suspend_thread))
|
|
{
|
|
rt_kprintf("%-*.*s 0x%08x %03d:",
|
|
maxlen, RT_NAME_MAX,
|
|
e->parent.parent.name,
|
|
e->set,
|
|
rt_list_len(&e->parent.suspend_thread));
|
|
rt_susp_list_print(&(e->parent.suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s 0x%08x 0\n",
|
|
maxlen, RT_NAME_MAX, e->parent.parent.name, e->set);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_EVENT */
|
|
|
|
#ifdef RT_USING_MUTEX
|
|
long list_mutex(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "mutex";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Mutex, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s owner hold priority suspend thread \n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" -------- ---- -------- --------------\n");
|
|
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_mutex *m;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
m = (struct rt_mutex *)obj;
|
|
if (!rt_list_isempty(&m->parent.suspend_thread))
|
|
{
|
|
rt_kprintf("%-*.*s %-8.*s %04d %8d %04d ",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
RT_NAME_MAX,
|
|
m->owner->parent.name,
|
|
m->hold,
|
|
m->priority,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
rt_susp_list_print(&(m->parent.suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s %-8.*s %04d %8d %04d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
RT_NAME_MAX,
|
|
m->owner->parent.name,
|
|
m->hold,
|
|
m->priority,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_MUTEX */
|
|
|
|
#ifdef RT_USING_MAILBOX
|
|
long list_mailbox(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "mailbox";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_MailBox, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s entry size suspend thread\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---- ---- --------------\n");
|
|
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_mailbox *m;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
m = (struct rt_mailbox *)obj;
|
|
if (!rt_list_isempty(&m->parent.suspend_thread))
|
|
{
|
|
rt_kprintf("%-*.*s %04d %04d %d:",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
m->entry,
|
|
m->size,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
rt_susp_list_print(&(m->parent.suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s %04d %04d %d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
m->entry,
|
|
m->size,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_MAILBOX */
|
|
|
|
#ifdef RT_USING_MESSAGEQUEUE
|
|
long list_msgqueue(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "msgqueue";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_MessageQueue, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s entry suspend thread\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---- --------------\n");
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_messagequeue *m;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
m = (struct rt_messagequeue *)obj;
|
|
if (!rt_list_isempty(&m->parent.suspend_thread))
|
|
{
|
|
rt_kprintf("%-*.*s %04d %d:",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
m->entry,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
rt_susp_list_print(&(m->parent.suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s %04d %d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
m->parent.parent.name,
|
|
m->entry,
|
|
rt_list_len(&m->parent.suspend_thread));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_MESSAGEQUEUE */
|
|
|
|
#ifdef RT_USING_MEMHEAP
|
|
long list_memheap(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "memheap";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_MemHeap, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s pool size max used size available size\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---------- ------------- --------------\n");
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_memheap *mh;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
mh = (struct rt_memheap *)obj;
|
|
|
|
rt_kprintf("%-*.*s %-010d %-013d %-05d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
mh->parent.name,
|
|
mh->pool_size,
|
|
mh->max_used_size,
|
|
mh->available_size);
|
|
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_MEMHEAP */
|
|
|
|
#ifdef RT_USING_MEMPOOL
|
|
long list_mempool(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "mempool";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_MemPool, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s block total free suspend thread\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---- ---- ---- --------------\n");
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_mempool *mp;
|
|
int suspend_thread_count;
|
|
rt_list_t *node;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
mp = (struct rt_mempool *)obj;
|
|
|
|
suspend_thread_count = 0;
|
|
rt_list_for_each(node, &mp->suspend_thread)
|
|
{
|
|
suspend_thread_count++;
|
|
}
|
|
|
|
if (suspend_thread_count > 0)
|
|
{
|
|
rt_kprintf("%-*.*s %04d %04d %04d %d:",
|
|
maxlen, RT_NAME_MAX,
|
|
mp->parent.name,
|
|
mp->block_size,
|
|
mp->block_total_count,
|
|
mp->block_free_count,
|
|
suspend_thread_count);
|
|
rt_susp_list_print(&(mp->suspend_thread));
|
|
rt_kprintf("\n");
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("%-*.*s %04d %04d %04d %d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
mp->parent.name,
|
|
mp->block_size,
|
|
mp->block_total_count,
|
|
mp->block_free_count,
|
|
suspend_thread_count);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_MEMPOOL */
|
|
|
|
long list_timer(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
|
|
int maxlen;
|
|
const char *item_title = "timer";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Timer, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s periodic timeout activated mode\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" ---------- ---------- ----------- ---------\n");
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_timer *timer;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
timer = (struct rt_timer *)obj;
|
|
rt_kprintf("%-*.*s 0x%08x 0x%08x ",
|
|
maxlen, RT_NAME_MAX,
|
|
timer->parent.name,
|
|
timer->init_tick,
|
|
timer->timeout_tick);
|
|
if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
|
|
rt_kprintf("activated ");
|
|
else
|
|
rt_kprintf("deactivated ");
|
|
if (timer->parent.flag & RT_TIMER_FLAG_PERIODIC)
|
|
rt_kprintf("periodic\n");
|
|
else
|
|
rt_kprintf("one shot\n");
|
|
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
rt_kprintf("current tick:0x%08x\n", rt_tick_get());
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef RT_USING_DEVICE
|
|
static char *const device_type_str[RT_Device_Class_Unknown] =
|
|
{
|
|
"Character Device",
|
|
"Block Device",
|
|
"Network Interface",
|
|
"MTD Device",
|
|
"CAN Device",
|
|
"RTC",
|
|
"Sound Device",
|
|
"Graphic Device",
|
|
"I2C Bus",
|
|
"USB Slave Device",
|
|
"USB Host Bus",
|
|
"USB OTG Bus",
|
|
"SPI Bus",
|
|
"SPI Device",
|
|
"SDIO Bus",
|
|
"PM Pseudo Device",
|
|
"Pipe",
|
|
"Portal Device",
|
|
"Timer Device",
|
|
"Miscellaneous Device",
|
|
"Sensor Device",
|
|
"Touch Device",
|
|
"Phy Device",
|
|
"Security Device",
|
|
"WLAN Device",
|
|
"Pin Device",
|
|
"ADC Device",
|
|
"DAC Device",
|
|
"WDT Device",
|
|
"PWM Device",
|
|
"Bus Device",
|
|
};
|
|
|
|
long list_device(void)
|
|
{
|
|
rt_base_t level;
|
|
list_get_next_t find_arg;
|
|
struct rt_object_information *info;
|
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
|
const char *device_type;
|
|
|
|
int maxlen;
|
|
const char *item_title = "device";
|
|
|
|
list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
|
|
|
maxlen = RT_NAME_MAX;
|
|
|
|
rt_kprintf("%-*.*s type ref count\n", maxlen, maxlen, item_title);
|
|
object_split(maxlen);
|
|
rt_kprintf(" -------------------- ----------\n");
|
|
do
|
|
{
|
|
next = list_get_next(next, &find_arg);
|
|
{
|
|
int i;
|
|
for (i = 0; i < find_arg.nr_out; i++)
|
|
{
|
|
struct rt_object *obj;
|
|
struct rt_device *device;
|
|
|
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
|
{
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
continue;
|
|
}
|
|
|
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
|
|
|
device = (struct rt_device *)obj;
|
|
device_type = "Unknown";
|
|
if (device->type < RT_Device_Class_Unknown &&
|
|
device_type_str[device->type] != RT_NULL)
|
|
{
|
|
device_type = device_type_str[device->type];
|
|
}
|
|
rt_kprintf("%-*.*s %-20s %-8d\n",
|
|
maxlen, RT_NAME_MAX,
|
|
device->parent.name,
|
|
device_type,
|
|
device->ref_count);
|
|
|
|
}
|
|
}
|
|
}
|
|
while (next != (rt_list_t *)RT_NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* RT_USING_DEVICE */
|
|
|
|
#ifndef FINSH_USING_OPTION_COMPLETION
|
|
static int cmd_list(int argc, char **argv)
|
|
{
|
|
if(argc == 2)
|
|
{
|
|
if(strcmp(argv[1], "thread") == 0)
|
|
{
|
|
list_thread();
|
|
}
|
|
else if(strcmp(argv[1], "timer") == 0)
|
|
{
|
|
list_timer();
|
|
}
|
|
#ifdef RT_USING_SEMAPHORE
|
|
else if(strcmp(argv[1], "sem") == 0)
|
|
{
|
|
list_sem();
|
|
}
|
|
#endif /* RT_USING_SEMAPHORE */
|
|
#ifdef RT_USING_EVENT
|
|
else if(strcmp(argv[1], "event") == 0)
|
|
{
|
|
list_event();
|
|
}
|
|
#endif /* RT_USING_EVENT */
|
|
#ifdef RT_USING_MUTEX
|
|
else if(strcmp(argv[1], "mutex") == 0)
|
|
{
|
|
list_mutex();
|
|
}
|
|
#endif /* RT_USING_MUTEX */
|
|
#ifdef RT_USING_MAILBOX
|
|
else if(strcmp(argv[1], "mailbox") == 0)
|
|
{
|
|
list_mailbox();
|
|
}
|
|
#endif /* RT_USING_MAILBOX */
|
|
#ifdef RT_USING_MESSAGEQUEUE
|
|
else if(strcmp(argv[1], "msgqueue") == 0)
|
|
{
|
|
list_msgqueue();
|
|
}
|
|
#endif /* RT_USING_MESSAGEQUEUE */
|
|
#ifdef RT_USING_MEMHEAP
|
|
else if(strcmp(argv[1], "memheap") == 0)
|
|
{
|
|
list_memheap();
|
|
}
|
|
#endif /* RT_USING_MEMHEAP */
|
|
#ifdef RT_USING_MEMPOOL
|
|
else if(strcmp(argv[1], "mempool") == 0)
|
|
{
|
|
list_mempool();
|
|
}
|
|
#endif /* RT_USING_MEMPOOL */
|
|
#ifdef RT_USING_DEVICE
|
|
else if(strcmp(argv[1], "device") == 0)
|
|
{
|
|
list_device();
|
|
}
|
|
#endif /* RT_USING_DEVICE */
|
|
#ifdef RT_USING_DFS
|
|
else if(strcmp(argv[1], "fd") == 0)
|
|
{
|
|
extern int list_fd(void);
|
|
list_fd();
|
|
}
|
|
#endif /* RT_USING_DFS */
|
|
else
|
|
{
|
|
goto _usage;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
_usage:
|
|
rt_kprintf("Usage: list [options]\n");
|
|
rt_kprintf("[options]:\n");
|
|
rt_kprintf(" %-12s - list threads\n", "thread");
|
|
rt_kprintf(" %-12s - list timers\n", "timer");
|
|
#ifdef RT_USING_SEMAPHORE
|
|
rt_kprintf(" %-12s - list semaphores\n", "sem");
|
|
#endif /* RT_USING_SEMAPHORE */
|
|
#ifdef RT_USING_MUTEX
|
|
rt_kprintf(" %-12s - list mutexs\n", "mutex");
|
|
#endif /* RT_USING_MUTEX */
|
|
#ifdef RT_USING_EVENT
|
|
rt_kprintf(" %-12s - list events\n", "event");
|
|
#endif /* RT_USING_EVENT */
|
|
#ifdef RT_USING_MAILBOX
|
|
rt_kprintf(" %-12s - list mailboxs\n", "mailbox");
|
|
#endif /* RT_USING_MAILBOX */
|
|
#ifdef RT_USING_MESSAGEQUEUE
|
|
rt_kprintf(" %-12s - list message queues\n", "msgqueue");
|
|
#endif /* RT_USING_MESSAGEQUEUE */
|
|
#ifdef RT_USING_MEMHEAP
|
|
rt_kprintf(" %-12s - list memory heaps\n", "memheap");
|
|
#endif /* RT_USING_MEMHEAP */
|
|
#ifdef RT_USING_MEMPOOL
|
|
rt_kprintf(" %-12s - list memory pools\n", "mempool");
|
|
#endif /* RT_USING_MEMPOOL */
|
|
#ifdef RT_USING_DEVICE
|
|
rt_kprintf(" %-12s - list devices\n", "device");
|
|
#endif /* RT_USING_DEVICE */
|
|
#ifdef RT_USING_DFS
|
|
rt_kprintf(" %-12s - list file descriptors\n", "fd");
|
|
#endif /* RT_USING_DFS */
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
CMD_OPTIONS_STATEMENT(cmd_list)
|
|
static int cmd_list(int argc, char **argv)
|
|
{
|
|
if (argc == 2)
|
|
{
|
|
switch (MSH_OPT_ID_GET(cmd_list))
|
|
{
|
|
case RT_Object_Class_Thread: list_thread(); break;
|
|
case RT_Object_Class_Timer: list_timer(); break;
|
|
#ifdef RT_USING_SEMAPHORE
|
|
case RT_Object_Class_Semaphore: list_sem(); break;
|
|
#endif /* RT_USING_SEMAPHORE */
|
|
#ifdef RT_USING_EVENT
|
|
case RT_Object_Class_Event: list_event(); break;
|
|
#endif /* RT_USING_EVENT */
|
|
#ifdef RT_USING_MUTEX
|
|
case RT_Object_Class_Mutex: list_mutex(); break;
|
|
#endif /* RT_USING_MUTEX */
|
|
#ifdef RT_USING_MAILBOX
|
|
case RT_Object_Class_MailBox: list_mailbox(); break;
|
|
#endif /* RT_USING_MAILBOX */
|
|
#ifdef RT_USING_MESSAGEQUEUE
|
|
case RT_Object_Class_MessageQueue: list_msgqueue(); break;
|
|
#endif /* RT_USING_MESSAGEQUEUE */
|
|
#ifdef RT_USING_MEMHEAP
|
|
case RT_Object_Class_MemHeap: list_memheap(); break;
|
|
#endif /* RT_USING_MEMHEAP */
|
|
#ifdef RT_USING_MEMPOOL
|
|
case RT_Object_Class_MemPool: list_mempool(); break;
|
|
#endif /* RT_USING_MEMPOOL */
|
|
#ifdef RT_USING_DEVICE
|
|
case RT_Object_Class_Device: list_device(); break;
|
|
#endif /* RT_USING_DEVICE */
|
|
#ifdef RT_USING_DFS
|
|
case LIST_DFS_OPT_ID:
|
|
{
|
|
extern int list_fd(void);
|
|
list_fd();
|
|
break;
|
|
}
|
|
#endif /* RT_USING_DFS */
|
|
default:
|
|
goto _usage;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
_usage:
|
|
rt_kprintf("Usage: list [options]\n");
|
|
rt_kprintf("[options]:\n");
|
|
MSH_OPT_DUMP(cmd_list);
|
|
return 0;
|
|
}
|
|
CMD_OPTIONS_NODE_START(cmd_list)
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Thread, thread, list threads)
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Timer, timer, list timers)
|
|
#ifdef RT_USING_SEMAPHORE
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Semaphore, sem, list semaphores)
|
|
#endif /* RT_USING_SEMAPHORE */
|
|
#ifdef RT_USING_EVENT
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Event, event, list events)
|
|
#endif /* RT_USING_EVENT */
|
|
#ifdef RT_USING_MUTEX
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Mutex, mutex, list mutexs)
|
|
#endif /* RT_USING_MUTEX */
|
|
#ifdef RT_USING_MAILBOX
|
|
CMD_OPTIONS_NODE(RT_Object_Class_MailBox, mailbox, list mailboxs)
|
|
#endif /* RT_USING_MAILBOX */
|
|
#ifdef RT_USING_MESSAGEQUEUE
|
|
CMD_OPTIONS_NODE(RT_Object_Class_MessageQueue, msgqueue, list message queues)
|
|
#endif /* RT_USING_MESSAGEQUEUE */
|
|
#ifdef RT_USING_MEMHEAP
|
|
CMD_OPTIONS_NODE(RT_Object_Class_MemHeap, memheap, list memory heaps)
|
|
#endif /* RT_USING_MEMHEAP */
|
|
#ifdef RT_USING_MEMPOOL
|
|
CMD_OPTIONS_NODE(RT_Object_Class_MemPool, mempool, list memory pools)
|
|
#endif /* RT_USING_MEMPOOL */
|
|
#ifdef RT_USING_DEVICE
|
|
CMD_OPTIONS_NODE(RT_Object_Class_Device, device, list devices)
|
|
#endif /* RT_USING_DEVICE */
|
|
#ifdef RT_USING_DFS
|
|
CMD_OPTIONS_NODE(LIST_DFS_OPT_ID, fd, list file descriptors)
|
|
#endif /* RT_USING_DFS */
|
|
CMD_OPTIONS_NODE_END
|
|
#endif /* FINSH_USING_OPTION_COMPLETION */
|
|
MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects, optenable);
|
|
|
|
#endif /* RT_USING_FINSH */
|