优先级继承协议支持

This commit is contained in:
zhangzheng
2025-03-11 17:03:30 +08:00
parent dc7a0675fa
commit 141a6fd96b
13 changed files with 574 additions and 31 deletions

18
TODO.md
View File

@@ -8,24 +8,24 @@
* [x] 一种新的ipc机制暂时取名fastipc不切上下文只切内存流程更加简单解决原来ipc优先级问题以及并发性问题。 * [x] 一种新的ipc机制暂时取名fastipc不切上下文只切内存流程更加简单解决原来ipc优先级问题以及并发性问题。
* [x] cpu占用率支持 * [x] cpu占用率支持
* [x] 进程管理机制完善,进程状态订阅,进程间信号发送。 * [x] 进程管理机制完善,进程状态订阅,进程间信号发送。
* [ ] 文件系统&网络协议栈完善自动删除支持(文件描述符自动管理库)
* [x] 内核信号量对象完善,支持超时(已完成)。
* [ ] 内核信号量支持优先级反转
* [x] TTY 支持自动切换前后台 * [x] TTY 支持自动切换前后台
* [x] 内核信号量对象完善,支持超时(已完成)。
* [x] 重构路径管理nsfs * [x] 重构路径管理nsfs
* [ ] 线程占用率统计
* [x] 去除原来的ipc机制使用fastipc机制并单独实现sleep接口目前的ipc有概率卡死问题 * [x] 去除原来的ipc机制使用fastipc机制并单独实现sleep接口目前的ipc有概率卡死问题
* [ ] 几大组件稳定性测试
* [ ] dup, dup2等接口支持
* [ ] FPU完整支持fastipc FPU支持
* [x] TTY驱动支持 * [x] TTY驱动支持
* [ ] proc支持 * [x] 内核二值信号量支持优先级反转(优先级继承协议)。
* [ ] FPU完整支持fastipc FPU支持
* [ ] 文件系统&网络协议栈完善自动删除支持(文件描述符自动管理库)
* [ ] 线程占用率统计
* [ ] procfs支持
* [ ] 新进程中env支持 * [ ] 新进程中env支持
* [ ] dup, dup2等接口支持
* [ ] posix mq支持 * [ ] posix mq支持
* [ ] posix sig支持 * [ ] posix sig支持
* [ ] posix shm支持 * [ ] posix shm支持
* [ ] posix sema支持 * [ ] posix sema支持
* [ ] vfork + exec实现 * [ ] vfork + exec实现
* [ ] 几大组件稳定性测试
### mid prio ### mid prio
* [x] net server support * [x] net server support
* [x] block driver * [x] block driver
@@ -43,8 +43,10 @@
- [ ] lvgl support - [ ] lvgl support
- [ ] modbus support - [ ] modbus support
- [ ] poll/select实现 - [ ] poll/select实现
- [ ] 零星调度支持
#### must low prio #### must low prio
- [ ] AT proctol support - [ ] AT proctol support
- [ ] can proctol support - [ ] can proctol support
- [ ] dyn so support - [ ] dyn so support
- [ ] mrpoid 适配

269
mkrtos_knl/inc/knl/plist.h Normal file
View File

