优化futex

This commit is contained in:
zhangzheng
2023-11-27 21:47:05 +08:00
parent d1cfcedc67
commit 5fc71a7f98
9 changed files with 182 additions and 83 deletions

View File

@@ -10,9 +10,12 @@ typedef struct futex_queue
int front;
int rear;
} futex_queue_t;
typedef int (*futex_iter_func)(umword_t e, void *data);
void fq_init(futex_queue_t *q);
int fq_empty(futex_queue_t *q);
int fq_enqueue(futex_queue_t *q, umword_t e);
int fq_dequeue(futex_queue_t *q, umword_t *e);
int fq_queue_len(futex_queue_t *q);
bool_t fq_is_full(futex_queue_t *q);
int fq_queue_iter(futex_queue_t *q, futex_iter_func iter_func, void *data);

View File

@@ -11,8 +11,11 @@
#include "assert.h"
struct kobject;
typedef struct kobject kobject_t;
struct obj_space;
typedef struct obj_space obj_space_t;
typedef void (*syscall_func)(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_tag, entry_frame_t *f);
typedef void (*obj_unmap_func)(obj_space_t *obj_space_obj, kobject_t *kobj);
typedef void (*obj_release_stage_1_func)(kobject_t *kobj);
typedef void (*obj_release_stage_2_func)(kobject_t *kobj);
typedef bool_t (*obj_release_put)(kobject_t *kobj);
@@ -51,6 +54,7 @@ typedef struct kobject
obj_release_stage_1_func stage_1_func;
obj_release_stage_2_func stage_2_func;
obj_release_put put_func;
obj_unmap_func unmap_func;
enum knl_obj_type kobj_type;
} kobject_t;

View File

