diff --git a/mkrtos_bootstrap/inc/lib/types.h b/mkrtos_bootstrap/inc/lib/types.h index 1a6b67a50..e1072a32d 100755 --- a/mkrtos_bootstrap/inc/lib/types.h +++ b/mkrtos_bootstrap/inc/lib/types.h @@ -15,11 +15,13 @@ typedef long long int64_t; typedef unsigned long umword_t; typedef unsigned short uhmword_t; typedef long mword_t; +typedef short uhumword_t; typedef signed long int intptr_t; typedef unsigned long int uintptr_t; typedef umword_t size_t; +typedef mword_t ssize_t; typedef umword_t ptr_t; typedef char bool_t; typedef unsigned long obj_addr_t; diff --git a/mkrtos_knl/drivers/stm32f1x/systick/systick.c b/mkrtos_knl/drivers/stm32f1x/systick/systick.c index 7d7b97e1d..9997c3881 100755 --- a/mkrtos_knl/drivers/stm32f1x/systick/systick.c +++ b/mkrtos_knl/drivers/stm32f1x/systick/systick.c @@ -15,6 +15,7 @@ void SysTick_Handler(void) // 进行上下文切换 thread_sched(); sys_tick_cnt++; + thread_timeout_check(); timeout_times_tick(); futex_timeout_times_tick(); } diff --git a/mkrtos_knl/drivers/stm32f2x/systick/systick.c b/mkrtos_knl/drivers/stm32f2x/systick/systick.c index 89d65a32e..e55d4c439 100755 --- a/mkrtos_knl/drivers/stm32f2x/systick/systick.c +++ b/mkrtos_knl/drivers/stm32f2x/systick/systick.c @@ -15,6 +15,7 @@ void SysTick_Handler(void) // 进行上下文切换 thread_sched(); sys_tick_cnt++; + thread_timeout_check(1); timeout_times_tick(); futex_timeout_times_tick(); } diff --git a/mkrtos_knl/inc/knl/ipc.h b/mkrtos_knl/inc/knl/ipc.h index 21b81848c..85ead065f 100755 --- a/mkrtos_knl/inc/knl/ipc.h +++ b/mkrtos_knl/inc/knl/ipc.h @@ -2,50 +2,4 @@ #include "thread.h" #include "types.h" -#define IPC_MSG_SIZE 96 -#define MAP_BUF_SIZE 16 -#define IPC_USER_SIZE 12 - -#if (IPC_MSG_SIZE + MAP_BUF_SIZE + IPC_USER_SIZE) > THREAD_MSG_BUG_LEN -#error "IPC MSG len error." -#endif - -typedef struct ipc_msg -{ - union - { - struct - { - umword_t msg_buf[IPC_MSG_SIZE / WORD_BYTES]; - umword_t map_buf[MAP_BUF_SIZE / WORD_BYTES]; - umword_t user[IPC_USER_SIZE / WORD_BYTES]; - }; - uint8_t data[THREAD_MSG_BUG_LEN]; - }; -} ipc_msg_t; - -typedef union ipc_timeout -{ - umword_t raw; - struct - { - uhmword_t send_timeout; - uhmword_t recv_timeout; - }; -} ipc_timeout_t; - -static inline ipc_timeout_t ipc_timeout_create2(uhmword_t send_timeout, uhmword_t recv_timeout) -{ - return (ipc_timeout_t){ - .send_timeout = send_timeout, - .recv_timeout = recv_timeout, - }; -} -static inline ipc_timeout_t ipc_timeout_create(umword_t raw) -{ - return (ipc_timeout_t){ - .raw = raw, - }; -} - void timeout_times_tick(void); diff --git a/mkrtos_knl/inc/knl/kobject.h b/mkrtos_knl/inc/knl/kobject.h index 0e8d7ea6f..3bc65b2d6 100755 --- a/mkrtos_knl/inc/knl/kobject.h +++ b/mkrtos_knl/inc/knl/kobject.h @@ -39,6 +39,7 @@ enum knl_obj_type MM_TYPE, FACTORY_TYPE, SYS_TYPE, + FUTEX_TYPE, }; typedef struct kobject diff --git a/mkrtos_knl/inc/knl/obj_space.h b/mkrtos_knl/inc/knl/obj_space.h index 6c861aa41..8df53bb8e 100755 --- a/mkrtos_knl/inc/knl/obj_space.h +++ b/mkrtos_knl/inc/knl/obj_space.h @@ -69,3 +69,4 @@ void obj_space_del(obj_space_t *obj_space, obj_addr_t inx); obj_map_entry_t *obj_space_insert(obj_space_t *obj_space, ram_limit_t *ram, kobject_t *kobj, obj_addr_t inx, uint8_t attrs); obj_map_entry_t *obj_space_lookup(obj_space_t *obj_space, obj_addr_t inx); kobject_t *obj_space_lookup_kobj(obj_space_t *obj_space, obj_addr_t inx); +kobject_t *obj_space_lookup_kobj_cmp_type(obj_space_t *obj_space, obj_addr_t inx, enum knl_obj_type obj_type); diff --git a/mkrtos_knl/inc/knl/thread.h b/mkrtos_knl/inc/knl/thread.h index 1ffb28801..90b147965 100755 --- a/mkrtos_knl/inc/knl/thread.h +++ b/mkrtos_knl/inc/knl/thread.h @@ -21,13 +21,73 @@ typedef struct task task_t; struct thread; typedef struct thread thread_t; +#define THREAD_MSG_BUG_LEN 128UL //!< 最小的消息寄存器大小 +#define MSG_BUF_HAS_DATA_FLAGS 0x01U //!< 已经有数据了 +#define MSG_BUF_RECV_R_FLAGS 0x02U //!< 接收来自recv_th的消息 +#define MSG_BUF_REPLY_FLAGS 0x04U //!< 回复消息给send_th + +#define IPC_MSG_SIZE 96 +#define MAP_BUF_SIZE 16 +#define IPC_USER_SIZE 12 + +#if (IPC_MSG_SIZE + MAP_BUF_SIZE + IPC_USER_SIZE) > THREAD_MSG_BUG_LEN +#error "IPC MSG len error." +#endif + +typedef struct ipc_msg +{ + union + { + struct + { + umword_t msg_buf[IPC_MSG_SIZE / WORD_BYTES]; + umword_t map_buf[MAP_BUF_SIZE / WORD_BYTES]; + umword_t user[IPC_USER_SIZE / WORD_BYTES]; + }; + uint8_t data[THREAD_MSG_BUG_LEN]; + }; +} ipc_msg_t; + +typedef union ipc_timeout +{ + umword_t raw; + struct + { + uhmword_t send_timeout; + uhmword_t recv_timeout; + }; +} ipc_timeout_t; + +static inline ipc_timeout_t ipc_timeout_create2(uhmword_t send_timeout, uhmword_t recv_timeout) +{ + return (ipc_timeout_t){ + .send_timeout = send_timeout, + .recv_timeout = recv_timeout, + }; +} +static inline ipc_timeout_t ipc_timeout_create(umword_t raw) +{ + return (ipc_timeout_t){ + .raw = raw, + }; +} + enum thread_state { - THREAD_IDLE, //!< 空闲状态 - THREAD_DEAD, //!< 死亡状态 - THREAD_SUSPEND, //!< 只有接收和发送ipc消息时才能挂起 - THREAD_READY, //!< 在就绪队列中 - THREAD_TODEAD, //!< 该标志标志线程马上要死亡了,执行完必要操作后,进入THREAD_DEAD状态 + THREAD_IDLE = 0, //!< 空闲状态 + THREAD_DEAD = 1, //!< 死亡状态 + THREAD_SUSPEND = 2, //!< 只有接收和发送ipc消息时才能挂起 + THREAD_READY = 3, //!< 在就绪队列中 + THREAD_TODEAD = 4, //!< 该标志标志线程马上要死亡了,执行完必要操作后,进入THREAD_DEAD状态 +}; +enum thread_ipc_state +{ + THREAD_NONE, + THREAD_SEND, + THREAD_RECV, + THREAD_WAIT, + THREAD_TIMEOUT, + THREAD_IPC_ABORT, }; typedef struct { @@ -50,11 +110,6 @@ typedef struct sp_info mword_t sp_type; //!< 使用的栈类型 } sp_info_t; -#define THREAD_MSG_BUG_LEN 128UL //!< 默认的消息寄存器大小 -#define MSG_BUF_HAS_DATA_FLAGS 0x01U //!< 已经有数据了 -#define MSG_BUF_RECV_R_FLAGS 0x02U //!< 接收来自recv_th的消息 -#define MSG_BUF_REPLY_FLAGS 0x04U //!< 回复消息给send_th - typedef struct msg_buf { void *msg; //!< buf,长度是固定的 @see THREAD_MSG_BUG_LEN @@ -64,15 +119,23 @@ typedef struct msg_buf #define THREAD_MAIGC 0xdeadead //!< 用于栈溢出检测 typedef struct thread { - kobject_t kobj; //!< 内核对象节点 - sched_t sche; //!< 调度节点 - kobject_t *task; //!< 绑定的task - sp_info_t sp; //!< sp信息 - ram_limit_t *lim; //!< 内存限制 - ref_counter_t ref; //!< 引用计数 - msg_buf_t msg; //!< 每个线程独有的消息缓存区 - enum thread_state status; //!< 线程状态 - umword_t magic; //!< maigc + kobject_t kobj; //!< 内核对象节点 + sched_t sche; //!< 调度节点 + kobject_t *task; //!< 绑定的task + sp_info_t sp; //!< sp信息 + ram_limit_t *lim; //!< 内存限制 + ref_counter_t ref; //!< 引用计数 + + msg_buf_t msg; //!< 每个线程独有的消息缓存区 + slist_head_t wait_send; //!< 节点 + slist_head_t wait_head; //!< 里面是等待发送给当前线程数据的线程们。 + mword_t ipc_times; //!< ipc时间 + thread_t *last_send_th; //!< 当前线程上次接收到谁的数据 + + enum thread_state status; //!< 线程状态 + enum thread_ipc_state ipc_status; //!< ipc状态 + + umword_t magic; //!< maigc } thread_t; static inline void thread_set_msg_bug(thread_t *th, void *msg) @@ -119,4 +182,6 @@ void thread_sched(void); void thread_suspend(thread_t *th); void thread_dead(thread_t *th); void thread_todead(thread_t *th, bool_t is_sche); -void thread_ready(thread_t *th, bool_t is_sche); \ No newline at end of file +void thread_ready(thread_t *th, bool_t is_sche); + +void thread_timeout_check(ssize_t tick); \ No newline at end of file diff --git a/mkrtos_knl/inc/lib/types.h b/mkrtos_knl/inc/lib/types.h index dddcac131..0b36b3706 100755 --- a/mkrtos_knl/inc/lib/types.h +++ b/mkrtos_knl/inc/lib/types.h @@ -20,6 +20,7 @@ typedef signed long int intptr_t; typedef unsigned long int uintptr_t; typedef umword_t size_t; +typedef mword_t ssize_t; typedef umword_t ptr_t; typedef char bool_t; typedef unsigned long obj_addr_t; diff --git a/mkrtos_knl/knl/futex.c b/mkrtos_knl/knl/futex.c index dc4823dda..a2dc433a0 100644 --- a/mkrtos_knl/knl/futex.c +++ b/mkrtos_knl/knl/futex.c @@ -445,7 +445,7 @@ static void futex_release_stage2(kobject_t *kobj) } static void futex_init(futex_t *ft) { - kobject_init(&ft->kobj, IPC_TYPE); + kobject_init(&ft->kobj, FUTEX_TYPE); spinlock_init(&ft->lock); ft->kobj.invoke_func = futex_syscall; ft->kobj.stage_1_func = futex_release_stage1; diff --git a/mkrtos_knl/knl/ipc.c b/mkrtos_knl/knl/ipc.c index bece3f8a9..801397e26 100755 --- a/mkrtos_knl/knl/ipc.c +++ b/mkrtos_knl/knl/ipc.c @@ -277,8 +277,8 @@ static int ipc_data_copy(thread_t *dst_th, thread_t *src_th, msg_tag_t tag) static msg_tag_t ipc_call(ipc_t *ipc, thread_t *th, entry_frame_t *f, msg_tag_t tag, ipc_timeout_t timeout) { umword_t status; - int ret = -1; msg_tag_t tmp_tag; + int ret = -1; assert(th != ipc->svr_th); status = spinlock_lock(&ipc->lock); diff --git a/mkrtos_knl/knl/obj_space.c b/mkrtos_knl/knl/obj_space.c index b8604360f..806773838 100755 --- a/mkrtos_knl/knl/obj_space.c +++ b/mkrtos_knl/knl/obj_space.c @@ -102,4 +102,18 @@ kobject_t *obj_space_lookup_kobj(obj_space_t *obj_space, obj_addr_t inx) return NULL; } return obj_map_kobj_get(entry_obj->obj); +} +kobject_t *obj_space_lookup_kobj_cmp_type(obj_space_t *obj_space, obj_addr_t inx, enum knl_obj_type obj_type) +{ + kobject_t *kobj = obj_space_lookup_kobj(obj_space, inx); + + if (!kobj) + { + return NULL; + } + if (kobj->kobj_type != obj_type) + { + return NULL; + } + return kobj; } \ No newline at end of file diff --git a/mkrtos_knl/knl/thread.c b/mkrtos_knl/knl/thread.c index cbfe7d4e0..b19533ee1 100755 --- a/mkrtos_knl/knl/thread.c +++ b/mkrtos_knl/knl/thread.c @@ -23,6 +23,18 @@ #include "thread_armv7m.h" #include "assert.h" #include "err.h" +#include "map.h" +enum thread_op +{ + SET_EXEC_REGS, + RUN_THREAD, + BIND_TASK, + MSG_BUG_GET, + MSG_BUG_SET, + YIELD, + DO_IPC, +}; + static void thread_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_tag, entry_frame_t *f); static bool_t thread_put(kobject_t *kobj); static void thread_release_stage1(kobject_t *kobj); @@ -36,7 +48,8 @@ void thread_init(thread_t *th, ram_limit_t *lim) { kobject_init(&th->kobj, THREAD_TYPE); sched_init(&th->sche); - // slist_init(&th->wait); + slist_init(&th->wait_send); + slist_init(&th->wait_head); ref_counter_init(&th->ref); ref_counter_inc(&th->ref); th->lim = lim; @@ -58,30 +71,28 @@ static void thread_release_stage1(kobject_t *kobj) thread_t *cur = thread_get_current(); kobject_invalidate(kobj); - if (cur == th) + if (cur != th) { - if (th->status == THREAD_READY || th->status == THREAD_TODEAD) + //! 线程在运行中,则挂起线程 + if (th->status == THREAD_READY) { - thread_dead(th); - } - } - else - { - if (th->status == THREAD_TODEAD) //!< 如果在TODEAD状态则等待其死亡 - { - while (th->status != THREAD_DEAD) - { - //!< 循环等待其死亡 - thread_sched(); - preemption(); - } - } - else if (th->status == THREAD_READY) - { - thread_dead(th); + thread_suspend(th); } } + thread_t *pos; + slist_foreach_not_next(pos, &th->wait_head, wait_send) + { + assert(pos->status == THREAD_SUSPEND); + thread_t *next = slist_next_entry(pos, &th->wait_head, wait_send); + + pos->ipc_status = THREAD_IPC_ABORT; + thread_ready(pos, TRUE); + + slist_del(&pos->wait_send); + pos = next; + } + slist_del(&th->wait_send); //!< 从链表中删除 thread_unbind(th); } static void thread_release_stage2(kobject_t *kobj) @@ -243,15 +254,346 @@ thread_t *thread_create(ram_limit_t *ram) printk("create thread 0x%x\n", th); return th; } -enum thread_op +enum IPC_TYPE { - SET_EXEC_REGS, - RUN_THREAD, - BIND_TASK, - MSG_BUG_GET, - MSG_BUG_SET, - YIELD, + IPC_CALL, + IPC_REPLY, + IPC_WAIT, + IPC_RECV, + IPC_SEND, }; +void thread_timeout_check(ssize_t tick) +{ + thread_t *pos; + thread_t *th = thread_get_current(); + + slist_foreach_not_next(pos, &th->wait_head, wait_send) + { + assert(pos->status == THREAD_SUSPEND); + thread_t *next = slist_next_entry(pos, &th->wait_head, wait_send); + + if (pos->ipc_times > 0) + { + pos->ipc_times -= tick; + if (pos->ipc_times <= 0) + { + pos->ipc_status = THREAD_TIMEOUT; + thread_ready(pos, TRUE); + + slist_del(&pos->wait_send); + } + } + pos = next; + } +} +/** + * @brief ipc传输时的数据拷贝 + * + * @param dst_th + * @param src_th + * @param tag + * @return int + */ +static int ipc_data_copy(thread_t *dst_th, thread_t *src_th, msg_tag_t tag) +{ + void *src = src_th->msg.msg; + void *dst = dst_th->msg.msg; + ipc_msg_t *src_ipc; + ipc_msg_t *dst_ipc; + + src_ipc = src; + dst_ipc = dst; + + if (tag.map_buf_len > 0) + { + kobj_del_list_t del; + int map_len = tag.map_buf_len; + + kobj_del_list_init(&del); + task_t *src_tk = thread_get_bind_task(src_th); + task_t *dst_tk = thread_get_bind_task(dst_th); + for (int i = 0; i < map_len; i++) + { + int ret = 0; + + vpage_t dst_page = vpage_create_raw(dst_ipc->map_buf[i]); + vpage_t src_page = vpage_create_raw(src_ipc->map_buf[i]); + + if (src_page.flags & VPAGE_FLAGS_MAP) + { + ret = obj_map_src_dst(&dst_tk->obj_space, &src_tk->obj_space, + vpage_get_obj_handler(dst_page), + vpage_get_obj_handler(src_page), + dst_tk->lim, + vpage_get_attrs(src_page), &del); + } + + if (ret < 0) + { + return ret; + } + } + kobj_del_list_to_do(&del); + } + memcpy(dst_ipc->msg_buf, src_ipc->msg_buf, MIN(tag.msg_buf_len * WORD_BYTES, IPC_MSG_SIZE)); + return 0; +} + +/** + * @brief 当前线程接收数据 + * + * @return int + */ +static int thread_ipc_recv(msg_tag_t *ret_msg) +{ + assert(ret_msg); + thread_t *cur_th = thread_get_current(); + umword_t lock_status; + + lock_status = cpulock_lock(); + cur_th->ipc_status = THREAD_RECV; //!< 因为接收挂起 + + thread_suspend(cur_th); //!< 挂起 + if (!slist_is_empty(&cur_th->wait_head)) + { + slist_head_t *mslist = slist_first(&cur_th->wait_head); + thread_t *send_th = container_of(mslist, thread_t, wait_send); + + slist_del(mslist); //!< 删除唤醒的线程 + thread_ready(send_th, TRUE); + } + preemption(); //!< 进行调度 + cur_th->ipc_status = THREAD_NONE; + *ret_msg = cur_th->msg.tag; + cpulock_set(lock_status); + + return 0; +} + +/** + * @brief 当前线程回复数据给上一次的发送者,回复完成后则释放上一次的接收者指针 + * + * @param in_tag + * @return int + */ +static int thread_ipc_reply(msg_tag_t in_tag) +{ + thread_t *cur_th = thread_get_current(); + umword_t status; + + if (cur_th->last_send_th == NULL) + { + return -1; + } + status = cpulock_lock(); + if (cur_th->last_send_th == NULL) + { + cpulock_set(status); + return -1; + } + assert(cur_th->last_send_th->status == THREAD_SUSPEND); + assert(cur_th->last_send_th->ipc_status == THREAD_RECV); + //!< 发送数据给上一次的发送者 + int ret = ipc_data_copy(cur_th->last_send_th, cur_th, in_tag); //!< 拷贝数据 + + if (ret < 0) + { + cpulock_set(status); + return ret; + } + cur_th->last_send_th->msg.tag = in_tag; + thread_ready(cur_th->last_send_th, TRUE); //!< 直接唤醒接受者 + ref_counter_dec_and_release(&cur_th->last_send_th->ref, &cur_th->last_send_th->kobj); + cur_th->last_send_th = NULL; + cpulock_set(status); + return ret; +} +static int thread_ipc_send(obj_handler_t target_th_hd, msg_tag_t in_tag, ipc_timeout_t timout) +{ + int ret = -EINVAL; + task_t *cur_task = thread_get_current_task(); + thread_t *cur_th = thread_get_current(); + mword_t lock_stats = spinlock_lock(&cur_task->kobj.lock); + thread_t *recv_kobj; + + if (lock_stats < 0) + { + //!< 锁已经无效了 + return -EACCES; + } + ref_counter_inc(&cur_task->ref_cn); + recv_kobj = (thread_t *)obj_space_lookup_kobj_cmp_type(&cur_task->obj_space, target_th_hd, THREAD_TYPE); + if (!recv_kobj) /*比较类型*/ + { + return -ENOENT; + } +again_check: + if (recv_kobj->status == THREAD_READY) + { + cur_th->ipc_status = THREAD_SEND; //!< 因为发送挂起 + cur_th->ipc_times = timout.send_timeout; + thread_suspend(cur_th); //!< 挂起 + slist_add_append(&recv_kobj->wait_head, &cur_th->wait_send); //!< 放到等待队列中 + preemption(); //!< 进行调度 + if (cur_th->ipc_status == THREAD_IPC_ABORT) + { + ret = -ESHUTDOWN; + goto end; + } + else if (cur_th->ipc_status == THREAD_TIMEOUT) + { + ret = -EWTIMEDOUT; + goto end; + } + cur_th->ipc_status = THREAD_NONE; + goto again_check; + } + else if (recv_kobj->status == THREAD_SUSPEND && recv_kobj->ipc_status == THREAD_RECV) + { + //!< 开始发送数据 + ret = ipc_data_copy(recv_kobj, cur_th, in_tag); //!< 拷贝数据 + if (ret < 0) + { + //!< 拷贝失败 + goto end; + } + thread_ready(recv_kobj, TRUE); //!< 直接唤醒接受者 + preemption(); //!< 进行调度 + } + ret = 0; +end: + spinlock_set(&cur_task->kobj.lock, lock_stats); + ref_counter_dec_and_release(&cur_task->ref_cn, &cur_task->kobj); + return ret; +} +static int thread_ipc_call(obj_handler_t target_th_hd, msg_tag_t in_tag, msg_tag_t *ret_tag, ipc_timeout_t timout) +{ + assert(ret_tag); + int ret = -EINVAL; + task_t *cur_task = thread_get_current_task(); + thread_t *cur_th = thread_get_current(); + thread_t *recv_kobj; + mword_t lock_stats = spinlock_lock(&cur_task->kobj.lock); + + if (lock_stats < 0) + { + //!< 锁已经无效了 + return -EACCES; + } + ref_counter_inc(&cur_task->ref_cn); + recv_kobj = (thread_t *)obj_space_lookup_kobj_cmp_type(&cur_task->obj_space, target_th_hd, THREAD_TYPE); + if (!recv_kobj) /*比较类型*/ + { + ret = -ENOENT; + goto end; + } +again_check: + if (recv_kobj->status == THREAD_READY) + { + cur_th->ipc_status = THREAD_SEND; //!< 因为发送挂起 + cur_th->ipc_times = timout.send_timeout; + thread_suspend(cur_th); //!< 挂起 + slist_add_append(&recv_kobj->wait_head, &cur_th->wait_send); //!< 放到等待队列中 + preemption(); //!< 进行调度 + if (cur_th->ipc_status == THREAD_IPC_ABORT) + { + cur_th->ipc_status = THREAD_NONE; + ret = -ESHUTDOWN; + goto end; + } + else if (cur_th->ipc_status == THREAD_TIMEOUT) + { + ret = -EWTIMEDOUT; + goto end; + } + cur_th->ipc_status = THREAD_NONE; + goto again_check; + } + else if (recv_kobj->status == THREAD_SUSPEND && recv_kobj->ipc_status == THREAD_RECV) + { + //!< 开始发送数据 + ret = ipc_data_copy(recv_kobj, cur_th, in_tag); //!< 拷贝数据 + if (ret < 0) + { + //!< 拷贝失败 + goto end; + } + recv_kobj->last_send_th = cur_th; //!< 设置接收者的上一次发送者是谁 + ref_counter_inc(&cur_th->ref); //!< 作为发送者增加一次引用 + thread_ready(recv_kobj, TRUE); //!< 直接唤醒接受者 + thread_ipc_recv(ret_tag); //!< 当前线程进行接收 + preemption(); //!< 进行调度 + } + ret = 0; +end: + spinlock_set(&cur_task->kobj.lock, lock_stats); + ref_counter_dec_and_release(&cur_task->ref_cn, &cur_task->kobj); + return ret; +} +/** + * @brief 执行ipc + * + * @param kobj + * @param in_tag + * @param f + * @return int + */ +static msg_tag_t thread_do_ipc(kobject_t *kobj, entry_frame_t *f) +{ + assert(kobj); + task_t *cur_task = thread_get_current_task(); + thread_t *cur_th = thread_get_current(); + umword_t ipc_type = f->r[1]; + obj_handler_t th_hd = 0; + int ret = -EINVAL; + + switch (ipc_type) + { + case IPC_CALL: + { + msg_tag_t in_tag = msg_tag_init(f->r[0]); + msg_tag_t recv_tag; + th_hd = f->r[2]; + ipc_timeout_t ipc_tm_out = ipc_timeout_create(f->r[3]); + + ret = thread_ipc_call(th_hd, in_tag, &recv_tag, ipc_tm_out); + if (ret < 0) + { + return msg_tag_init4(0, 0, 0, ret); + } + return recv_tag; + } + case IPC_REPLY: + { + msg_tag_t in_tag = msg_tag_init(f->r[0]); + + ret = thread_ipc_reply(in_tag); + return msg_tag_init4(0, 0, 0, ret); + } + case IPC_RECV: + case IPC_WAIT: + { + msg_tag_t ret_msg; + + thread_ipc_recv(&ret_msg); + return ret_msg; + } + case IPC_SEND: + { + msg_tag_t in_tag = msg_tag_init(f->r[0]); + ipc_timeout_t ipc_tm_out = ipc_timeout_create(f->r[3]); + th_hd = f->r[2]; + + ret = thread_ipc_send(th_hd, in_tag, ipc_tm_out); + return msg_tag_init4(0, 0, 0, ret); + } + default: + ret = -ENOSYS; + break; + } + + return msg_tag_init4(0, 0, 0, ret); +} static void thread_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_tag, entry_frame_t *f) { msg_tag_t tag = msg_tag_init4(0, 0, 0, -EINVAL); @@ -330,6 +672,11 @@ static void thread_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_t tag = msg_tag_init4(0, 0, 0, 0); } break; + case DO_IPC: + { + tag = thread_do_ipc(&cur_th->kobj, f); + } + break; } f->r[0] = tag.raw; } diff --git a/mkrtos_user/lib/sys/inc/u_thread.h b/mkrtos_user/lib/sys/inc/u_thread.h index 7f024e4d7..f5effef81 100644 --- a/mkrtos_user/lib/sys/inc/u_thread.h +++ b/mkrtos_user/lib/sys/inc/u_thread.h @@ -2,7 +2,7 @@ #include "u_types.h" #include "u_prot.h" - +#include "u_ipc.h" msg_tag_t thread_yield(obj_handler_t obj); msg_tag_t thread_msg_buf_set(obj_handler_t obj, void *msg); msg_tag_t thread_msg_buf_get(obj_handler_t obj, umword_t *msg, umword_t *len); @@ -10,6 +10,11 @@ msg_tag_t thread_exec_regs(obj_handler_t obj, umword_t pc, umword_t sp, umword_t msg_tag_t thread_run(obj_handler_t obj, uint8_t prio); msg_tag_t thread_bind_task(obj_handler_t obj, obj_handler_t tk_obj); +msg_tag_t thread_ipc_wait(void); +msg_tag_t thread_ipc_reply(msg_tag_t in_tag, ipc_timeout_t timeout); +msg_tag_t thread_ipc_send(msg_tag_t in_tag, obj_handler_t target_th_obj, ipc_timeout_t timeout); +msg_tag_t thread_ipc_call(msg_tag_t in_tag, obj_handler_t target_th_obj, ipc_timeout_t timeout); + #define thread_get_cur_ipc_msg() \ ( \ { \ diff --git a/mkrtos_user/lib/sys/src/u_thread.c b/mkrtos_user/lib/sys/src/u_thread.c index 8694bd57f..014341fc5 100644 --- a/mkrtos_user/lib/sys/src/u_thread.c +++ b/mkrtos_user/lib/sys/src/u_thread.c @@ -1,6 +1,7 @@ #include "u_prot.h" #include "u_types.h" #include "u_thread.h" +#include "u_ipc.h" enum thread_op { SET_EXEC_REGS, @@ -9,7 +10,80 @@ enum thread_op MSG_BUG_GET, MSG_BUG_SET, YIELD, + DO_IPC, }; +enum IPC_TYPE +{ + IPC_CALL, + IPC_REPLY, + IPC_WAIT, + IPC_RECV, + IPC_SEND, +}; +msg_tag_t thread_ipc_wait(void) +{ + register volatile umword_t r0 asm("r0"); + mk_syscall(syscall_prot_create4(DO_IPC, THREAD_PROT, -1, TRUE).raw, + 0, + IPC_WAIT, + 0, + 0, + 0, + 0); + asm __volatile__("" + : + : + : "r0"); + return msg_tag_init(r0); +} +msg_tag_t thread_ipc_reply(msg_tag_t in_tag, ipc_timeout_t timeout) +{ + register volatile umword_t r0 asm("r0"); + mk_syscall(syscall_prot_create4(DO_IPC, THREAD_PROT, -1, TRUE).raw, + in_tag.raw, + IPC_REPLY, + 0, + timeout.raw, + 0, + 0); + asm __volatile__("" + : + : + : "r0"); + return msg_tag_init(r0); +} +msg_tag_t thread_ipc_send(msg_tag_t in_tag, obj_handler_t target_th_obj, ipc_timeout_t timeout) +{ + register volatile umword_t r0 asm("r0"); + mk_syscall(syscall_prot_create4(DO_IPC, THREAD_PROT, -1, TRUE).raw, + in_tag.raw, + IPC_SEND, + target_th_obj, + timeout.raw, + 0, + 0); + asm __volatile__("" + : + : + : "r0"); + return msg_tag_init(r0); +} +msg_tag_t thread_ipc_call(msg_tag_t in_tag, obj_handler_t target_th_obj, ipc_timeout_t timeout) +{ + register volatile umword_t r0 asm("r0"); + mk_syscall(syscall_prot_create4(DO_IPC, THREAD_PROT, -1, TRUE).raw, + in_tag.raw, + IPC_CALL, + target_th_obj, + timeout.raw, + 0, + 0); + asm __volatile__("" + : + : + : "r0"); + return msg_tag_init(r0); +} msg_tag_t thread_yield(obj_handler_t obj) { register volatile umword_t r0 asm("r0"); diff --git a/mkrtos_user/server/init/src/main.c b/mkrtos_user/server/init/src/main.c index 06140535e..fad01edf2 100644 --- a/mkrtos_user/server/init/src/main.c +++ b/mkrtos_user/server/init/src/main.c @@ -35,10 +35,10 @@ int main(int argc, char *args[]) mpu_test(); thread_press_test(); kobj_create_press_test(); - ipc_test(); pthread_cond_lock_test(); pthread_lock_test(); #endif + ipc_test(); uenv_t env = *u_get_global_env(); obj_handler_t ipc_hd; int ret = rpc_creaite_bind_ipc(THREAD_MAIN, NULL, &ipc_hd); diff --git a/mkrtos_user/server/init/src/test/ipc_test.c b/mkrtos_user/server/init/src/test/ipc_test.c index 5f01c0033..2d24093a9 100644 --- a/mkrtos_user/server/init/src/test/ipc_test.c +++ b/mkrtos_user/server/init/src/test/ipc_test.c @@ -69,7 +69,7 @@ static void thread_test_func2(void) static void hard_sleep(void) { - for (volatile int i; i < 10000000; i++) + for (volatile int i; i < 1000000000; i++) ; } static void thread_test_func(void) @@ -79,10 +79,10 @@ static void thread_test_func(void) thread_msg_buf_get(th1_hd, (umword_t *)(&buf), NULL); while (1) { - ipc_wait(ipc_hd, 0); + thread_ipc_wait(); printf("srv recv:%s", buf); hard_sleep(); - ipc_reply(ipc_hd, msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0)); + thread_ipc_reply(msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0), ipc_timeout_create2(0, 0)); } printf("thread_test_func.\n"); task_unmap(TASK_PROT, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th1_hd)); @@ -96,7 +96,7 @@ static void thread_test_func2(void) while (1) { strcpy(buf, "I am th2.\n"); - ipc_call(ipc_hd, msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0), ipc_timeout_create2(0, 0)); + thread_ipc_call(msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0), th1_hd, ipc_timeout_create2(0, 0)); printf("th2:%s", buf); } printf("thread_test_func2.\n"); @@ -113,7 +113,7 @@ static void thread_test_func3(void) while (1) { strcpy(buf, "I am th3.\n"); - ipc_call(ipc_hd, msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0), ipc_timeout_create2(0, 0)); + thread_ipc_call(msg_tag_init4(0, ROUND_UP(strlen(buf), WORD_BYTES), 0, 0), th1_hd, ipc_timeout_create2(0, 0)); printf("th3:%s", buf); } printf("thread_test_func2.\n"); @@ -127,17 +127,14 @@ static void thread_test_func3(void) */ void ipc_test(void) { + msg_tag_t tag; th1_hd = handler_alloc(); assert(th1_hd != HANDLER_INVALID); th2_hd = handler_alloc(); assert(th2_hd != HANDLER_INVALID); th3_hd = handler_alloc(); assert(th3_hd != HANDLER_INVALID); - ipc_hd = handler_alloc(); - assert(ipc_hd != HANDLER_INVALID); - msg_tag_t tag = factory_create_ipc(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, ipc_hd)); - assert(msg_tag_get_prot(tag) >= 0); tag = factory_create_thread(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, th1_hd)); assert(msg_tag_get_prot(tag) >= 0); ipc_bind(ipc_hd, th1_hd, 0); @@ -176,11 +173,4 @@ void ipc_test(void) void ipc_timeout_test(void) { - obj_handler_t hd = handler_alloc(); - factory_create_ipc(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, hd)); - printf("sleep.\n"); - ipc_call(hd, msg_tag_init4(0, 0, 0, 0), ipc_timeout_create2(100, 100)); - printf("sleep.\n"); - ipc_call(hd, msg_tag_init4(0, 0, 0, 0), ipc_timeout_create2(100, 100)); - handler_free_umap(hd); }