线程增加ipc能力,原ipc对象将修改为ipc代理功能
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -15,6 +15,7 @@ void SysTick_Handler(void)
|
||||
// 进行上下文切换
|
||||
thread_sched();
|
||||
sys_tick_cnt++;
|
||||
thread_timeout_check();
|
||||
timeout_times_tick();
|
||||
futex_timeout_times_tick();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ void SysTick_Handler(void)
|
||||
// 进行上下文切换
|
||||
thread_sched();
|
||||
sys_tick_cnt++;
|
||||
thread_timeout_check(1);
|
||||
timeout_times_tick();
|
||||
futex_timeout_times_tick();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -39,6 +39,7 @@ enum knl_obj_type
|
||||
MM_TYPE,
|
||||
FACTORY_TYPE,
|
||||
SYS_TYPE,
|
||||
FUTEX_TYPE,
|
||||
};
|
||||
|
||||
typedef struct kobject
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -70,8 +125,16 @@ typedef struct thread
|
||||
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;
|
||||
|
||||
@@ -120,3 +183,5 @@ 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);
|
||||
|
||||
void thread_timeout_check(ssize_t tick);
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -103,3 +103,17 @@ kobject_t *obj_space_lookup_kobj(obj_space_t *obj_space, obj_addr_t inx)
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() \
|
||||
( \
|
||||
{ \
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user