@@ -0,0 +1,269 @@
// /*
// * Descending-priority-sorted double-linked list //降序优先排序的双向链表,prio越大任务优先级越小 ===> prio的值越大在链表上越靠后
// *
// * Based on simple lists (include/linux/list.h).
// *
// * This is a priority-sorted list of nodes; each node has a priority from INT_MIN (highest) to INT_MAX (lowest).
// *
// * Addition is O(K), removal is O(1), change of priority of a node is O(K) and K is the number of RT priority
// * levels used in the system. (1 <= K <= 99)
// *
// * This list is really a list of lists:
// * - The tier 1 list is the prio_list, different priority nodes.
// * - The tier 2 list is the node_list, serialized nodes.
// *
// * Simple ASCII art explanation:
// *
// * pl:prio_list (only for plist_node)
// * nl:node_list
// * HEAD| NODE(S)
// * |
// * ||------------------------------------|
// * ||->|pl|<->|pl|<--------------->|pl|<-|
// * | |10| |21| |21| |21| |40| (prio)
// * | | | | | | | | | | |
// * | | | | | | | | | | |
// * |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
// * |-------------------------------------------|
// *
// * The nodes on the prio_list list are sorted by priority to simplify the insertion of new nodes. There are no nodes with
// * duplicate priorites on the list.
// *
// * The nodes on the node_list are ordered by priority and can contain entries which have the same priority. Those entries
// * are ordered FIFO
// *
// * Addition means: look for the prio_list node in the prio_list for the priority of the node and insert it before the node_list
// * entry of the next prio_list node. If it is the first node of that priority, add it to the prio_list in the right position and
// * insert it into the serialized node_list list
// *
// * Removal means remove it from the node_list and remove it from the prio_list if the node_list list_head is non empty. In case
// * of removal from the prio_list it must be checked whether other entries of the same priority are on the list or not. If there
// * is another entry of the same priority then this entry has to replace the removed entry on the prio_list. If the entry which
// * is removed is the only entry of this priority then a simple remove from both list is sufficient.
// *
// * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX is lowest priority.
// *
// * No locking is done, up to the caller.
// */
// #ifndef _LINUX_PLIST_H_
// #define _LINUX_PLIST_H_
// #include "slist.h"
// #include "printk.h"
// /*----------I add------------*/
// #define WARN_ON(cond) \
// if (cond) { \
// printk("WARN: file: %s, line: %d, func: %s\n", __FILE__, __LINE__, __func__); \
// }
// #define BUG_ON(cond) \
// if (cond) { \
// printk("BUG: file: %s, line: %d, func: %s\n", __FILE__, __LINE__, __func__); \
// }
// /*------------end-----------*/
// typedef struct plist_head {
// slist_head_t node_list;
// } plist_head_t;
// typedef struct plist_node {
// int prio;
// slist_head_t prio_list;
// slist_head_t node_list;
// } plist_node_t;
// /**
// * PLIST_HEAD_INIT - static struct plist_head initializer
// * @head: struct plist_head variable name
// */
// #define PLIST_HEAD_INIT(head) \
// { \
// .node_list = SLIST_HEAD_INIT((head).node_list) \
// }
// /**
// * PLIST_HEAD - declare and init plist_head
// * @head: name for struct plist_head variable
// */
// #define PLIST_HEAD(head) \
// struct plist_head head = PLIST_HEAD_INIT(head)
// /**
// * PLIST_NODE_INIT - static struct plist_node initializer
// * @node: struct plist_node variable name
// * @__prio: initial node priority
// */
// #define PLIST_NODE_INIT(node, __prio) \
// { \
// .prio = (__prio), \
// .prio_list = SLIST_HEAD_INIT((node).prio_list), \
// .node_list = SLIST_HEAD_INIT((node).node_list), \
// }
// /**
// * plist_head_init - dynamic struct plist_head initializer
// * @head: &struct plist_head pointer
// */
// static inline void plist_head_init(struct plist_head *head)
// {
// INIT_SLIST_HEAD(&head->node_list);
// }
// /**
// * plist_node_init - Dynamic struct plist_node initializer
// * @node: &struct plist_node pointer
// * @prio: initial node priority
// */
// static inline void plist_node_init(struct plist_node *node, int prio)
// {
// node->prio = prio;
// INIT_SLIST_HEAD(&node->prio_list);
// INIT_SLIST_HEAD(&node->node_list);
// }
// extern void plist_add(struct plist_node *node, struct plist_head *head);
// extern void plist_del(struct plist_node *node, struct plist_head *head);
// extern void plist_requeue(struct plist_node *node, struct plist_head *head);
// /**
// * plist_for_each - iterate over the plist
// * @pos: the type * to use as a loop counter
// * @head: the head for your list
// */
// #define plist_for_each(pos, head) \
// slist_foreach(pos, &(head)->node_list, node_list)
// /**
// * plist_for_each_continue - continue iteration over the plist
// * @pos: the type * to use as a loop cursor
// * @head: the head for your list
// *
// * Continue to iterate over plist, continuing after the current position.
// */
// #define plist_for_each_continue(pos, head) \
// list_for_each_entry_continue(pos, &(head)->node_list, node_list)
// /**
// * plist_for_each_safe - iterate safely over a plist of given type
// * @pos: the type * to use as a loop counter
// * @n: another type * to use as temporary storage
// * @head: the head for your list
// *
// * Iterate over a plist of given type, safe against removal of list entry.
// */
// #define plist_for_each_safe(pos, n, head) \
// list_for_each_entry_safe(pos, n, &(head)->node_list, node_list)
// /**
// * plist_for_each_entry - iterate over list of given type
// * @pos: the type * to use as a loop counter
// * @head: the head for your list
// * @mem: the name of the list_head within the struct
// */
// #define plist_for_each_entry(pos, head, mem) \
// list_for_each_entry(pos, &(head)->node_list, mem.node_list)
// /**
// * plist_for_each_entry_continue - continue iteration over list of given type
// * @pos: the type * to use as a loop cursor
// * @head: the head for your list
// * @m: the name of the list_head within the struct
// *
// * Continue to iterate over list of given type, continuing after
// * the current position.
// */
// #define plist_for_each_entry_continue(pos, head, m) \
// list_for_each_entry_continue(pos, &(head)->node_list, m.node_list)
// /**
// * plist_for_each_entry_safe - iterate safely over list of given type
// * @pos: the type * to use as a loop counter
// * @n: another type * to use as temporary storage
// * @head: the head for your list
// * @m: the name of the list_head within the struct
// *
// * Iterate over list of given type, safe against removal of list entry.
// */
// #define plist_for_each_entry_safe(pos, n, head, m) \
// list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list)
// /**
// * plist_head_empty - return !0 if a plist_head is empty
// * @head: &struct plist_head pointer
// */
// static inline int plist_head_empty(const struct plist_head *head)
// {
// return slist_is_empty(&head->node_list);
// }
// /**
// * plist_node_empty - return !0 if plist_node is not on a list
// * @node: &struct plist_node pointer
// */
// static inline int plist_node_empty(const struct plist_node *node)
// {
// return slist_is_empty(&node->node_list);
// }
// /* All functions below assume the plist_head is not empty. */
// /**
// * plist_first_entry - get the struct for the first entry
// * @head: the &struct plist_head pointer
// * @type: the type of the struct this is embedded in
// * @member: the name of the list_head within the struct
// */
// # define plist_first_entry(head, type, member) \
// container_of(plist_first(head), type, member)
// /**
// * plist_last_entry - get the struct for the last entry
// * @head: the &struct plist_head pointer
// * @type: the type of the struct this is embedded in
// * @member: the name of the list_head within the struct
// */
// # define plist_last_entry(head, type, member) \
// container_of(plist_last(head), type, member)
// /**
// * plist_next - get the next entry in list
// * @pos: the type * to cursor
// */
// #define plist_next(pos) \
// list_next_entry(pos, node_list)
// /**
// * plist_prev - get the prev entry in list
// * @pos: the type * to cursor
// */
// #define plist_prev(pos) \
// list_prev_entry(pos, node_list)
// /**
// * plist_first - return the first node (and thus, highest priority)
// * @head: the &struct plist_head pointer
// *
// * Assumes the plist is _not_ empty.
// */
// static inline struct plist_node *plist_first(const struct plist_head *head)
// {
// return slist_entry(head->node_list.next, struct plist_node, node_list);
// }
// /**
// * plist_last - return the last node (and thus, lowest priority)
// * @head: the &struct plist_head pointer
// *
// * Assumes the plist is _not_ empty.
// */
// static inline struct plist_node *plist_last(const struct plist_head *head)
// {
// return slist_entry(head->node_list.prev, struct plist_node, node_list);
// }
// #endif

