diff --git a/TODO.md b/TODO.md index 0d72ccdef..ef28a9a33 100644 --- a/TODO.md +++ b/TODO.md @@ -8,24 +8,24 @@ * [x] 一种新的ipc机制(暂时取名fastipc),不切上下文,只切内存,流程更加简单,解决原来ipc优先级问题,以及并发性问题。 * [x] cpu占用率支持 * [x] 进程管理机制完善,进程状态订阅,进程间信号发送。 -* [ ] 文件系统&网络协议栈完善自动删除支持(文件描述符自动管理库) -* [x] 内核信号量对象完善,支持超时(已完成)。 -* [ ] 内核信号量支持优先级反转 * [x] TTY 支持自动切换前后台 +* [x] 内核信号量对象完善,支持超时(已完成)。 * [x] 重构路径管理(nsfs) -* [ ] 线程占用率统计 * [x] 去除原来的ipc机制(使用fastipc机制),并单独实现sleep接口,目前的ipc有概率卡死问题 -* [ ] 几大组件稳定性测试 -* [ ] dup, dup2等接口支持 -* [ ] FPU完整支持,fastipc FPU支持 * [x] TTY驱动支持 -* [ ] proc支持 +* [x] 内核二值信号量支持优先级反转(优先级继承协议)。 +* [ ] FPU完整支持,fastipc FPU支持 +* [ ] 文件系统&网络协议栈完善自动删除支持(文件描述符自动管理库) +* [ ] 线程占用率统计 +* [ ] procfs支持 * [ ] 新进程中env支持 +* [ ] dup, dup2等接口支持 * [ ] posix mq支持 * [ ] posix sig支持 * [ ] posix shm支持 * [ ] posix sema支持 * [ ] vfork + exec实现 +* [ ] 几大组件稳定性测试 ### mid prio * [x] net server support * [x] block driver @@ -43,8 +43,10 @@ - [ ] lvgl support - [ ] modbus support - [ ] poll/select实现 +- [ ] 零星调度支持 #### must low prio - [ ] AT proctol support - [ ] can proctol support - [ ] dyn so support +- [ ] mrpoid 适配 diff --git a/mkrtos_knl/inc/knl/plist.h b/mkrtos_knl/inc/knl/plist.h new file mode 100644 index 000000000..11135c8cb --- /dev/null +++ b/mkrtos_knl/inc/knl/plist.h @@ -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 \ No newline at end of file diff --git a/mkrtos_knl/inc/knl/sema.h b/mkrtos_knl/inc/knl/sema.h index f24404fc9..d604138f4 100644 --- a/mkrtos_knl/inc/knl/sema.h +++ b/mkrtos_knl/inc/knl/sema.h @@ -3,13 +3,16 @@ #include #include #include + typedef struct sema { kobject_t kobj; //!< 内核对象节点 spinlock_t lock; //!< int 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; typedef sema_t mutex_t; diff --git a/mkrtos_knl/inc/knl/slist.h b/mkrtos_knl/inc/knl/slist.h index 0e00e638e..f78762641 100755 --- a/mkrtos_knl/inc/knl/slist.h +++ b/mkrtos_knl/inc/knl/slist.h @@ -8,7 +8,14 @@ typedef struct slist_head struct slist_head *prev; //!< 前一个 struct slist_head *next; //!< 后一个 } 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) { list->prev = list; diff --git a/mkrtos_knl/inc/knl/thread.h b/mkrtos_knl/inc/knl/thread.h index eefbe9808..5e10869a5 100755 --- a/mkrtos_knl/inc/knl/thread.h +++ b/mkrtos_knl/inc/knl/thread.h @@ -163,6 +163,10 @@ typedef struct thread umword_t magic; //!< maigc } thread_t; +static inline int thread_get_prio(thread_t *th) +{ + return th->sche.prio; +} static inline int thread_get_cpu(thread_t *th) { 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_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) { return thread_get_pf(thread_get_current()); diff --git a/mkrtos_knl/knl/sema.c b/mkrtos_knl/knl/sema.c index 46863bfe1..98828137c 100644 --- a/mkrtos_knl/knl/sema.c +++ b/mkrtos_knl/knl/sema.c @@ -45,6 +45,7 @@ void sema_up(sema_t *obj) { assert(obj); umword_t status; + thread_t *th = thread_get_current(); status = spinlock_lock(&obj->lock); 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 = 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) { slist_del(first_wait_node); 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); } } @@ -76,11 +75,18 @@ void sema_up(sema_t *obj) { // 超时退出,但是切出来的时候切到了唤醒线程中,所以这里不是suspend状态。 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) { 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); } spinlock_set(&obj->lock, status); @@ -104,6 +110,14 @@ again: sema_wait_item_init(&wait_item, th); ref_counter_inc(&th->ref); 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); if (remain_sleep == 0 && ticks != 0) { @@ -126,6 +140,11 @@ again: { assert(obj->cnt > 0); 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); } spinlock_set(&obj->lock, status); diff --git a/mkrtos_knl/knl/thread.c b/mkrtos_knl/knl/thread.c index fbfe421e3..ff6cf28f9 100755 --- a/mkrtos_knl/knl/thread.c +++ b/mkrtos_knl/knl/thread.c @@ -1468,6 +1468,24 @@ static int thread_remote_migration(ipi_msg_t *msg, bool_t *is_sched) } #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, msg_tag_t in_tag, entry_frame_t *f) { diff --git a/mkrtos_knl/knl/thread_knl.c b/mkrtos_knl/knl/thread_knl.c index d93e94279..b1a86254d 100755 --- a/mkrtos_knl/knl/thread_knl.c +++ b/mkrtos_knl/knl/thread_knl.c @@ -51,6 +51,7 @@ static thread_t *knl_thread[CONFIG_CPU]; static slist_head_t del_task_head; static umword_t cpu_usage[CONFIG_CPU]; static spinlock_t del_lock; +static umword_t cpu_usage_last_tick_val[CONFIG_CPU]; 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); } -static uint32_t cpu_usage_last_tick_val[CONFIG_CPU]; /** * 计算cpu占用率 */ void thread_calc_cpu_usage(void) { 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) { - cpu_usage[cur_cpu_id] = 1000 - ((thread_knl_get_current_run_nr() - cpu_usage_last_tick_val[cur_cpu_id])); - cpu_usage_last_tick_val[cur_cpu_id] = thread_knl_get_current_run_nr(); + mword_t calc = tick - cpu_usage_last_tick_val[cur_cpu_id]; + + 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()]); } } diff --git a/mkrtos_knl/lib/plist.c b/mkrtos_knl/lib/plist.c new file mode 100644 index 000000000..bf62119a4 --- /dev/null +++ b/mkrtos_knl/lib/plist.c @@ -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); +// } \ No newline at end of file diff --git a/mkrtos_user/lib/letter-shell/demo/mkrtos/shell_fs_ext.c b/mkrtos_user/lib/letter-shell/demo/mkrtos/shell_fs_ext.c index b37412d92..17af07901 100644 --- a/mkrtos_user/lib/letter-shell/demo/mkrtos/shell_fs_ext.c +++ b/mkrtos_user/lib/letter-shell/demo/mkrtos/shell_fs_ext.c @@ -38,30 +38,35 @@ int ls(int argc, char *agrv[]) { return -ENOMEM; } - strcpy(path, in_path); - dir = opendir(in_path); + ret = getcwd(path, PAGE_SIZE); + if (ret < 0) + { + u_free(path); + return ret; + } + ret = chdir(in_path); + if (ret < 0) + { + u_free(path); + return ret; + } + dir = opendir("."); if (!dir) { u_free(path); return 0; } + printf("%-20s%10s\n", "name", "size"); + while ((ptr = readdir(dir)) != NULL) { struct stat st = {0}; - // strcat(path, "/"); - strcat(path, ptr->d_name); - ret = stat(path, &st); - // if (ret >= 0) - // { - printf("%s\t\t\t%dB\n", path, st.st_size); - // } - // else - // { - // printf("error:%d\n", ret); - // } - strcpy(path, in_path); + + ret = stat(ptr->d_name, &st); + printf("%-20s%10d\n", ptr->d_name, st.st_size); } closedir(dir); + chdir(path); u_free(path); return 0; } @@ -234,7 +239,7 @@ int shell_sys_info(int argc, char *argv[]) size_t free; 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; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), sys, shell_sys_info, sys command); diff --git a/mkrtos_user/server/init/src/test/mutex_test.c b/mkrtos_user/server/init/src/test/mutex_test.c new file mode 100644 index 000000000..f82062870 --- /dev/null +++ b/mkrtos_user/server/init/src/test/mutex_test.c @@ -0,0 +1,88 @@ + +#include "u_factory.h" +#include "u_hd_man.h" +#include "u_task.h" +#include "u_thread.h" +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/mkrtos_user/server/init/src/test/test.h b/mkrtos_user/server/init/src/test/test.h index 9736e2d90..a733f6dcb 100644 --- a/mkrtos_user/server/init/src/test/test.h +++ b/mkrtos_user/server/init/src/test/test.h @@ -15,6 +15,8 @@ CuSuite *pthread_base_test_suite(void); CuSuite *thread_base_test_suite(void); CuSuite *ipc_test_suite(void); CuSuite *sharem_mem_test_suite(void); +CuSuite *mutex_test_suite(void); + void test_main(void); void mm_test(void); diff --git a/mkrtos_user/server/init/src/test/test_main.c b/mkrtos_user/server/init/src/test/test_main.c index f87d0f021..4622f469a 100644 --- a/mkrtos_user/server/init/src/test/test_main.c +++ b/mkrtos_user/server/init/src/test/test_main.c @@ -26,6 +26,7 @@ static void RunAllTests(void) CuSuiteAddSuite(&suite, map_test_suite()); #endif CuSuiteAddSuite(&suite, thread_base_test_suite()); + CuSuiteAddSuite(&suite, mutex_test_suite()); CuSuiteAddSuite(&suite, sema_test_suite()); CuSuiteAddSuite(&suite, pthread_base_test_suite()); CuSuiteAddSuite(&suite, pthread_press_test_suite());