@@ -116,7 +116,7 @@ typedef struct msg_buf
msg_tag_t tag; //!< 存放发送的临时标识
} msg_buf_t;
#define THREAD_MAIGC 0xdeadead //!< 用于栈溢出检测
#define THREAD_MAGIC 0xdeadead //!< 用于栈溢出检测
typedef struct thread
{
kobject_t kobj; //!< 内核对象节点
@@ -126,6 +126,8 @@ typedef struct thread
ram_limit_t *lim; //!< 内存限制
ref_counter_t ref; //!< 引用计数
slist_head_t futex_node; //!< futex使用
msg_buf_t msg; //!< 每个线程独有的消息缓存区
slist_head_t wait_node; //!< 节点
mword_t ipc_times; //!< ipc时间

View File

@@ -24,6 +24,7 @@
#include "string.h"
#include "ipc.h"
#include "err.h"
#include "slist.h"
#include <access.h>
#define INT_MAX 0x7fffffff
@@ -59,15 +60,15 @@ struct timespec
*/
typedef struct futex_lock
{
uint32_t *uaddr; //!< 锁的地址
futex_queue_t fqt; //!< 锁的等待队列
uint32_t *uaddr; //!< 锁的地址
slist_head_t thread_list_head;
size_t cnt;
} futex_lock_t;
typedef struct futex
{
kobject_t kobj;
futex_lock_t fl_list[FT_ADDR_NR]; //!< 存储加锁的地址
spinlock_t lock;
} futex_t;
static futex_t futex_obj;
static void futex_init(futex_t *ft);
@@ -75,7 +76,7 @@ typedef struct futex_wait_item
{
slist_head_t node;
thread_t *th;
umword_t sleep_times;
mword_t sleep_times;
} futex_wait_item_t;
static slist_head_t wait_list;
@@ -96,23 +97,24 @@ void futex_timeout_times_tick(void)
{
futex_wait_item_t *item;
slist_foreach(item, &wait_list, node) //!< 第一次循环等待的ipc
slist_foreach_not_next(item, &wait_list, node) //!< 第一次循环等待的ipc
{
futex_wait_item_t *next = slist_next_entry(item, &wait_list, node);
if (item->sleep_times > 0)
{
if ((--item->sleep_times) == 0)
{
slist_del(&item->node);
//!< 超时时间满后直接唤醒等待者
thread_ready(item->th, TRUE);
}
}
else
{
if (item->th->status == THREAD_SUSPEND)
{
thread_ready(item->th, TRUE);
}
slist_del(&item->node);
thread_ready(item->th, TRUE);
}
item = next;
}
}
static void futex_reg(void)
@@ -122,24 +124,41 @@ static void futex_reg(void)
}
INIT_KOBJ(futex_reg);
static bool_t futex_find_thread(futex_queue_t *fq, thread_t *thread_hd)
static bool_t futex_find_thread(futex_lock_t *flt, thread_t *thread_hd)
{
int find = 0;
int len;
thread_t *pos;
len = fq_queue_len(fq);
for (int i = 0; i < len; i++)
slist_foreach(pos, &flt->thread_list_head, futex_node)
{
umword_t out;
fq_dequeue(fq, &out);
if (out == (umword_t)thread_hd)
if (pos == thread_hd)
{
find = 1;
return TRUE;
}
fq_enqueue(fq, out);
}
return find;
return FALSE;
}
static void futex_enqueue(futex_lock_t *flt, thread_t *th)
{
slist_add_append(&flt->thread_list_head, &th->futex_node);
flt->cnt++;
}
static int futex_dequeue(futex_lock_t *flt, thread_t **th)
{
assert(th);
if (slist_is_empty(&flt->thread_list_head))
{
return -1;
}
slist_head_t *first = slist_first(&flt->thread_list_head);
slist_del(first);
flt->cnt--;
*th = container_of(first, thread_t, futex_node);
return 0;
}
static size_t futex_cnt(futex_lock_t *flt)
{
return flt->cnt;
}
/**
* @brief 查找一个地址,如果已经有了,则加入等待,否则增加一个信息,并加入等待
@@ -157,9 +176,9 @@ static futex_lock_t *futex_set_addr(futex_t *ft, void *uaddr, thread_t *hd)
{
if (ft->fl_list[i].uaddr == uaddr)
{
if (!futex_find_thread(&ft->fl_list[i].fqt, hd))
if (!futex_find_thread(&ft->fl_list[i], hd))
{
fq_enqueue(&ft->fl_list[i].fqt, (umword_t)hd);
futex_enqueue(&ft->fl_list[i], hd);
}
return &ft->fl_list[i];
}
@@ -171,7 +190,7 @@ static futex_lock_t *futex_set_addr(futex_t *ft, void *uaddr, thread_t *hd)
if (empty_inx != -1)
{
ft->fl_list[empty_inx].uaddr = uaddr;
fq_enqueue(&ft->fl_list[empty_inx].fqt, (umword_t)hd);
futex_enqueue(&ft->fl_list[empty_inx], hd);
return &ft->fl_list[empty_inx];
}
return NULL;
@@ -196,14 +215,14 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
futex_op = futex_op & 0x7f;
umword_t status;
status = spinlock_lock(&fst->lock);
status = spinlock_lock(&fst->kobj.lock);
switch (futex_op)
{
case FUTEX_REQUEUE:
{
if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE))
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -EACCES;
}
if (val3 == *uaddr)
@@ -214,47 +233,47 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
if (flt)
{
wake_cnt = val = INT_MAX ? fq_queue_len(&flt->fqt) : val;
wake_cnt = val = INT_MAX ? futex_cnt(flt) : val;
for (int i = 0; i < wake_cnt; i++)
{
thread_t *th;
int ret = fq_dequeue(&flt->fqt, (umword_t *)&th);
int ret = futex_dequeue(flt, &th);
if (ret != 0)
{
continue;
}
if (fq_queue_len(&flt->fqt) == 0)
if (futex_cnt(flt) == 0)
{
flt->uaddr = 0;
}
thread_ready(th, TRUE);
}
if (fq_queue_len(&flt->fqt) <= 0)
if (futex_cnt(flt) <= 0)
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return wake_cnt;
}
int requeue_cn = fq_queue_len(&flt->fqt);
int requeue_cn = futex_cnt(flt);
rel_cnt = requeue_cn;
for (int i = 0; i < rel_cnt; i++)
{
thread_t *th;
int ret = fq_dequeue(&flt->fqt, (umword_t *)&th);
int ret = futex_dequeue(flt, &th);
if (ret != 0)
{
continue;
}
if (fq_queue_len(&flt->fqt) == 0)
if (futex_cnt(flt) == 0)
{
flt->uaddr = 0;
}
futex_set_addr(fst, (void *)uaddr2, th);
}
}
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return wake_cnt;
}
}
@@ -263,16 +282,16 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
{
if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE))
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -EACCES;
}
if (val == *uaddr)
if (val == *uaddr) //!< 检查值是否时期望值
{
ref_counter_inc(&cur_th->ref);
ref_counter_inc(&cur_th->ref); //!< 指定线程引用计数+1
if (futex_set_addr(fst, uaddr, cur_th) == NULL)
{
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -ENOMEM;
}
if (timeout != 0)
@@ -287,26 +306,37 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
slist_add_append(&wait_list, &item.node);
thread_suspend(cur_th);
preemption();
slist_del(&item.node);
if (timeout <= 0)
if (item.sleep_times <= 0)
{
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -ETIMEDOUT;
}
if (cur_th->ipc_status == THREAD_IPC_ABORT)
{
cur_th->ipc_status = THREAD_NONE;
spinlock_set(&fst->kobj.lock, status);
return 0;
}
}
else
{
// 一直等待
thread_suspend(cur_th);
preemption();
if (cur_th->ipc_status == THREAD_IPC_ABORT)
{
cur_th->ipc_status = THREAD_NONE;
spinlock_set(&fst->kobj.lock, status);
return 0;
}
}
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
}
else
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -EAGAIN;
}
break;
@@ -319,16 +349,16 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
if (flt)
{
rel_cnt = val = INT_MAX ? fq_queue_len(&flt->fqt) : val;
rel_cnt = val = INT_MAX ? futex_cnt(flt) : val;
for (int i = 0; i < rel_cnt; i++)
{
thread_t *th;
int ret = fq_dequeue(&flt->fqt, (umword_t *)(&th));
int ret = futex_dequeue(flt, (&th));
if (ret == 0)
{
if (fq_queue_len(&flt->fqt) == 0)
if (futex_cnt(flt) == 0)
{
flt->uaddr = 0;
}
@@ -336,7 +366,7 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
}
}
}
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return rel_cnt;
}
case FUTEX_UNLOCK_PI:
@@ -344,7 +374,7 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
{
if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE))
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -EACCES;
}
futex_lock_t *flt = futex_find(fst, uaddr);
@@ -352,16 +382,16 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
if (flt)
{
rel_cnt = val = INT_MAX ? fq_queue_len(&flt->fqt) : val;
rel_cnt = val = INT_MAX ? futex_cnt(flt) : val;
for (int i = 0; i < rel_cnt; i++)
{
thread_t *th;
int ret = fq_dequeue(&flt->fqt, (umword_t *)(&th));
int ret = futex_dequeue(flt, (&th));
if (ret == 0)
{
if (fq_queue_len(&flt->fqt) == 0)
if (futex_cnt(flt) == 0)
{
flt->uaddr = 0;
}
@@ -370,14 +400,14 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
}
}
*uaddr = 0;
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return rel_cnt;
}
case FUTEX_LOCK_PI:
{
if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE))
{
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -EACCES;
}
if (*uaddr = 0)
@@ -391,10 +421,10 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v
break;
}
default:
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return -ENOSYS;
}
spinlock_set(&fst->lock, status);
spinlock_set(&fst->kobj.lock, status);
return 0;
}
static void futex_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_tag, entry_frame_t *f)
@@ -435,9 +465,42 @@ static void futex_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_ta
}
f->r[0] = tag.raw;
}
static void futex_unmap(obj_space_t *obj_space, kobject_t *kobj)
{
task_t *task = container_of(obj_space, task_t, obj_space);
futex_t *futex = container_of(kobj, futex_t, kobj);
printk("%s:%d\n", __func__, __LINE__);
umword_t status = spinlock_lock(&futex->kobj.lock);
for (int i = 0; i < FT_ADDR_NR; i++)
{
thread_t *pos;
if (futex->fl_list[i].uaddr)
{
slist_foreach_not_next(pos, &futex->fl_list[i].thread_list_head, futex_node)
{
thread_t *next = slist_next_entry(pos, &futex->fl_list[i].thread_list_head, futex_node);
task_t *bind_task = thread_get_bind_task(pos);
if (bind_task == task)
{
assert(pos->status == THREAD_SUSPEND);
slist_del(&pos->futex_node);
pos->status == THREAD_IPC_ABORT;
thread_ready(pos, TRUE);
}
pos = next;
}
}
}
spinlock_set(&futex->kobj.lock, status);
}
static void futex_release_stage1(kobject_t *kobj)
{
/*TODO:删除task所占用的futex资源*/
/*删除的任务可能不是当前任务*/
}
static void futex_release_stage2(kobject_t *kobj)
{
@@ -446,8 +509,12 @@ static void futex_release_stage2(kobject_t *kobj)
static void futex_init(futex_t *ft)
{
kobject_init(&ft->kobj, FUTEX_TYPE);
spinlock_init(&ft->lock);
for (int i = 0; i < FT_ADDR_NR; i++)
{
slist_init(&ft->fl_list[i].thread_list_head);
}
ft->kobj.invoke_func = futex_syscall;
ft->kobj.unmap_func = futex_unmap;
ft->kobj.stage_1_func = futex_release_stage1;
ft->kobj.stage_2_func = futex_release_stage2;
}

View File

@@ -19,6 +19,10 @@ int fq_empty(futex_queue_t *q)
return 0;
}
}
bool_t fq_is_full(futex_queue_t *q)
{
return (q->rear + 1) % FUTEX_QUEUE_LEN == q->front;
}
int fq_enqueue(futex_queue_t *q, umword_t e)
{
if (((q->rear + 1) % FUTEX_QUEUE_LEN) == q->front)
@@ -42,4 +46,20 @@ int fq_dequeue(futex_queue_t *q, umword_t *e)
int fq_queue_len(futex_queue_t *q)
{
return (q->rear - q->front + FUTEX_QUEUE_LEN) % FUTEX_QUEUE_LEN;
}
}
int fq_queue_iter(futex_queue_t *q, futex_iter_func iter_func, void *data)
{
assert(iter_func);
int i;
int j = q->front;
int e = (q->rear - q->front + FUTEX_QUEUE_LEN) % FUTEX_QUEUE_LEN;
for (i = 0; i < e; i++)
{
int ret = iter_func(q->m[j], data);
if (ret < 0)
{
return ret;
}
j = (j + 1) % FUTEX_QUEUE_LEN;
}
}