View File

@@ -3,13 +3,16 @@
#include <spinlock.h> #include <spinlock.h>
#include <slist.h> #include <slist.h>
#include <kobject.h> #include <kobject.h>
typedef struct sema typedef struct sema
{ {
kobject_t kobj; //!< 内核对象节点 kobject_t kobj; //!< 内核对象节点
spinlock_t lock; //!< spinlock_t lock; //!<
int cnt; //!< 计数 int cnt; //!< 计数
int max_cnt; //!< 最大计数 int max_cnt; //!< 最大计数
slist_head_t suspend_head; //!< 挂起的线程 kobject_t *hold_th; //!< 那个线程获取到了信号量只有当max_cnt为1时才能有效因为>1时可能有多个消费者
int hold_th_prio; //!< 获取mutex线程的优先级.
slist_head_t suspend_head; //!< 挂起的线程FIXME:修改为plist
} sema_t; } sema_t;
typedef sema_t mutex_t; typedef sema_t mutex_t;

View File

@@ -8,7 +8,14 @@ typedef struct slist_head
struct slist_head *prev; //!< 前一个 struct slist_head *prev; //!< 前一个
struct slist_head *next; //!< 后一个 struct slist_head *next; //!< 后一个
} slist_head_t; } slist_head_t;
#define SLIST_HEAD_INIT(name) { &(name), &(name) }
#define WRITE_ONCE(var, val) (*((volatile typeof(val) *)(&(var))) = (val))
#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
static inline void INIT_SLIST_HEAD(slist_head_t *list)
{
WRITE_ONCE(list->next, list);
list->prev = list;
}
static inline void slist_init(slist_head_t *list) static inline void slist_init(slist_head_t *list)
{ {
list->prev = list; list->prev = list;

View File

@@ -163,6 +163,10 @@ typedef struct thread
umword_t magic; //!< maigc umword_t magic; //!< maigc
} thread_t; } thread_t;
static inline int thread_get_prio(thread_t *th)
{
return th->sche.prio;
}
static inline int thread_get_cpu(thread_t *th) static inline int thread_get_cpu(thread_t *th)
{ {
return th->cpu; return th->cpu;
@@ -274,7 +278,7 @@ static inline int thread_fast_ipc_pop(thread_t *th, thread_fast_ipc_item_t *item
task_t *thread_get_current_task(void); task_t *thread_get_current_task(void);
task_t *thread_get_task(thread_t *th); task_t *thread_get_task(thread_t *th);
task_t *thread_get_bind_task(thread_t *th); task_t *thread_get_bind_task(thread_t *th);
int thread_set_prio(thread_t *th, int prio);
static inline pf_t *thread_get_current_pf(void) static inline pf_t *thread_get_current_pf(void)
{ {
return thread_get_pf(thread_get_current()); return thread_get_pf(thread_get_current());

View File

@@ -45,6 +45,7 @@ void sema_up(sema_t *obj)
{ {
assert(obj); assert(obj);
umword_t status; umword_t status;
thread_t *th = thread_get_current();
status = spinlock_lock(&obj->lock); status = spinlock_lock(&obj->lock);
if (slist_is_empty(&obj->suspend_head)) if (slist_is_empty(&obj->suspend_head))
@@ -62,13 +63,11 @@ void sema_up(sema_t *obj)
first_wait_node = slist_first(&obj->suspend_head); first_wait_node = slist_first(&obj->suspend_head);
first_wait = container_of(first_wait_node, sema_wait_item_t, node); first_wait = container_of(first_wait_node, sema_wait_item_t, node);
// assert(first_wait->thread->status == THREAD_SUSPEND);
if (thread_get_status(first_wait->thread) == THREAD_SUSPEND) if (thread_get_status(first_wait->thread) == THREAD_SUSPEND)
{ {
slist_del(first_wait_node); slist_del(first_wait_node);
if (ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj) != 1) if (ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj) != 1)
{ {
// thread_ready_remote(first_wait->thread, FALSE);
thread_sleep_del_and_wakeup(first_wait->thread); thread_sleep_del_and_wakeup(first_wait->thread);
} }
} }
@@ -76,11 +75,18 @@ void sema_up(sema_t *obj)
{ {
// 超时退出但是切出来的时候切到了唤醒线程中所以这里不是suspend状态。 // 超时退出但是切出来的时候切到了唤醒线程中所以这里不是suspend状态。
thread_sleep_del(first_wait->thread); thread_sleep_del(first_wait->thread);
// 这里引用计数要-1
ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj);
} }
if (obj->cnt < obj->max_cnt) if (obj->cnt < obj->max_cnt)
{ {
obj->cnt++; obj->cnt++;
} }
if (obj->max_cnt == 1 && obj->hold_th == &th->kobj)
{
//还原优先级
thread_set_prio(th, obj->hold_th_prio);
}
// printk("up1 sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt); // printk("up1 sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt);
} }
spinlock_set(&obj->lock, status); spinlock_set(&obj->lock, status);
@@ -104,6 +110,14 @@ again:
sema_wait_item_init(&wait_item, th); sema_wait_item_init(&wait_item, th);
ref_counter_inc(&th->ref); ref_counter_inc(&th->ref);
slist_add_append(&obj->suspend_head, &wait_item.node); slist_add_append(&obj->suspend_head, &wait_item.node);
if (obj->max_cnt == 1 && obj->hold_th)
{
if (thread_get_prio(th) > thread_get_prio((thread_t*)(obj->hold_th)))
{
//执行优先级继承
thread_set_prio(((thread_t*)(obj->hold_th)), thread_get_prio(th));
}
}
remain_sleep = thread_sleep(ticks); remain_sleep = thread_sleep(ticks);
if (remain_sleep == 0 && ticks != 0) if (remain_sleep == 0 && ticks != 0)
{ {
@@ -126,6 +140,11 @@ again:
{ {
assert(obj->cnt > 0); assert(obj->cnt > 0);
obj->cnt--; obj->cnt--;
if (obj->max_cnt == 1)
{
obj->hold_th = &th->kobj;
obj->hold_th_prio = thread_get_prio(th);
}
// printk("down sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt); // printk("down sema cnt:%d max:%d.\n", obj->cnt, obj->max_cnt);
} }
spinlock_set(&obj->lock, status); spinlock_set(&obj->lock, status);

View File

@@ -1468,6 +1468,24 @@ static int thread_remote_migration(ipi_msg_t *msg, bool_t *is_sched)
} }
#endif #endif
int thread_set_prio(thread_t *th, int prio)
{
assert(cpulock_get_status());
int old_prio = thread_get_prio(th);
if (old_prio != prio)
{
if (thread_get_status(th) == THREAD_READY)
{
thread_suspend(th);
th->sche.prio = prio;
thread_ready(th, TRUE);
} else {
th->sche.prio = prio;
}
}
return old_prio;
}
static void thread_syscall(kobject_t *kobj, syscall_prot_t sys_p, static void thread_syscall(kobject_t *kobj, syscall_prot_t sys_p,
msg_tag_t in_tag, entry_frame_t *f) msg_tag_t in_tag, entry_frame_t *f)
{ {

View File

@@ -51,6 +51,7 @@ static thread_t *knl_thread[CONFIG_CPU];
static slist_head_t del_task_head; static slist_head_t del_task_head;
static umword_t cpu_usage[CONFIG_CPU]; static umword_t cpu_usage[CONFIG_CPU];
static spinlock_t del_lock; static spinlock_t del_lock;
static umword_t cpu_usage_last_tick_val[CONFIG_CPU];
static void knl_main(void) static void knl_main(void)
{ {
@@ -131,17 +132,21 @@ static inline uint32_t thread_knl_get_current_run_nr(void)
return atomic_read(&knl_thread[arch_get_current_cpu_id()]->time_count); return atomic_read(&knl_thread[arch_get_current_cpu_id()]->time_count);
} }
static uint32_t cpu_usage_last_tick_val[CONFIG_CPU];
/** /**
* 计算cpu占用率 * 计算cpu占用率
*/ */
void thread_calc_cpu_usage(void) void thread_calc_cpu_usage(void)
{ {
uint8_t cur_cpu_id = arch_get_current_cpu_id(); uint8_t cur_cpu_id = arch_get_current_cpu_id();
umword_t tick = thread_knl_get_current_run_nr();
if (sys_tick_cnt_get() % 1000 == 0) if (sys_tick_cnt_get() % 1000 == 0)
{ {
cpu_usage[cur_cpu_id] = 1000 - ((thread_knl_get_current_run_nr() - cpu_usage_last_tick_val[cur_cpu_id])); mword_t calc = tick - cpu_usage_last_tick_val[cur_cpu_id];
cpu_usage_last_tick_val[cur_cpu_id] = thread_knl_get_current_run_nr();
calc = calc > 1000 ? 1000 : calc;
cpu_usage[cur_cpu_id] = 1000 - calc;
cpu_usage_last_tick_val[cur_cpu_id] = tick;
// printk("%d\n", cpu_usage[arch_get_current_cpu_id()]); // printk("%d\n", cpu_usage[arch_get_current_cpu_id()]);
} }
} }

120
mkrtos_knl/lib/plist.c Normal file
View File

@@ -0,0 +1,120 @@
// /*
// * lib/plist.c
// * Based on simple lists (include/linux/list.h).
// *
// * This file contains the add / del functions which are considered to
// * be too large to inline. See include/linux/plist.h for further
// * information.
// */
// #include "plist.h"
// #define plist_check_head(h) do { } while (0)
// /**
// * plist_add - add @node to @head
// *
// * @node: &struct plist_node pointer
// * @head: &struct plist_head pointer
// */
// void plist_add(struct plist_node *node, struct plist_head *head)
// {
// struct plist_node *first, *iter, *prev = NULL;
// struct list_head *node_next = &head->node_list;
// plist_check_head(head);
// WARN_ON(!plist_node_empty(node));
// WARN_ON(!slist_is_empty(&node->prio_list));
// if (plist_head_empty(head))
// goto ins_node;
// first = iter = plist_first(head);
// do {
// if (node->prio < iter->prio) {
// node_next = &iter->node_list;
// break;
// }
// prev = iter;
// iter = slist_entry(iter->prio_list.next, struct plist_node, prio_list);
// } while (iter != first);
// if (!prev || prev->prio != node->prio)
// slist_add_append(&iter->prio_list, &node->prio_list);
// ins_node:
// slist_add_append(node_next, &node->node_list);
// plist_check_head(head);
// }
// /**
// * plist_del - Remove a @node from plist.
// *
// * @node: &struct plist_node pointer - entry to be removed
// * @head: &struct plist_head pointer - list head
// */
// void plist_del(struct plist_node *node, struct plist_head *head)
// {
// plist_check_head(head);
// if (!slist_is_empty(&node->prio_list)) {
// if (node->node_list.next != &head->node_list) {
// struct plist_node *next;
// next = slist_entry(node->node_list.next, struct plist_node, node_list);
// /* add the next plist_node into prio_list */
// if (slist_is_empty(&next->prio_list))
// slist_add(&node->prio_list, &next->prio_list);
// }
// list_del_init(&node->prio_list);
// }
// list_del_init(&node->node_list);
// plist_check_head(head);
// }
// /**
// * plist_requeue - Requeue @node at end of same-prio entries.
// *
// * This is essentially an optimized plist_del() followed by
// * plist_add(). It moves an entry already in the plist to
// * after any other same-priority entries.
// *
// * @node: &struct plist_node pointer - entry to be moved
// * @head: &struct plist_head pointer - list head
// */
// void plist_requeue(struct plist_node *node, struct plist_head *head)
// {
// struct plist_node *iter;
// struct list_head *node_next = &head->node_list;
// plist_check_head(head);
// BUG_ON(plist_head_empty(head));
// BUG_ON(plist_node_empty(node));
// if (node == plist_last(head))
// return;
// iter = plist_next(node);
// if (node->prio != iter->prio)
// return;
// plist_del(node, head);
// plist_for_each_continue(iter, head) {
// if (node->prio != iter->prio) {
// node_next = &iter->node_list;
// break;
// }
// }
// slist_add_append(node_next, &node->node_list);
// plist_check_head(head);
// }

View File

@@ -38,30 +38,35 @@ int ls(int argc, char *agrv[])
{ {
return -ENOMEM; return -ENOMEM;
} }
strcpy(path, in_path); ret = getcwd(path, PAGE_SIZE);
dir = opendir(in_path); if (ret < 0)
{
u_free(path);
return ret;
}
ret = chdir(in_path);
if (ret < 0)
{
u_free(path);
return ret;
}
dir = opendir(".");
if (!dir) if (!dir)
{ {
u_free(path); u_free(path);
return 0; return 0;
} }
printf("%-20s%10s\n", "name", "size");
while ((ptr = readdir(dir)) != NULL) while ((ptr = readdir(dir)) != NULL)
{ {
struct stat st = {0}; struct stat st = {0};
// strcat(path, "/");
strcat(path, ptr->d_name); ret = stat(ptr->d_name, &st);
ret = stat(path, &st); printf("%-20s%10d\n", ptr->d_name, st.st_size);
// if (ret >= 0)
// {
printf("%s\t\t\t%dB\n", path, st.st_size);
// }
// else
// {
// printf("error:%d\n", ret);
// }
strcpy(path, in_path);
} }
closedir(dir); closedir(dir);
chdir(path);
u_free(path); u_free(path);
return 0; return 0;
} }
@@ -234,7 +239,7 @@ int shell_sys_info(int argc, char *argv[])
size_t free; size_t free;
printf("sys:\n"); printf("sys:\n");
printf("\tcpu usage:%2.1f\n", sys_read_cpu_usage() / 10.0f); printf("\tcpu usage:%d.%d\n", sys_read_cpu_usage() / 10, sys_read_cpu_usage() % 10);
return 0; return 0;
} }
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), sys, shell_sys_info, sys command); SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), sys, shell_sys_info, sys command);

