1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2006-04-30     Bernard      first implementation
9  * 2006-05-04     Bernard      add list_thread,
10  *                                 list_sem,
11  *                                 list_timer
12  * 2006-05-20     Bernard      add list_mutex,
13  *                                 list_mailbox,
14  *                                 list_msgqueue,
15  *                                 list_event,
16  *                                 list_fevent,
17  *                                 list_mempool
18  * 2006-06-03     Bernard      display stack information in list_thread
19  * 2006-08-10     Bernard      change version to invoke rt_show_version
20  * 2008-09-10     Bernard      update the list function for finsh syscall
21  *                                 list and sysvar list
22  * 2009-05-30     Bernard      add list_device
23  * 2010-04-21     yi.qiu       add list_module
24  * 2012-04-29     goprife      improve the command line auto-complete feature.
25  * 2012-06-02     lgnq         add list_memheap
26  * 2012-10-22     Bernard      add MS VC++ patch.
27  * 2016-06-02     armink       beautify the list_thread command
28  * 2018-11-22     Jesven       list_thread add smp support
29  * 2018-12-27     Jesven       Fix the problem that disable interrupt too long in list_thread
30  *                             Provide protection for the "first layer of objects" when list_*
31  * 2020-04-07     chenhui      add clear
32  * 2022-07-02     Stanley Lwin add list command
33  * 2023-09-15     xqyjlj       perf rt_hw_interrupt_disable/enable
34  * 2024-02-09     Bernard      fix the version command
35  */
36 
37 #include <rthw.h>
38 #include <rtthread.h>
39 #include <string.h>
40 
41 #ifdef RT_USING_FINSH
42 #include <finsh.h>
43 
44 #define LIST_DFS_OPT_ID 0x100
45 #define LIST_FIND_OBJ_NR 8
46 
clear(void)47 static long clear(void)
48 {
49     rt_kprintf("\x1b[2J\x1b[H");
50 
51     return 0;
52 }
53 MSH_CMD_EXPORT(clear, clear the terminal screen);
54 
version(void)55 static long version(void)
56 {
57     rt_show_version();
58 
59     return 0;
60 }
61 MSH_CMD_EXPORT(version, show RT-Thread version information);
62 
object_split(int len)63 rt_inline void object_split(int len)
64 {
65     while (len--) rt_kprintf("-");
66 }
67 
68 typedef struct
69 {
70     rt_list_t *list;
71     rt_list_t **array;
72     rt_uint8_t type;
73     int nr;             /* input: max nr, can't be 0 */
74     int nr_out;         /* out: got nr */
75 } list_get_next_t;
76 
list_find_init(list_get_next_t * p,rt_uint8_t type,rt_list_t ** array,int nr)77 static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
78 {
79     struct rt_object_information *info;
80     rt_list_t *list;
81 
82     info = rt_object_get_information((enum rt_object_class_type)type);
83     list = &info->object_list;
84 
85     p->list = list;
86     p->type = type;
87     p->array = array;
88     p->nr = nr;
89     p->nr_out = 0;
90 }
91 
list_get_next(rt_list_t * current,list_get_next_t * arg)92 static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
93 {
94     int first_flag = 0;
95     rt_base_t level;
96     rt_list_t *node, *list;
97     rt_list_t **array;
98     struct rt_object_information *info;
99     int nr;
100 
101     arg->nr_out = 0;
102 
103     if (!arg->nr || !arg->type)
104     {
105         return (rt_list_t *)RT_NULL;
106     }
107 
108     list = arg->list;
109     info = rt_list_entry(list, struct rt_object_information, object_list);
110 
111     if (!current) /* find first */
112     {
113         node = list;
114         first_flag = 1;
115     }
116     else
117     {
118         node = current;
119     }
120 
121     level = rt_spin_lock_irqsave(&info->spinlock);
122 
123     if (!first_flag)
124     {
125         struct rt_object *obj;
126         /* The node in the list? */
127         obj = rt_list_entry(node, struct rt_object, list);
128         if ((obj->type & ~RT_Object_Class_Static) != arg->type)
129         {
130             rt_spin_unlock_irqrestore(&info->spinlock, level);
131             return (rt_list_t *)RT_NULL;
132         }
133     }
134 
135     nr = 0;
136     array = arg->array;
137     while (1)
138     {
139         node = node->next;
140 
141         if (node == list)
142         {
143             node = (rt_list_t *)RT_NULL;
144             break;
145         }
146         nr++;
147         *array++ = node;
148         if (nr == arg->nr)
149         {
150             break;
151         }
152     }
153 
154     rt_spin_unlock_irqrestore(&info->spinlock, level);
155     arg->nr_out = nr;
156     return node;
157 }
158 
list_thread(void)159 long list_thread(void)
160 {
161     rt_base_t level;
162     list_get_next_t find_arg;
163     struct rt_object_information *info;
164     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
165     rt_list_t *next = (rt_list_t *)RT_NULL;
166     const char *item_title = "thread";
167     const size_t tcb_strlen = sizeof(void *) * 2 + 2;
168     int maxlen;
169 
170     list_find_init(&find_arg, RT_Object_Class_Thread, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
171     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
172 
173     maxlen = RT_NAME_MAX;
174 
175 #ifdef RT_USING_SMP
176     rt_kprintf("%-*.*s cpu bind pri  status      sp     stack size max used left tick   error  tcb addr\n", maxlen, maxlen, item_title);
177     object_split(maxlen);
178     rt_kprintf(" --- ---- ---  ------- ---------- ----------  ------  ---------- -------");
179     rt_kprintf(" ");
180     object_split(tcb_strlen);
181     rt_kprintf("\n");
182 #else
183     rt_kprintf("%-*.*s pri  status      sp     stack size max used left tick   error  tcb addr\n", maxlen, maxlen, item_title);
184     object_split(maxlen);
185     rt_kprintf(" ---  ------- ---------- ----------  ------  ---------- -------");
186     rt_kprintf(" ");
187     object_split(tcb_strlen);
188     rt_kprintf("\n");
189 #endif /*RT_USING_SMP*/
190 
191     do
192     {
193         next = list_get_next(next, &find_arg);
194         {
195             int i;
196             for (i = 0; i < find_arg.nr_out; i++)
197             {
198                 struct rt_object *obj;
199                 struct rt_thread thread_info, *thread;
200 
201                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
202                 level = rt_spin_lock_irqsave(&info->spinlock);
203 
204                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
205                 {
206                     rt_spin_unlock_irqrestore(&info->spinlock, level);
207                     continue;
208                 }
209                 /* copy info */
210                 rt_memcpy(&thread_info, obj, sizeof thread_info);
211                 rt_spin_unlock_irqrestore(&info->spinlock, level);
212 
213                 thread = (struct rt_thread *)obj;
214                 {
215                     rt_uint8_t stat;
216                     rt_uint8_t *ptr;
217 
218 #ifdef RT_USING_SMP
219                     /* no synchronization applied since it's only for debug */
220                     if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED)
221                         rt_kprintf("%-*.*s %3d %3d %4d ", maxlen, RT_NAME_MAX,
222                                    thread->parent.name, RT_SCHED_CTX(thread).oncpu,
223                                    RT_SCHED_CTX(thread).bind_cpu,
224                                    RT_SCHED_PRIV(thread).current_priority);
225                     else
226                         rt_kprintf("%-*.*s N/A %3d %4d ", maxlen, RT_NAME_MAX,
227                                    thread->parent.name,
228                                    RT_SCHED_CTX(thread).bind_cpu,
229                                    RT_SCHED_PRIV(thread).current_priority);
230 
231 #else
232                     /* no synchronization applied since it's only for debug */
233                     rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->parent.name, RT_SCHED_PRIV(thread).current_priority);
234 #endif /*RT_USING_SMP*/
235                     stat = (RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK);
236                     if (stat == RT_THREAD_READY)        rt_kprintf(" ready  ");
237                     else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
238                     else if (stat == RT_THREAD_INIT)    rt_kprintf(" init   ");
239                     else if (stat == RT_THREAD_CLOSE)   rt_kprintf(" close  ");
240                     else if (stat == RT_THREAD_RUNNING) rt_kprintf(" running");
241 
242 #if defined(ARCH_CPU_STACK_GROWS_UPWARD)
243                     ptr = (rt_uint8_t *)thread->stack_addr + thread->stack_size - 1;
244                     while (*ptr == '#')ptr --;
245 
246                     rt_kprintf(" 0x%08x 0x%08x    %02d%%   0x%08x %s %p\n",
247                                ((rt_ubase_t)thread->sp - (rt_ubase_t)thread->stack_addr),
248                                thread->stack_size,
249                                ((rt_ubase_t)ptr - (rt_ubase_t)thread->stack_addr) * 100 / thread->stack_size,
250                                thread->remaining_tick,
251                                rt_strerror(thread->error),
252                                thread);
253 #else
254                     ptr = (rt_uint8_t *)thread->stack_addr;
255                     while (*ptr == '#') ptr ++;
256                     rt_kprintf(" 0x%08x 0x%08x    %02d%%   0x%08x %s %p\n",
257                                thread->stack_size + ((rt_ubase_t)thread->stack_addr - (rt_ubase_t)thread->sp),
258                                thread->stack_size,
259                                (thread->stack_size - ((rt_ubase_t) ptr - (rt_ubase_t) thread->stack_addr)) * 100
260                                / thread->stack_size,
261                                RT_SCHED_PRIV(thread).remaining_tick,
262                                rt_strerror(thread->error),
263                                thread);
264 #endif
265                 }
266             }
267         }
268     }
269     while (next != (rt_list_t *)RT_NULL);
270 
271     return 0;
272 }
273 
274 #ifdef RT_USING_SEMAPHORE
list_sem(void)275 long list_sem(void)
276 {
277     rt_base_t level;
278     list_get_next_t find_arg;
279     struct rt_object_information *info;
280     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
281     rt_list_t *next = (rt_list_t *)RT_NULL;
282 
283     int maxlen;
284     const char *item_title = "semaphore";
285 
286     list_find_init(&find_arg, RT_Object_Class_Semaphore, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
287     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
288 
289     maxlen = RT_NAME_MAX;
290 
291     rt_kprintf("%-*.*s v   suspend thread\n", maxlen, maxlen, item_title);
292     object_split(maxlen);
293     rt_kprintf(" --- --------------\n");
294 
295     do
296     {
297         next = list_get_next(next, &find_arg);
298         {
299             int i;
300             for (i = 0; i < find_arg.nr_out; i++)
301             {
302                 struct rt_object *obj;
303                 struct rt_semaphore *sem;
304 
305                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
306                 level = rt_spin_lock_irqsave(&info->spinlock);
307                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
308                 {
309                     rt_spin_unlock_irqrestore(&info->spinlock, level);
310                     continue;
311                 }
312                 rt_spin_unlock_irqrestore(&info->spinlock, level);
313 
314                 sem = (struct rt_semaphore *)obj;
315                 if (!rt_list_isempty(&sem->parent.suspend_thread))
316                 {
317                     rt_kprintf("%-*.*s %03d %d:",
318                                maxlen, RT_NAME_MAX,
319                                sem->parent.parent.name,
320                                sem->value,
321                                rt_list_len(&sem->parent.suspend_thread));
322                     rt_susp_list_print(&(sem->parent.suspend_thread));
323                     rt_kprintf("\n");
324                 }
325                 else
326                 {
327                     rt_kprintf("%-*.*s %03d %d\n",
328                                maxlen, RT_NAME_MAX,
329                                sem->parent.parent.name,
330                                sem->value,
331                                rt_list_len(&sem->parent.suspend_thread));
332                 }
333             }
334         }
335     }
336     while (next != (rt_list_t *)RT_NULL);
337 
338     return 0;
339 }
340 #endif /* RT_USING_SEMAPHORE */
341 
342 #ifdef RT_USING_EVENT
list_event(void)343 long list_event(void)
344 {
345     rt_base_t level;
346     list_get_next_t find_arg;
347     struct rt_object_information *info;
348     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
349     rt_list_t *next = (rt_list_t *)RT_NULL;
350 
351     int maxlen;
352     const char *item_title = "event";
353 
354     list_find_init(&find_arg, RT_Object_Class_Event, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
355     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
356 
357     maxlen = RT_NAME_MAX;
358 
359     rt_kprintf("%-*.*s      set    suspend thread\n", maxlen, maxlen, item_title);
360     object_split(maxlen);
361     rt_kprintf("  ---------- --------------\n");
362 
363     do
364     {
365         next = list_get_next(next, &find_arg);
366         {
367             int i;
368             for (i = 0; i < find_arg.nr_out; i++)
369             {
370                 struct rt_object *obj;
371                 struct rt_event *e;
372 
373                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
374                 level = rt_spin_lock_irqsave(&info->spinlock);
375                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
376                 {
377                     rt_spin_unlock_irqrestore(&info->spinlock, level);
378                     continue;
379                 }
380 
381                 rt_spin_unlock_irqrestore(&info->spinlock, level);
382 
383                 e = (struct rt_event *)obj;
384                 if (!rt_list_isempty(&e->parent.suspend_thread))
385                 {
386                     rt_kprintf("%-*.*s  0x%08x %03d:",
387                                maxlen, RT_NAME_MAX,
388                                e->parent.parent.name,
389                                e->set,
390                                rt_list_len(&e->parent.suspend_thread));
391                     rt_susp_list_print(&(e->parent.suspend_thread));
392                     rt_kprintf("\n");
393                 }
394                 else
395                 {
396                     rt_kprintf("%-*.*s  0x%08x 0\n",
397                                maxlen, RT_NAME_MAX, e->parent.parent.name, e->set);
398                 }
399             }
400         }
401     }
402     while (next != (rt_list_t *)RT_NULL);
403 
404     return 0;
405 }
406 #endif /* RT_USING_EVENT */
407 
408 #ifdef RT_USING_MUTEX
list_mutex(void)409 long list_mutex(void)
410 {
411     rt_base_t level;
412     list_get_next_t find_arg;
413     struct rt_object_information *info;
414     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
415     rt_list_t *next = (rt_list_t *)RT_NULL;
416 
417     int maxlen;
418     const char *item_title = "mutex";
419 
420     list_find_init(&find_arg, RT_Object_Class_Mutex, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
421     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
422 
423     maxlen = RT_NAME_MAX;
424 
425     rt_kprintf("%-*.*s   owner  hold priority suspend thread \n", maxlen, maxlen, item_title);
426     object_split(maxlen);
427     rt_kprintf(" -------- ---- -------- --------------\n");
428 
429     do
430     {
431         next = list_get_next(next, &find_arg);
432         {
433             int i;
434             for (i = 0; i < find_arg.nr_out; i++)
435             {
436                 struct rt_object *obj;
437                 struct rt_mutex *m;
438 
439                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
440                 level = rt_spin_lock_irqsave(&info->spinlock);
441                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
442                 {
443                     rt_spin_unlock_irqrestore(&info->spinlock, level);
444                     continue;
445                 }
446 
447                 rt_spin_unlock_irqrestore(&info->spinlock, level);
448 
449                 m = (struct rt_mutex *)obj;
450                 if (!rt_list_isempty(&m->parent.suspend_thread))
451                 {
452                     rt_kprintf("%-*.*s %-8.*s %04d %8d  %04d ",
453                            maxlen, RT_NAME_MAX,
454                            m->parent.parent.name,
455                            RT_NAME_MAX,
456                            (m->owner == RT_NULL) ? "(null)" : m->owner->parent.name,
457                            m->hold,
458                            m->priority,
459                            rt_list_len(&m->parent.suspend_thread));
460                     rt_susp_list_print(&(m->parent.suspend_thread));
461                     rt_kprintf("\n");
462                 }
463                 else
464                 {
465                     rt_kprintf("%-*.*s %-8.*s %04d %8d  %04d\n",
466                            maxlen, RT_NAME_MAX,
467                            m->parent.parent.name,
468                            RT_NAME_MAX,
469                            (m->owner == RT_NULL) ? "(null)" : m->owner->parent.name,
470                            m->hold,
471                            m->priority,
472                            rt_list_len(&m->parent.suspend_thread));
473                 }
474             }
475         }
476     }
477     while (next != (rt_list_t *)RT_NULL);
478 
479     return 0;
480 }
481 #endif /* RT_USING_MUTEX */
482 
483 #ifdef RT_USING_MAILBOX
list_mailbox(void)484 long list_mailbox(void)
485 {
486     rt_base_t level;
487     list_get_next_t find_arg;
488     struct rt_object_information *info;
489     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
490     rt_list_t *next = (rt_list_t *)RT_NULL;
491 
492     int maxlen;
493     const char *item_title = "mailbox";
494 
495     list_find_init(&find_arg, RT_Object_Class_MailBox, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
496     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
497 
498     maxlen = RT_NAME_MAX;
499 
500     rt_kprintf("%-*.*s entry size suspend thread\n", maxlen, maxlen, item_title);
501     object_split(maxlen);
502     rt_kprintf(" ----  ---- --------------\n");
503 
504     do
505     {
506         next = list_get_next(next, &find_arg);
507         {
508             int i;
509             for (i = 0; i < find_arg.nr_out; i++)
510             {
511                 struct rt_object *obj;
512                 struct rt_mailbox *m;
513 
514                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
515                 level = rt_spin_lock_irqsave(&info->spinlock);
516                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
517                 {
518                     rt_spin_unlock_irqrestore(&info->spinlock, level);
519                     continue;
520                 }
521 
522                 rt_spin_unlock_irqrestore(&info->spinlock, level);
523 
524                 m = (struct rt_mailbox *)obj;
525                 if (!rt_list_isempty(&m->parent.suspend_thread))
526                 {
527                     rt_kprintf("%-*.*s %04d  %04d %d:",
528                                maxlen, RT_NAME_MAX,
529                                m->parent.parent.name,
530                                m->entry,
531                                m->size,
532                                rt_list_len(&m->parent.suspend_thread));
533                     rt_susp_list_print(&(m->parent.suspend_thread));
534                     rt_kprintf("\n");
535                 }
536                 else
537                 {
538                     rt_kprintf("%-*.*s %04d  %04d %d\n",
539                                maxlen, RT_NAME_MAX,
540                                m->parent.parent.name,
541                                m->entry,
542                                m->size,
543                                rt_list_len(&m->parent.suspend_thread));
544                 }
545 
546             }
547         }
548     }
549     while (next != (rt_list_t *)RT_NULL);
550 
551     return 0;
552 }
553 #endif /* RT_USING_MAILBOX */
554 
555 #ifdef RT_USING_MESSAGEQUEUE
list_msgqueue(void)556 long list_msgqueue(void)
557 {
558     rt_base_t level;
559     list_get_next_t find_arg;
560     struct rt_object_information *info;
561     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
562     rt_list_t *next = (rt_list_t *)RT_NULL;
563 
564     int maxlen;
565     const char *item_title = "msgqueue";
566 
567     list_find_init(&find_arg, RT_Object_Class_MessageQueue, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
568     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
569 
570     maxlen = RT_NAME_MAX;
571 
572     rt_kprintf("%-*.*s entry suspend thread\n", maxlen, maxlen, item_title);
573     object_split(maxlen);
574     rt_kprintf(" ----  --------------\n");
575     do
576     {
577         next = list_get_next(next, &find_arg);
578         {
579             int i;
580             for (i = 0; i < find_arg.nr_out; i++)
581             {
582                 struct rt_object *obj;
583                 struct rt_messagequeue *m;
584 
585                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
586                 level = rt_spin_lock_irqsave(&info->spinlock);
587                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
588                 {
589                     rt_spin_unlock_irqrestore(&info->spinlock, level);
590                     continue;
591                 }
592 
593                 rt_spin_unlock_irqrestore(&info->spinlock, level);
594 
595                 m = (struct rt_messagequeue *)obj;
596                 if (!rt_list_isempty(&m->parent.suspend_thread))
597                 {
598                     rt_kprintf("%-*.*s %04d  %d:",
599                                maxlen, RT_NAME_MAX,
600                                m->parent.parent.name,
601                                m->entry,
602                                rt_list_len(&m->parent.suspend_thread));
603                     rt_susp_list_print(&(m->parent.suspend_thread));
604                     rt_kprintf("\n");
605                 }
606                 else
607                 {
608                     rt_kprintf("%-*.*s %04d  %d\n",
609                                maxlen, RT_NAME_MAX,
610                                m->parent.parent.name,
611                                m->entry,
612                                rt_list_len(&m->parent.suspend_thread));
613                 }
614             }
615         }
616     }
617     while (next != (rt_list_t *)RT_NULL);
618 
619     return 0;
620 }
621 #endif /* RT_USING_MESSAGEQUEUE */
622 
623 #ifdef RT_USING_MEMHEAP
list_memheap(void)624 long list_memheap(void)
625 {
626     rt_base_t level;
627     list_get_next_t find_arg;
628     struct rt_object_information *info;
629     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
630     rt_list_t *next = (rt_list_t *)RT_NULL;
631 
632     int maxlen;
633     const char *item_title = "memheap";
634 
635     list_find_init(&find_arg, RT_Object_Class_MemHeap, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
636     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
637 
638     maxlen = RT_NAME_MAX;
639 
640     rt_kprintf("%-*.*s  pool size  max used size available size\n", maxlen, maxlen, item_title);
641     object_split(maxlen);
642     rt_kprintf(" ---------- ------------- --------------\n");
643     do
644     {
645         next = list_get_next(next, &find_arg);
646         {
647             int i;
648             for (i = 0; i < find_arg.nr_out; i++)
649             {
650                 struct rt_object *obj;
651                 struct rt_memheap *mh;
652 
653                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
654                 level = rt_spin_lock_irqsave(&info->spinlock);
655                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
656                 {
657                     rt_spin_unlock_irqrestore(&info->spinlock, level);
658                     continue;
659                 }
660 
661                 rt_spin_unlock_irqrestore(&info->spinlock, level);
662 
663                 mh = (struct rt_memheap *)obj;
664 
665                 rt_kprintf("%-*.*s %-010d %-013d %-05d\n",
666                            maxlen, RT_NAME_MAX,
667                            mh->parent.name,
668                            mh->pool_size,
669                            mh->max_used_size,
670                            mh->available_size);
671 
672             }
673         }
674     }
675     while (next != (rt_list_t *)RT_NULL);
676 
677     return 0;
678 }
679 #endif /* RT_USING_MEMHEAP */
680 
681 #ifdef RT_USING_MEMPOOL
list_mempool(void)682 long list_mempool(void)
683 {
684     rt_base_t level;
685     list_get_next_t find_arg;
686     struct rt_object_information *info;
687     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
688     rt_list_t *next = (rt_list_t *)RT_NULL;
689 
690     int maxlen;
691     const char *item_title = "mempool";
692 
693     list_find_init(&find_arg, RT_Object_Class_MemPool, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
694     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
695 
696     maxlen = RT_NAME_MAX;
697 
698     rt_kprintf("%-*.*s block total free suspend thread\n", maxlen, maxlen, item_title);
699     object_split(maxlen);
700     rt_kprintf(" ----  ----  ---- --------------\n");
701     do
702     {
703         next = list_get_next(next, &find_arg);
704         {
705             int i;
706             for (i = 0; i < find_arg.nr_out; i++)
707             {
708                 struct rt_object *obj;
709                 struct rt_mempool *mp;
710                 int suspend_thread_count;
711                 rt_list_t *node;
712 
713                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
714                 level = rt_spin_lock_irqsave(&info->spinlock);
715                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
716                 {
717                     rt_spin_unlock_irqrestore(&info->spinlock, level);
718                     continue;
719                 }
720 
721                 rt_spin_unlock_irqrestore(&info->spinlock, level);
722 
723                 mp = (struct rt_mempool *)obj;
724 
725                 suspend_thread_count = 0;
726                 rt_list_for_each(node, &mp->suspend_thread)
727                 {
728                     suspend_thread_count++;
729                 }
730 
731                 if (suspend_thread_count > 0)
732                 {
733                     rt_kprintf("%-*.*s %04d  %04d  %04d %d:",
734                                maxlen, RT_NAME_MAX,
735                                mp->parent.name,
736                                mp->block_size,
737                                mp->block_total_count,
738                                mp->block_free_count,
739                                suspend_thread_count);
740                     rt_susp_list_print(&(mp->suspend_thread));
741                     rt_kprintf("\n");
742                 }
743                 else
744                 {
745                     rt_kprintf("%-*.*s %04d  %04d  %04d %d\n",
746                                maxlen, RT_NAME_MAX,
747                                mp->parent.name,
748                                mp->block_size,
749                                mp->block_total_count,
750                                mp->block_free_count,
751                                suspend_thread_count);
752                 }
753             }
754         }
755     }
756     while (next != (rt_list_t *)RT_NULL);
757 
758     return 0;
759 }
760 #endif /* RT_USING_MEMPOOL */
761 
list_timer(void)762 long list_timer(void)
763 {
764     rt_base_t level;
765     list_get_next_t find_arg;
766     struct rt_object_information *info;
767     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
768     rt_list_t *next = (rt_list_t *)RT_NULL;
769 
770     int maxlen;
771     const char *item_title = "timer";
772 
773     list_find_init(&find_arg, RT_Object_Class_Timer, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
774     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
775 
776     maxlen = RT_NAME_MAX;
777 
778     rt_kprintf("%-*.*s  periodic   timeout    activated     mode\n", maxlen, maxlen, item_title);
779     object_split(maxlen);
780     rt_kprintf(" ---------- ---------- ----------- ---------\n");
781     do
782     {
783         next = list_get_next(next, &find_arg);
784         {
785             int i;
786             for (i = 0; i < find_arg.nr_out; i++)
787             {
788                 struct rt_object *obj;
789                 struct rt_timer *timer;
790 
791                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
792                 level = rt_spin_lock_irqsave(&info->spinlock);
793                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
794                 {
795                     rt_spin_unlock_irqrestore(&info->spinlock, level);
796                     continue;
797                 }
798 
799                 rt_spin_unlock_irqrestore(&info->spinlock, level);
800 
801                 timer = (struct rt_timer *)obj;
802                 rt_kprintf("%-*.*s 0x%08x 0x%08x ",
803                            maxlen, RT_NAME_MAX,
804                            timer->parent.name,
805                            timer->init_tick,
806                            timer->timeout_tick);
807                 if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
808                     rt_kprintf("activated   ");
809                 else
810                     rt_kprintf("deactivated ");
811                 if (timer->parent.flag & RT_TIMER_FLAG_PERIODIC)
812                     rt_kprintf("periodic\n");
813                 else
814                     rt_kprintf("one shot\n");
815 
816             }
817         }
818     }
819     while (next != (rt_list_t *)RT_NULL);
820 
821     rt_kprintf("current tick:0x%08x\n", rt_tick_get());
822 
823     return 0;
824 }
825 
826 #ifdef RT_USING_DEVICE
827 static char *const device_type_str[RT_Device_Class_Unknown] =
828 {
829     "Character Device",
830     "Block Device",
831     "Network Interface",
832     "MTD Device",
833     "CAN Device",
834     "RTC",
835     "Sound Device",
836     "Graphic Device",
837     "I2C Bus",
838     "USB Slave Device",
839     "USB Host Bus",
840     "USB OTG Bus",
841     "SPI Bus",
842     "SPI Device",
843     "SDIO Bus",
844     "PM Pseudo Device",
845     "Pipe",
846     "Portal Device",
847     "Timer Device",
848     "Miscellaneous Device",
849     "Sensor Device",
850     "Touch Device",
851     "Phy Device",
852     "Security Device",
853     "WLAN Device",
854     "Pin Device",
855     "ADC Device",
856     "DAC Device",
857     "WDT Device",
858     "PWM Device",
859     "Bus Device",
860 };
861 
list_device(void)862 long list_device(void)
863 {
864     rt_base_t level;
865     list_get_next_t find_arg;
866     struct rt_object_information *info;
867     rt_list_t *obj_list[LIST_FIND_OBJ_NR];
868     rt_list_t *next = (rt_list_t *)RT_NULL;
869     const char *device_type;
870 
871     int maxlen;
872     const char *item_title = "device";
873 
874     list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
875     info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
876 
877     maxlen = RT_NAME_MAX;
878 
879     rt_kprintf("%-*.*s         type         ref count\n", maxlen, maxlen, item_title);
880     object_split(maxlen);
881     rt_kprintf(" -------------------- ----------\n");
882     do
883     {
884         next = list_get_next(next, &find_arg);
885         {
886             int i;
887             for (i = 0; i < find_arg.nr_out; i++)
888             {
889                 struct rt_object *obj;
890                 struct rt_device *device;
891 
892                 obj = rt_list_entry(obj_list[i], struct rt_object, list);
893                 level = rt_spin_lock_irqsave(&info->spinlock);
894                 if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
895                 {
896                     rt_spin_unlock_irqrestore(&info->spinlock, level);
897                     continue;
898                 }
899 
900                 rt_spin_unlock_irqrestore(&info->spinlock, level);
901 
902                 device = (struct rt_device *)obj;
903                 device_type = "Unknown";
904                 if (device->type < RT_Device_Class_Unknown &&
905                     device_type_str[device->type] != RT_NULL)
906                 {
907                     device_type = device_type_str[device->type];
908                 }
909                 rt_kprintf("%-*.*s %-20s %-8d\n",
910                            maxlen, RT_NAME_MAX,
911                            device->parent.name,
912                            device_type,
913                            device->ref_count);
914 
915             }
916         }
917     }
918     while (next != (rt_list_t *)RT_NULL);
919 
920     return 0;
921 }
922 #endif /* RT_USING_DEVICE */
923 
924 #ifndef FINSH_USING_OPTION_COMPLETION
cmd_list(int argc,char ** argv)925 static int cmd_list(int argc, char **argv)
926 {
927     if(argc == 2)
928     {
929         if(strcmp(argv[1], "thread") == 0)
930         {
931             list_thread();
932         }
933         else if(strcmp(argv[1], "timer") == 0)
934         {
935             list_timer();
936         }
937 #ifdef RT_USING_SEMAPHORE
938         else if(strcmp(argv[1], "sem") == 0)
939         {
940             list_sem();
941         }
942 #endif /* RT_USING_SEMAPHORE */
943 #ifdef RT_USING_EVENT
944         else if(strcmp(argv[1], "event") == 0)
945         {
946             list_event();
947         }
948 #endif /* RT_USING_EVENT */
949 #ifdef RT_USING_MUTEX
950         else if(strcmp(argv[1], "mutex") == 0)
951         {
952             list_mutex();
953         }
954 #endif /* RT_USING_MUTEX */
955 #ifdef RT_USING_MAILBOX
956         else if(strcmp(argv[1], "mailbox") == 0)
957         {
958             list_mailbox();
959         }
960 #endif  /* RT_USING_MAILBOX */
961 #ifdef RT_USING_MESSAGEQUEUE
962         else if(strcmp(argv[1], "msgqueue") == 0)
963         {
964             list_msgqueue();
965         }
966 #endif /* RT_USING_MESSAGEQUEUE */
967 #ifdef RT_USING_MEMHEAP
968         else if(strcmp(argv[1], "memheap") == 0)
969         {
970             list_memheap();
971         }
972 #endif /* RT_USING_MEMHEAP */
973 #ifdef RT_USING_MEMPOOL
974         else if(strcmp(argv[1], "mempool") == 0)
975         {
976             list_mempool();
977         }
978 #endif /* RT_USING_MEMPOOL */
979 #ifdef RT_USING_DEVICE
980         else if(strcmp(argv[1], "device") == 0)
981         {
982             list_device();
983         }
984 #endif /* RT_USING_DEVICE */
985 #ifdef RT_USING_DFS
986         else if(strcmp(argv[1], "fd") == 0)
987         {
988             extern int list_fd(void);
989             list_fd();
990         }
991 #endif /* RT_USING_DFS */
992         else
993         {
994             goto _usage;
995         }
996 
997         return 0;
998     }
999 
1000 _usage:
1001     rt_kprintf("Usage: list [options]\n");
1002     rt_kprintf("[options]:\n");
1003     rt_kprintf("    %-12s - list threads\n", "thread");
1004     rt_kprintf("    %-12s - list timers\n", "timer");
1005 #ifdef RT_USING_SEMAPHORE
1006     rt_kprintf("    %-12s - list semaphores\n", "sem");
1007 #endif /* RT_USING_SEMAPHORE */
1008 #ifdef RT_USING_MUTEX
1009     rt_kprintf("    %-12s - list mutexs\n", "mutex");
1010 #endif /* RT_USING_MUTEX */
1011 #ifdef RT_USING_EVENT
1012     rt_kprintf("    %-12s - list events\n", "event");
1013 #endif /* RT_USING_EVENT */
1014 #ifdef RT_USING_MAILBOX
1015     rt_kprintf("    %-12s - list mailboxs\n", "mailbox");
1016 #endif /* RT_USING_MAILBOX */
1017 #ifdef RT_USING_MESSAGEQUEUE
1018     rt_kprintf("    %-12s - list message queues\n", "msgqueue");
1019 #endif /* RT_USING_MESSAGEQUEUE */
1020 #ifdef RT_USING_MEMHEAP
1021     rt_kprintf("    %-12s - list memory heaps\n", "memheap");
1022 #endif /* RT_USING_MEMHEAP */
1023 #ifdef RT_USING_MEMPOOL
1024     rt_kprintf("    %-12s - list memory pools\n", "mempool");
1025 #endif /* RT_USING_MEMPOOL */
1026 #ifdef RT_USING_DEVICE
1027     rt_kprintf("    %-12s - list devices\n", "device");
1028 #endif /* RT_USING_DEVICE */
1029 #ifdef RT_USING_DFS
1030     rt_kprintf("    %-12s - list file descriptors\n", "fd");
1031 #endif /* RT_USING_DFS */
1032 
1033     return 0;
1034 }
1035 
1036 #else
CMD_OPTIONS_STATEMENT(cmd_list)1037 CMD_OPTIONS_STATEMENT(cmd_list)
1038 static int cmd_list(int argc, char **argv)
1039 {
1040     if (argc == 2)
1041     {
1042         switch (MSH_OPT_ID_GET(cmd_list))
1043         {
1044         case RT_Object_Class_Thread: list_thread(); break;
1045         case RT_Object_Class_Timer: list_timer(); break;
1046 #ifdef RT_USING_SEMAPHORE
1047         case RT_Object_Class_Semaphore: list_sem(); break;
1048 #endif /* RT_USING_SEMAPHORE */
1049 #ifdef RT_USING_EVENT
1050         case RT_Object_Class_Event: list_event(); break;
1051 #endif /* RT_USING_EVENT */
1052 #ifdef RT_USING_MUTEX
1053         case RT_Object_Class_Mutex: list_mutex(); break;
1054 #endif /* RT_USING_MUTEX */
1055 #ifdef RT_USING_MAILBOX
1056         case RT_Object_Class_MailBox: list_mailbox(); break;
1057 #endif  /* RT_USING_MAILBOX */
1058 #ifdef RT_USING_MESSAGEQUEUE
1059         case RT_Object_Class_MessageQueue: list_msgqueue(); break;
1060 #endif /* RT_USING_MESSAGEQUEUE */
1061 #ifdef RT_USING_MEMHEAP
1062         case RT_Object_Class_MemHeap: list_memheap(); break;
1063 #endif /* RT_USING_MEMHEAP */
1064 #ifdef RT_USING_MEMPOOL
1065         case RT_Object_Class_MemPool: list_mempool(); break;
1066 #endif /* RT_USING_MEMPOOL */
1067 #ifdef RT_USING_DEVICE
1068         case RT_Object_Class_Device: list_device(); break;
1069 #endif /* RT_USING_DEVICE */
1070 #ifdef RT_USING_DFS
1071         case LIST_DFS_OPT_ID:
1072         {
1073             extern int list_fd(void);
1074             list_fd();
1075             break;
1076         }
1077 #endif /* RT_USING_DFS */
1078         default:
1079             goto _usage;
1080         };
1081 
1082         return 0;
1083         }
1084 
1085 _usage:
1086     rt_kprintf("Usage: list [options]\n");
1087     rt_kprintf("[options]:\n");
1088     MSH_OPT_DUMP(cmd_list);
1089     return 0;
1090 }
1091 CMD_OPTIONS_NODE_START(cmd_list)
1092 CMD_OPTIONS_NODE(RT_Object_Class_Thread,       thread,   list threads)
1093 CMD_OPTIONS_NODE(RT_Object_Class_Timer,        timer,    list timers)
1094 #ifdef RT_USING_SEMAPHORE
1095 CMD_OPTIONS_NODE(RT_Object_Class_Semaphore,    sem,      list semaphores)
1096 #endif /* RT_USING_SEMAPHORE */
1097 #ifdef RT_USING_EVENT
1098 CMD_OPTIONS_NODE(RT_Object_Class_Event,        event,    list events)
1099 #endif /* RT_USING_EVENT */
1100 #ifdef RT_USING_MUTEX
1101 CMD_OPTIONS_NODE(RT_Object_Class_Mutex,        mutex,    list mutexs)
1102 #endif /* RT_USING_MUTEX */
1103 #ifdef RT_USING_MAILBOX
1104 CMD_OPTIONS_NODE(RT_Object_Class_MailBox,      mailbox,  list mailboxs)
1105 #endif  /* RT_USING_MAILBOX */
1106 #ifdef RT_USING_MESSAGEQUEUE
1107 CMD_OPTIONS_NODE(RT_Object_Class_MessageQueue, msgqueue, list message queues)
1108 #endif /* RT_USING_MESSAGEQUEUE */
1109 #ifdef RT_USING_MEMHEAP
1110 CMD_OPTIONS_NODE(RT_Object_Class_MemHeap,      memheap,  list memory heaps)
1111 #endif /* RT_USING_MEMHEAP */
1112 #ifdef RT_USING_MEMPOOL
1113 CMD_OPTIONS_NODE(RT_Object_Class_MemPool,      mempool,  list memory pools)
1114 #endif /* RT_USING_MEMPOOL */
1115 #ifdef RT_USING_DEVICE
1116 CMD_OPTIONS_NODE(RT_Object_Class_Device,       device,   list devices)
1117 #endif /* RT_USING_DEVICE */
1118 #ifdef RT_USING_DFS
1119 CMD_OPTIONS_NODE(LIST_DFS_OPT_ID,              fd,       list file descriptors)
1120 #endif /* RT_USING_DFS */
1121 CMD_OPTIONS_NODE_END
1122 #endif /* FINSH_USING_OPTION_COMPLETION */
1123 MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects, optenable);
1124 
1125 #endif /* RT_USING_FINSH */
1126