View File

@@ -97,18 +97,21 @@ void obj_unmap(obj_space_t *obj_space, vpage_t vpage, kobj_del_list_t *del_list)
{
return;
}
if (kobj->unmap_func)
{
kobj->unmap_func(obj_space, kobj);
}
if ((vpage.attrs & KOBJ_DELETE_RIGHT) &&
(obj_map_entry_get_attr(entry) & KOBJ_DELETE_RIGHT))
{
//!< 代表删除所有
obj_map_entry_t *pos;
again:
slist_foreach(pos, &kobj->mappable.node, node)
slist_foreach_not_next(pos, &kobj->mappable.node, node)
{
obj_map_entry_t *next = slist_next_entry(pos, &kobj->mappable.node, node);
slist_del(&pos->node);
pos->obj = NULL;
// slist_init(&pos->node);
// 删除一个
kobj->mappable.map_cnt--;
if (kobj->mappable.map_cnt <= 0)
@@ -118,7 +121,7 @@ void obj_unmap(obj_space_t *obj_space, vpage_t vpage, kobj_del_list_t *del_list)
kobj_del_list_add(del_list, &kobj->del_node);
}
}
goto again;
pos = next;
}
}
else
@@ -126,7 +129,6 @@ void obj_unmap(obj_space_t *obj_space, vpage_t vpage, kobj_del_list_t *del_list)
assert(!slist_is_empty(&entry->node));
slist_del(&entry->node);
entry->obj = NULL;
// slist_init(&entry->node);
// 删除一个
kobj->mappable.map_cnt--;
if (kobj->mappable.map_cnt <= 0)