View File

@@ -0,0 +1,88 @@
#include "u_factory.h"
#include "u_hd_man.h"
#include "u_task.h"
#include "u_thread.h"
#include <CuTest.h>
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <u_mutex.h>
#include <u_sleep.h>
#include <unistd.h>
static pthread_t pth1;
static pthread_t pth2;
static pthread_t pth3;
static u_mutex_t mutex_lock;
static int test_cn;
static __attribute__((optimize(0))) void hard_sleep(void)
{
int i = 99999999;
while(i--);
}
static void *thread_th1(void *arg)
{
thread_run(-1, 5);
u_mutex_lock(&mutex_lock, 0, NULL);
hard_sleep();
u_mutex_unlock(&mutex_lock);
return NULL;
}
static void *thread_th2(void *arg)
{
u_sleep_ms(10);
thread_run(-1, 6);
u_sleep_ms(20);
while(test_cn < 10000000) {
test_cn++;
}
return NULL;
}
static void *thread_th3(void *arg)
{
u_sleep_ms(20);
thread_run(-1, 7);
u_mutex_lock(&mutex_lock, 0, NULL);
hard_sleep();
if (test_cn != 0) {
u_mutex_unlock(&mutex_lock);
return (void *)-1;
}
u_mutex_unlock(&mutex_lock);
return NULL;
}
static void u_mutex_test(CuTest *tc)
{
obj_handler_t mutex_hd;
int ret;
mutex_hd = handler_alloc();
CuAssert(tc, "hd alloc fail.\n", mutex_hd != HANDLER_INVALID);
ret = u_mutex_init(&mutex_lock, mutex_hd);
CuAssert(tc, "u_mutex_init fail.\n", ret >= 0);
CuAssert(tc, "pthread_create fail.\n", pthread_create(&pth1, NULL, thread_th1, NULL) == 0);
CuAssert(tc, "pthread_create fail.\n", pthread_create(&pth2, NULL, thread_th2, NULL) == 0);
CuAssert(tc, "pthread_create fail.\n", pthread_create(&pth3, NULL, thread_th3, NULL) == 0);
if (pth1 != PTHREAD_NULL) {
CuAssert(tc, "pthread_join fail.\n", pthread_join(pth1, NULL) == 0);
}
if (pth2 != PTHREAD_NULL) {
CuAssert(tc, "pthread_join fail.\n", pthread_join(pth2, NULL) == 0);
}
if (pth3 != PTHREAD_NULL) {
umword_t arg;
CuAssert(tc, "pthread_join fail.\n", pthread_join(pth3, (void **)&arg) == 0);
CuAssert(tc, "pthread_join fail.\n", arg == 0);
}
}
static CuSuite suite;
CuSuite *mutex_test_suite(void)
{
CuSuiteInit(&suite);
SUITE_ADD_TEST(&suite, u_mutex_test);
return &suite;
}

