240 lines
4.6 KiB
C
240 lines
4.6 KiB
C
#include "rf/ref.h"
|
|
#include "ke/assert.h"
|
|
#include "ke/spin_lock.h"
|
|
#include "ke/atomic.h"
|
|
#include "ke/intr.h"
|
|
#include "clib.h"
|
|
|
|
#define K_IDENT_BASE (0x80000000ul)
|
|
|
|
static struct a_tree ident_tree;
|
|
static struct spin_lock ident_tree_lock;
|
|
static uint32 ident_base;
|
|
|
|
|
|
static int32
|
|
handle_compare(struct atree_node *tree_node, struct atree_node *my_node)
|
|
{
|
|
struct ident_node *tcb = OBTAIN_STRUCT_ADDR(tree_node, struct ident_node, tree_node);
|
|
struct ident_node *my_tcb = OBTAIN_STRUCT_ADDR(my_node, struct ident_node, tree_node);
|
|
|
|
if ((uintptr) tcb->ident > (uintptr) my_tcb->ident)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if ((uintptr) tcb->ident == (uintptr) my_tcb->ident)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static struct ident_node *
|
|
search_handle_node(k_ident ident)
|
|
{
|
|
struct atree_node *result;
|
|
struct ident_node temp;
|
|
temp.ident = ident;
|
|
result = lb_atree_search(&ident_tree, &temp.tree_node);
|
|
return result == NULL ? NULL : OBTAIN_STRUCT_ADDR(result, struct ident_node, tree_node);
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_ref_init(void)
|
|
{
|
|
lb_atree_init(&ident_tree, handle_compare);
|
|
ke_spin_init(&ident_tree_lock);
|
|
ident_base = K_IDENT_BASE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_ref_node_init(struct ref_node *rf_node, ref_free_fp free_func)
|
|
{
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
rf_node->f_free = free_func;
|
|
rf_node->ref_count = 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_ref_obj(struct ref_node *ref_node)
|
|
{
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
if (ref_node == NULL)
|
|
{
|
|
return STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
int32 old_ref_count = ke_atomic_inc_32(&ref_node->ref_count, 1);
|
|
|
|
KE_ASSERT(old_ref_count >= 1);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_deref_obj(struct ref_node *rf_node)
|
|
{
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
if (rf_node == NULL)
|
|
{
|
|
return STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
k_status result = STATUS_SUCCESS;
|
|
|
|
int32 old_ref_count = ke_atomic_inc_32(&rf_node->ref_count, -1);
|
|
|
|
KE_ASSERT(old_ref_count >= 1);
|
|
|
|
if (old_ref_count == 1)
|
|
{
|
|
rf_node->f_free(rf_node);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_open_obj_by_ident(k_ident id, struct ref_node **out)
|
|
{
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
uint32 irql;
|
|
k_status status = STATUS_SUCCESS;
|
|
struct ref_node *ref = NULL;
|
|
|
|
irql = ke_raise_irql(IRQL_DPC);
|
|
ke_spin_lock(&ident_tree_lock);
|
|
struct ident_node *ident_node = search_handle_node(id);
|
|
if (ident_node == NULL)
|
|
{
|
|
status = STATUS_INVALID_ARGS;
|
|
}
|
|
else
|
|
{
|
|
ref = ident_node->obj;
|
|
}
|
|
|
|
// PREREQUISITE: Having a handle -> having a reference
|
|
// MUST GUARANTEE that handle exists while we reference
|
|
if (SX_SUCCESS(status))
|
|
{
|
|
// reference the object then return the reference
|
|
rf_ref_obj(ref);
|
|
*out = ref;
|
|
}
|
|
|
|
ke_spin_unlock(&ident_tree_lock);
|
|
ke_lower_irql(irql);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_ident_create(struct ref_node *rf_node, struct ident_node *id_node, k_ident *out)
|
|
{
|
|
k_status result;
|
|
uint32 irql;
|
|
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
result = STATUS_SUCCESS;
|
|
|
|
// TODO: CHECK OVERFLOW
|
|
id_node->ident = (k_ident) ke_atomic_inc_32((int32 *) &ident_base, 1);
|
|
id_node->obj = rf_node;
|
|
|
|
irql = ke_raise_irql(IRQL_DPC);
|
|
ke_spin_lock(&ident_tree_lock);
|
|
|
|
struct ident_node *existing_node = search_handle_node(id_node->ident);
|
|
if (existing_node == NULL)
|
|
{
|
|
lb_atree_insert(&ident_tree, &id_node->tree_node);
|
|
}
|
|
else
|
|
{
|
|
/**
|
|
* Shouldn't get to here
|
|
*/
|
|
result = STATUS_DUPLICATE;
|
|
}
|
|
|
|
ke_spin_unlock(&ident_tree_lock);
|
|
ke_lower_irql(irql);
|
|
|
|
|
|
if (SX_SUCCESS(result))
|
|
{
|
|
rf_ref_obj(rf_node);
|
|
*out = id_node->ident;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
k_status
|
|
rf_ident_close(k_ident id)
|
|
{
|
|
uint32 irql;
|
|
k_status status;
|
|
struct ref_node *ref;
|
|
|
|
KE_ASSERT(ke_get_irql() <= IRQL_DPC);
|
|
|
|
status = STATUS_SUCCESS;
|
|
ref = NULL;
|
|
|
|
irql = ke_raise_irql(IRQL_DPC);
|
|
ke_spin_lock(&ident_tree_lock);
|
|
|
|
struct ident_node *id_node = search_handle_node(id);
|
|
if (id_node == NULL)
|
|
{
|
|
status = STATUS_INVALID_ARGS;
|
|
}
|
|
else
|
|
{
|
|
ref = id_node->obj;
|
|
lb_atree_delete(&ident_tree, &id_node->tree_node);
|
|
}
|
|
|
|
ke_spin_unlock(&ident_tree_lock);
|
|
ke_lower_irql(irql);
|
|
|
|
if (SX_SUCCESS(status))
|
|
{
|
|
/**
|
|
* Success means already freed
|
|
*/
|
|
id_node->free_routine(id_node);
|
|
/**
|
|
* Dereference the object
|
|
*/
|
|
rf_deref_obj(ref);
|
|
}
|
|
|
|
return status;
|
|
}
|