View File

@@ -41,7 +41,7 @@ void scheduler_add(sched_t *node)
{
thread_t *node_th = container_of(node, thread_t, sche);
assert(node_th->magic == THREAD_MAIGC);
assert(node_th->magic == THREAD_MAGIC);
scheduler_t *sched = scheduler_get_current();
assert(node->prio >= 0);
@@ -118,7 +118,7 @@ sp_info_t *schde_to(void *usp, void *ksp, umword_t sp_type)
sched_t *next = sche->cur_sche;
thread_t *next_th = container_of(next, thread_t, sche);
assert(next_th->magic == THREAD_MAIGC);
assert(next_th->magic == THREAD_MAGIC);
if (sched_reset)
{

View File

@@ -67,6 +67,7 @@ void thread_init(thread_t *th, ram_limit_t *lim)
kobject_init(&th->kobj, THREAD_TYPE);
sched_init(&th->sche);
slist_init(&th->wait_node);
slist_init(&th->futex_node);
ref_counter_init(&th->ref);
ref_counter_inc(&th->ref);
th->lim = lim;
@@ -74,7 +75,7 @@ void thread_init(thread_t *th, ram_limit_t *lim)
th->kobj.put_func = thread_put;
th->kobj.stage_1_func = thread_release_stage1;
th->kobj.stage_2_func = thread_release_stage2;
th->magic = THREAD_MAIGC;
th->magic = THREAD_MAGIC;
}
static bool_t thread_put(kobject_t *kobj)
{
@@ -228,7 +229,7 @@ void thread_sched(void)
sched_t *next_sche = scheduler_next();
thread_t *th = thread_get_current();
assert(th->magic == THREAD_MAIGC);
assert(th->magic == THREAD_MAGIC);
if (next_sche == &th->sche)
{
cpulock_set(status);

View File

@@ -22,23 +22,23 @@ extern void futex_init(void);
int main(int argc, char *args[])
{
ulog_write_str(LOG_PROT, "init..\n");
#if 1
// ulog_test();
// factory_test();
// printf_test();
// thread_exit_test();
// map_test();
#if 0
ulog_test();
factory_test();
printf_test();
thread_exit_test();
map_test();
// mm_test();
// app_test();
// mpu_test();
// thread_press_test();
// kobj_create_press_test();
// pthread_cond_lock_test();
// pthread_lock_test();
// u_sleep_ms(1000);
// ipc_test();
// ipc_obj_test();
mm_test();
app_test();
mpu_test();
thread_press_test();
kobj_create_press_test();
u_sleep_ms(1000);
ipc_test();
ipc_obj_test();
pthread_cond_lock_test();
pthread_lock_test();
#endif
uenv_t env = *u_get_global_env();
env.ns_hd = namespace_init();