2023-11-20 16:17:58 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @file futex.c
|
2023-12-02 10:16:14 +08:00
|
|
|
|
* @author ATShining (1358745329@qq.com)
|
2023-11-20 16:17:58 +08:00
|
|
|
|
* @brief futex在内核中实现
|
|
|
|
|
|
* @note TODO: 可以使用hashmap优化
|
|
|
|
|
|
* @version 0.1
|
|
|
|
|
|
* @date 2023-11-20
|
|
|
|
|
|
*
|
|
|
|
|
|
* @copyright Copyright (c) 2023
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
#include "types.h"
|
|
|
|
|
|
#include "init.h"
|
|
|
|
|
|
#include "prot.h"
|
|
|
|
|
|
#include "kobject.h"
|
|
|
|
|
|
#include "factory.h"
|
|
|
|
|
|
#include "task.h"
|
|
|
|
|
|
#include "thread.h"
|
|
|
|
|
|
#include "assert.h"
|
|
|
|
|
|
#include "slist.h"
|
|
|
|
|
|
#include "spinlock.h"
|
|
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
#include "string.h"
|
|
|
|
|
|
#include "ipc.h"
|
2023-11-20 16:17:58 +08:00
|
|
|
|
#include "err.h"
|
2023-11-27 21:47:05 +08:00
|
|
|
|
#include "slist.h"
|
2023-11-28 22:33:37 +08:00
|
|
|
|
#include "access.h"
|
|
|
|
|
|
#include "limits.h"
|
2023-12-05 00:01:26 +08:00
|
|
|
|
#include "futex.h"
|
2024-07-31 23:27:19 +08:00
|
|
|
|
#include "thread_arch.h"
|
2024-04-11 16:08:25 +00:00
|
|
|
|
#include <pre_cpu.h>
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 以下是futex的操作码
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
#define FUTEX_WAIT 0
|
|
|
|
|
|
#define FUTEX_WAKE 1
|
|
|
|
|
|
#define FUTEX_FD 2
|
|
|
|
|
|
#define FUTEX_REQUEUE 3
|
|
|
|
|
|
#define FUTEX_CMP_REQUEUE 4
|
|
|
|
|
|
#define FUTEX_WAKE_OP 5
|
|
|
|
|
|
#define FUTEX_LOCK_PI 6
|
|
|
|
|
|
#define FUTEX_UNLOCK_PI 7
|
|
|
|
|
|
#define FUTEX_TRYLOCK_PI 8
|
|
|
|
|
|
#define FUTEX_WAIT_BITSET 9
|
|
|
|
|
|
#define FUTEX_WAKE_CLEAR 10
|
|
|
|
|
|
#define FUTEX_WAITERS 0x80000000
|
|
|
|
|
|
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex对象的操作码
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
enum futex_op
|
|
|
|
|
|
{
|
2023-12-05 21:16:00 +08:00
|
|
|
|
FUTEX_CTRL, //!< futex的控制
|
2023-11-19 23:01:35 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct timespec
|
|
|
|
|
|
{
|
|
|
|
|
|
time_t tv_sec; /* seconds */
|
|
|
|
|
|
long tv_nsec; /* nanoseconds */
|
|
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 存储锁信息
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
typedef struct futex_lock
|
|
|
|
|
|
{
|
2023-12-05 21:16:00 +08:00
|
|
|
|
uint32_t *uaddr; //!< 锁的地址
|
|
|
|
|
|
slist_head_t thread_list_head; //!< 存储线程的头节点
|
|
|
|
|
|
size_t cnt; //!< 有多少个线程在等待锁
|
2023-11-19 23:01:35 +08:00
|
|
|
|
} futex_lock_t;
|
|
|
|
|
|
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex的对象定义
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
typedef struct futex
|
|
|
|
|
|
{
|
|
|
|
|
|
kobject_t kobj;
|
2023-12-05 00:01:26 +08:00
|
|
|
|
futex_lock_t fl_list[CONFIG_FT_ADDR_NR]; //!< 存储加锁的地址
|
2023-11-19 23:01:35 +08:00
|
|
|
|
} futex_t;
|
2023-11-28 22:33:37 +08:00
|
|
|
|
|
2023-12-05 21:16:00 +08:00
|
|
|
|
static futex_t futex_obj; //!< 全局的futex对象
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static void futex_init(futex_t *ft);
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex的等待的item
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-20 16:17:58 +08:00
|
|
|
|
typedef struct futex_wait_item
|
|
|
|
|
|
{
|
|
|
|
|
|
slist_head_t node;
|
|
|
|
|
|
thread_t *th;
|
2023-11-27 21:47:05 +08:00
|
|
|
|
mword_t sleep_times;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
} futex_wait_item_t;
|
2023-11-28 22:33:37 +08:00
|
|
|
|
|
2024-04-11 16:08:25 +00:00
|
|
|
|
static PER_CPU(slist_head_t, wait_list); //!< futex的等待队列
|
2023-11-20 16:17:58 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 初始化一个超时等待队列
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void futex_wait_list_init(void)
|
|
|
|
|
|
{
|
2024-04-11 16:08:25 +00:00
|
|
|
|
for (int i = 0; i < CONFIG_CPU; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
slist_init(pre_cpu_get_var_cpu(i, &wait_list));
|
|
|
|
|
|
}
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
INIT_KOBJ(futex_wait_list_init);
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 检查超时队列
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
void futex_timeout_times_tick(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
futex_wait_item_t *item;
|
|
|
|
|
|
|
2024-07-30 09:37:49 +08:00
|
|
|
|
slist_foreach_not_next(item,
|
|
|
|
|
|
(slist_head_t *)pre_cpu_get_current_cpu_var(&wait_list),
|
|
|
|
|
|
node) //!< 第一次循环等待的ipc
|
2023-11-20 16:17:58 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
futex_wait_item_t *next = slist_next_entry(item,
|
|
|
|
|
|
(slist_head_t *)pre_cpu_get_current_cpu_var(&wait_list),
|
|
|
|
|
|
node);
|
2023-11-20 16:17:58 +08:00
|
|
|
|
if (item->sleep_times > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((--item->sleep_times) == 0)
|
|
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
slist_del(&item->node);
|
2023-11-20 16:17:58 +08:00
|
|
|
|
//!< 超时时间满后直接唤醒等待者
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_ready_remote(item->th, TRUE);
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
slist_del(&item->node);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_ready_remote(item->th, TRUE);
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
2023-11-27 21:47:05 +08:00
|
|
|
|
item = next;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 初始化全局的futex并注册
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static void futex_reg(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
futex_init(&futex_obj);
|
|
|
|
|
|
global_reg_kobj(&futex_obj.kobj, FUTEX_PROT);
|
|
|
|
|
|
}
|
|
|
|
|
|
INIT_KOBJ(futex_reg);
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 查找futex中指定线程是否存在
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param flt futex_lock_t对象
|
|
|
|
|
|
* @param thread_hd 线程的指针
|
|
|
|
|
|
* @return bool_t TRUE:存在 FALSE:不存在
|
|
|
|
|
|
*/
|
2023-11-27 21:47:05 +08:00
|
|
|
|
static bool_t futex_find_thread(futex_lock_t *flt, thread_t *thread_hd)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
thread_t *pos;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2023-11-27 21:47:05 +08:00
|
|
|
|
slist_foreach(pos, &flt->thread_list_head, futex_node)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
if (pos == thread_hd)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
return TRUE;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-27 21:47:05 +08:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex进队
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param flt
|
|
|
|
|
|
* @param th
|
|
|
|
|
|
*/
|
2023-11-27 21:47:05 +08:00
|
|
|
|
static void futex_enqueue(futex_lock_t *flt, thread_t *th)
|
|
|
|
|
|
{
|
|
|
|
|
|
slist_add_append(&flt->thread_list_head, &th->futex_node);
|
|
|
|
|
|
flt->cnt++;
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex出队
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param flt
|
|
|
|
|
|
* @param th
|
|
|
|
|
|
* @return int
|
|
|
|
|
|
*/
|
2023-11-27 21:47:05 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 获取futex的锁有多少个线程在等待
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param flt
|
|
|
|
|
|
* @return size_t
|
|
|
|
|
|
*/
|
2023-11-27 21:47:05 +08:00
|
|
|
|
static size_t futex_cnt(futex_lock_t *flt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return flt->cnt;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 查找一个地址,如果已经有了,则加入等待,否则增加一个信息,并加入等待
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param ft
|
|
|
|
|
|
* @param uaddr
|
|
|
|
|
|
* @param hd
|
|
|
|
|
|
* @return futex_lock_t*
|
|
|
|
|
|
*/
|
|
|
|
|
|
static futex_lock_t *futex_set_addr(futex_t *ft, void *uaddr, thread_t *hd)
|
|
|
|
|
|
{
|
|
|
|
|
|
int empty_inx = -1;
|
|
|
|
|
|
|
2023-12-05 00:01:26 +08:00
|
|
|
|
for (int i = 0; i < CONFIG_FT_ADDR_NR; i++)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (ft->fl_list[i].uaddr == uaddr)
|
|
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
if (!futex_find_thread(&ft->fl_list[i], hd))
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
futex_enqueue(&ft->fl_list[i], hd);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
return &ft->fl_list[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ft->fl_list[i].uaddr == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
empty_inx = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (empty_inx != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
ft->fl_list[empty_inx].uaddr = uaddr;
|
2023-11-27 21:47:05 +08:00
|
|
|
|
futex_enqueue(&ft->fl_list[empty_inx], hd);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
return &ft->fl_list[empty_inx];
|
|
|
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 找到指定地址的锁结构体
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param fst
|
|
|
|
|
|
* @param uaddr
|
|
|
|
|
|
* @return futex_lock_t*
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static futex_lock_t *futex_find(futex_t *fst, void *uaddr)
|
|
|
|
|
|
{
|
2023-12-05 00:01:26 +08:00
|
|
|
|
for (int i = 0; i < CONFIG_FT_ADDR_NR; i++)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (fst->fl_list[i].uaddr == uaddr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return &fst->fl_list[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
static int futex_wake(futex_t *fst, uint32_t *uaddr, int val)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
mword_t status;
|
|
|
|
|
|
int rel_cnt = 0;
|
|
|
|
|
|
uint32_t *paddr;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2023-11-27 21:47:05 +08:00
|
|
|
|
status = spinlock_lock(&fst->kobj.lock);
|
2024-07-31 23:27:19 +08:00
|
|
|
|
paddr = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (paddr == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
|
|
|
|
|
// printk("%s:%d uaddr: 0x%lx paddr: 0x%lx\n", __func__, __LINE__, uaddr, paddr);
|
|
|
|
|
|
futex_lock_t *flt = futex_find(fst, paddr);
|
|
|
|
|
|
|
|
|
|
|
|
if (flt)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
rel_cnt = val = INT_MAX ? futex_cnt(flt) : val;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < rel_cnt; i++)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_t *th;
|
|
|
|
|
|
int ret = futex_dequeue(flt, (&th));
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (ret == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (futex_cnt(flt) == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
flt->uaddr = 0;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_ready_remote(th, TRUE);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
|
|
|
|
|
|
return rel_cnt;
|
|
|
|
|
|
}
|
|
|
|
|
|
static int futex_wait(thread_t *cur_th, futex_t *fst, uint32_t *uaddr, int val, umword_t timeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
umword_t status;
|
|
|
|
|
|
uint32_t *p_addr;
|
|
|
|
|
|
|
|
|
|
|
|
status = spinlock_lock(&fst->kobj.lock);
|
|
|
|
|
|
if (!is_rw_access(thread_get_bind_task(cur_th), uaddr, sizeof(*uaddr), FALSE))
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
2024-07-31 23:27:19 +08:00
|
|
|
|
p_addr = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (p_addr == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
|
|
|
|
|
// printk("%s:%d uaddr: 0x%lx paddr: 0x%lx\n", __func__, __LINE__, uaddr, p_addr);
|
|
|
|
|
|
if (val == *p_addr) //!< 检查值是否时期望值
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
ref_counter_inc(&cur_th->ref); //!< 指定线程引用计数+1
|
|
|
|
|
|
if (futex_set_addr(fst, p_addr, cur_th) == NULL)
|
2023-11-20 16:17:58 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
|
2023-11-27 21:47:05 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return -ENOMEM;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
if (timeout != 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
//! 加入到等待队列中
|
|
|
|
|
|
futex_wait_item_t item = {
|
|
|
|
|
|
.th = cur_th,
|
|
|
|
|
|
.sleep_times = timeout,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
slist_init(&item.node);
|
|
|
|
|
|
slist_add_append((slist_head_t *)pre_cpu_get_current_cpu_var(&wait_list), &item.node);
|
|
|
|
|
|
thread_suspend(cur_th);
|
|
|
|
|
|
preemption();
|
|
|
|
|
|
if (item.sleep_times <= 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
// spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -ETIMEDOUT;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (cur_th->ipc_status == THREAD_IPC_ABORT)
|
2023-11-20 16:17:58 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
cur_th->ipc_status = THREAD_NONE;
|
|
|
|
|
|
// spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return 0;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
// 一直等待
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
|
|
|
|
|
|
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
else
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EAGAIN;
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
static int futex_wake_clear(thread_t *cur_th, futex_t *fst, uint32_t *uaddr, int val)
|
|
|
|
|
|
{
|
|
|
|
|
|
mword_t status;
|
|
|
|
|
|
uint32_t *paddr;
|
|
|
|
|
|
status = spinlock_lock(&fst->kobj.lock);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2024-07-31 23:27:19 +08:00
|
|
|
|
paddr = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (paddr == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!is_rw_access(thread_get_bind_task(cur_th), paddr, sizeof(*paddr), FALSE))
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
|
|
|
|
|
futex_lock_t *flt = futex_find(fst, paddr);
|
|
|
|
|
|
int rel_cnt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (flt)
|
|
|
|
|
|
{
|
|
|
|
|
|
rel_cnt = val = INT_MAX ? futex_cnt(flt) : val;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < rel_cnt; i++)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_t *th;
|
|
|
|
|
|
int ret = futex_dequeue(flt, (&th));
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (ret == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (futex_cnt(flt) == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
flt->uaddr = 0;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_ready_remote(th, TRUE);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
*paddr = 0;
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
static int futex_requeue(thread_t *cur_th, futex_t *fst,
|
|
|
|
|
|
uint32_t *uaddr, uint32_t *uaddr2, int val, int val3)
|
|
|
|
|
|
{
|
|
|
|
|
|
mword_t status;
|
|
|
|
|
|
uint32_t *paddr;
|
|
|
|
|
|
uint32_t *paddr2;
|
|
|
|
|
|
|
|
|
|
|
|
status = spinlock_lock(&fst->kobj.lock);
|
|
|
|
|
|
if (!is_rw_access(thread_get_bind_task(cur_th), uaddr, sizeof(*uaddr), FALSE))
|
|
|
|
|
|
{
|
2023-11-27 21:47:05 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return -EACCES;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-31 23:27:19 +08:00
|
|
|
|
paddr = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (paddr == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
2024-07-31 23:27:19 +08:00
|
|
|
|
paddr2 = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr2);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (paddr2 == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (val3 == *paddr)
|
|
|
|
|
|
{
|
|
|
|
|
|
futex_lock_t *flt = futex_find(fst, paddr);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
int rel_cnt = 0;
|
2024-07-30 09:37:49 +08:00
|
|
|
|
int wake_cnt = 0;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
|
|
|
|
|
if (flt)
|
|
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
wake_cnt = val = INT_MAX ? futex_cnt(flt) : val;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2024-07-30 09:37:49 +08:00
|
|
|
|
for (int i = 0; i < wake_cnt; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
thread_t *th;
|
|
|
|
|
|
int ret = futex_dequeue(flt, &th);
|
|
|
|
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (futex_cnt(flt) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
flt->uaddr = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
thread_ready_remote(th, TRUE);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (futex_cnt(flt) <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return wake_cnt;
|
|
|
|
|
|
}
|
|
|
|
|
|
int requeue_cn = futex_cnt(flt);
|
|
|
|
|
|
rel_cnt = requeue_cn;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
for (int i = 0; i < rel_cnt; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
thread_t *th;
|
2024-07-30 09:37:49 +08:00
|
|
|
|
int ret = futex_dequeue(flt, &th);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (ret != 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
continue;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (futex_cnt(flt) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
flt->uaddr = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
futex_set_addr(fst, (void *)paddr2, th);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-27 21:47:05 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return wake_cnt;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
static int futex_lock_pi(thread_t *cur_th, futex_t *fst, uint32_t *uaddr, uint32_t tid)
|
|
|
|
|
|
{
|
|
|
|
|
|
mword_t status;
|
|
|
|
|
|
uint32_t *paddr;
|
|
|
|
|
|
|
|
|
|
|
|
status = spinlock_lock(&fst->kobj.lock);
|
|
|
|
|
|
if (!is_rw_access(thread_get_bind_task(cur_th), uaddr, sizeof(*uaddr), FALSE))
|
|
|
|
|
|
{
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
2024-07-31 23:27:19 +08:00
|
|
|
|
paddr = (uint32_t *)task_get_currnt_paddr((vaddr_t)uaddr);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
if (paddr == 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return -EACCES;
|
|
|
|
|
|
}
|
2025-03-23 17:35:56 +08:00
|
|
|
|
if ((*paddr) == 0)
|
2024-07-30 09:37:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
*paddr = tid;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
*paddr |= FUTEX_WAITERS;
|
|
|
|
|
|
}
|
|
|
|
|
|
spinlock_set(&fst->kobj.lock, status);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex的处理函数
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param fst
|
|
|
|
|
|
* @param uaddr
|
|
|
|
|
|
* @param futex_op
|
|
|
|
|
|
* @param val
|
|
|
|
|
|
* @param timeout
|
|
|
|
|
|
* @param uaddr2
|
|
|
|
|
|
* @param val3
|
|
|
|
|
|
* @param tid
|
|
|
|
|
|
* @return int
|
|
|
|
|
|
*/
|
|
|
|
|
|
static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t val,
|
|
|
|
|
|
umword_t timeout /*val2*/, umword_t uaddr2, uint32_t val3, int tid)
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
thread_t *cur_th = thread_get_current();
|
|
|
|
|
|
umword_t status;
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
|
|
futex_op = futex_op & 0x7f;
|
|
|
|
|
|
|
|
|
|
|
|
switch (futex_op)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FUTEX_REQUEUE:
|
|
|
|
|
|
{
|
|
|
|
|
|
ret = futex_requeue(cur_th, fst, uaddr, (void *)uaddr2, val, val3);
|
|
|
|
|
|
if (ret < 0)
|
2023-11-20 16:17:58 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return ret;
|
2023-11-20 16:17:58 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case FUTEX_WAIT:
|
|
|
|
|
|
{
|
|
|
|
|
|
// printk("futex wait:0x%lx\n", uaddr);
|
|
|
|
|
|
ret = futex_wait(cur_th, fst, uaddr, val, timeout);
|
|
|
|
|
|
if (ret < 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return ret;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case FUTEX_WAKE:
|
|
|
|
|
|
{
|
|
|
|
|
|
int rel_cnt;
|
|
|
|
|
|
// printk("futex wake:0x%lx\n", uaddr);
|
|
|
|
|
|
rel_cnt = futex_wake(fst, uaddr, val);
|
|
|
|
|
|
return rel_cnt;
|
|
|
|
|
|
}
|
|
|
|
|
|
case FUTEX_UNLOCK_PI:
|
|
|
|
|
|
case FUTEX_WAKE_CLEAR:
|
|
|
|
|
|
{
|
|
|
|
|
|
int rel_cnt;
|
|
|
|
|
|
|
|
|
|
|
|
rel_cnt = futex_wake_clear(cur_th, fst, uaddr, val);
|
|
|
|
|
|
return rel_cnt;
|
|
|
|
|
|
}
|
|
|
|
|
|
case FUTEX_LOCK_PI:
|
|
|
|
|
|
{
|
|
|
|
|
|
ret = futex_lock_pi(cur_th, fst, uaddr, tid);
|
|
|
|
|
|
if (ret < 0)
|
2023-11-19 23:01:35 +08:00
|
|
|
|
{
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return ret;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
return -ENOSYS;
|
|
|
|
|
|
}
|
2024-07-30 09:37:49 +08:00
|
|
|
|
return ret;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief futex的系统调用
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param kobj
|
|
|
|
|
|
* @param sys_p
|
|
|
|
|
|
* @param in_tag
|
|
|
|
|
|
* @param f
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static void futex_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);
|
|
|
|
|
|
thread_t *th = thread_get_current();
|
|
|
|
|
|
futex_t *futex = container_of(kobj, futex_t, kobj);
|
|
|
|
|
|
ipc_msg_t *msg;
|
|
|
|
|
|
|
|
|
|
|
|
if (sys_p.prot != FUTEX_PROT)
|
|
|
|
|
|
{
|
2024-04-04 16:51:29 +00:00
|
|
|
|
f->regs[0] = msg_tag_init4(0, 0, 0, -EPROTO).raw;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
msg = thread_get_msg_buf(th);
|
|
|
|
|
|
if (msg == NULL)
|
|
|
|
|
|
{
|
2024-04-04 16:51:29 +00:00
|
|
|
|
f->regs[0] = msg_tag_init4(0, 0, 0, -ENOBUFS).raw;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (sys_p.op)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FUTEX_CTRL:
|
|
|
|
|
|
{
|
|
|
|
|
|
int ret;
|
2024-07-30 09:37:49 +08:00
|
|
|
|
umword_t *msg_buf = thread_get_kmsg_buf(th);
|
|
|
|
|
|
uint32_t *uaddr = (uint32_t *)(msg_buf[0]);
|
|
|
|
|
|
int futex_op = msg_buf[1];
|
|
|
|
|
|
uint32_t val = msg_buf[2];
|
|
|
|
|
|
umword_t timeout = msg_buf[3];
|
|
|
|
|
|
uint32_t uaddr2 = msg_buf[4];
|
|
|
|
|
|
uint32_t val3 = msg_buf[5];
|
|
|
|
|
|
int tid = msg_buf[6];
|
|
|
|
|
|
mword_t lock_status = cpulock_lock();
|
2023-11-19 23:01:35 +08:00
|
|
|
|
|
|
|
|
|
|
ret = futex_dispose(futex, uaddr, futex_op, val, timeout, uaddr2, val3, tid);
|
2024-07-30 09:37:49 +08:00
|
|
|
|
cpulock_set(lock_status);
|
2024-01-20 21:20:45 +08:00
|
|
|
|
tag = msg_tag_init4(0, 0, 0, ret);
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2024-04-04 16:51:29 +00:00
|
|
|
|
f->regs[0] = tag.raw;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 在task结束时,需要删除某个task所关联的futex
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param obj_space 需要操作的task的obj_space
|
|
|
|
|
|
* @param kobj 哪一个futex对象
|
|
|
|
|
|
*/
|
2023-11-27 21:47:05 +08:00
|
|
|
|
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);
|
2023-12-05 00:01:26 +08:00
|
|
|
|
for (int i = 0; i < CONFIG_FT_ADDR_NR; i++)
|
2023-11-27 21:47:05 +08:00
|
|
|
|
{
|
|
|
|
|
|
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);
|
2025-03-17 00:35:42 +08:00
|
|
|
|
pos->status = THREAD_IPC_ABORT;
|
2024-07-30 09:37:49 +08:00
|
|
|
|
thread_ready_remote(pos, TRUE);
|
2023-11-27 21:47:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
pos = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
spinlock_set(&futex->kobj.lock, status);
|
|
|
|
|
|
}
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static void futex_release_stage1(kobject_t *kobj)
|
|
|
|
|
|
{
|
2023-11-27 22:25:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
static bool_t futex_release_put(kobject_t *kobj)
|
|
|
|
|
|
{
|
|
|
|
|
|
return FALSE;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
static void futex_release_stage2(kobject_t *kobj)
|
|
|
|
|
|
{
|
|
|
|
|
|
printk("futex don't release.\n");
|
|
|
|
|
|
}
|
2023-12-05 21:16:00 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 初始化futex对象
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param ft
|
|
|
|
|
|
*/
|
2023-11-19 23:01:35 +08:00
|
|
|
|
static void futex_init(futex_t *ft)
|
|
|
|
|
|
{
|
2023-11-26 00:15:32 +08:00
|
|
|
|
kobject_init(&ft->kobj, FUTEX_TYPE);
|
2023-12-05 00:01:26 +08:00
|
|
|
|
for (int i = 0; i < CONFIG_FT_ADDR_NR; i++)
|
2023-11-27 21:47:05 +08:00
|
|
|
|
{
|
|
|
|
|
|
slist_init(&ft->fl_list[i].thread_list_head);
|
|
|
|
|
|
}
|
2023-11-19 23:01:35 +08:00
|
|
|
|
ft->kobj.invoke_func = futex_syscall;
|
2023-11-27 21:47:05 +08:00
|
|
|
|
ft->kobj.unmap_func = futex_unmap;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
ft->kobj.stage_1_func = futex_release_stage1;
|
|
|
|
|
|
ft->kobj.stage_2_func = futex_release_stage2;
|
2023-11-27 22:25:21 +08:00
|
|
|
|
ft->kobj.put_func = futex_release_put;
|
2023-11-19 23:01:35 +08:00
|
|
|
|
}
|