优先级继承协议支持
This commit is contained in:
18
TODO.md
18
TODO.md
@@ -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
269
mkrtos_knl/inc/knl/plist.h
Normal 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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
120
mkrtos_knl/lib/plist.c
Normal 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);
|
||||||
|
// }
|
||||||
@@ -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);
|
||||||
|
|||||||
88
mkrtos_user/server/init/src/test/mutex_test.c
Normal file
88
mkrtos_user/server/init/src/test/mutex_test.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
Reference in New Issue
Block a user