View File

@@ -15,6 +15,8 @@ CuSuite *pthread_base_test_suite(void);
CuSuite *thread_base_test_suite(void); CuSuite *thread_base_test_suite(void);
CuSuite *ipc_test_suite(void); CuSuite *ipc_test_suite(void);
CuSuite *sharem_mem_test_suite(void); CuSuite *sharem_mem_test_suite(void);
CuSuite *mutex_test_suite(void);
void test_main(void); void test_main(void);
void mm_test(void); void mm_test(void);

View File

@@ -26,6 +26,7 @@ static void RunAllTests(void)
CuSuiteAddSuite(&suite, map_test_suite()); CuSuiteAddSuite(&suite, map_test_suite());
#endif #endif
CuSuiteAddSuite(&suite, thread_base_test_suite()); CuSuiteAddSuite(&suite, thread_base_test_suite());
CuSuiteAddSuite(&suite, mutex_test_suite());
CuSuiteAddSuite(&suite, sema_test_suite()); CuSuiteAddSuite(&suite, sema_test_suite());
CuSuiteAddSuite(&suite, pthread_base_test_suite()); CuSuiteAddSuite(&suite, pthread_base_test_suite());
CuSuiteAddSuite(&suite, pthread_press_test_suite()); CuSuiteAddSuite(&suite, pthread_press_test_suite());