bond/kernel/rf/ref.c

303 lines
7.1 KiB
C
Raw Normal View History

2018-01-26 08:43:22 +00:00
#include "kernel/rf/ref.h"
#include "kernel/ke/alloc.h"
#include "kernel/ke/spin_lock.h"
#include "kernel/ke/assert.h"
#include "kernel/ke/atomic.h"
#include "lib/avl_tree.h"
2016-07-24 00:54:54 +00:00
2016-08-06 05:55:55 +00:00
typedef struct
{
2017-02-01 03:26:08 +00:00
avl_tree_node_t tree_node;
handle_t handle;
ref_node_t *ref;
callback_func_t free_routine;
} handle_node_t;
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
static int32_t rfp_handle_node_free(void *node, void *up)
2016-08-28 00:20:38 +00:00
{
2017-02-01 03:26:08 +00:00
UNREFERENCED(up);
2016-08-28 09:14:22 +00:00
ke_free(node);
return 0;
2016-08-28 00:20:38 +00:00
}
// ===========================
// Ke Functions
// ===========================
2017-02-01 03:26:08 +00:00
static avl_tree_t handle_tree;
static bool initialized;
static k_spin_lock_t handle_tree_lock;
static int32_t handle_base;
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
static int32_t rfp_handle_compare(void *tree_node, void *my_node)
2016-08-28 00:20:38 +00:00
{
2017-02-01 03:26:08 +00:00
handle_node_t *tcb = OBTAIN_STRUCT_ADDR(tree_node, handle_node_t, tree_node);
handle_node_t *my_tcb = OBTAIN_STRUCT_ADDR(my_node, handle_node_t, tree_node);
2016-08-28 00:20:38 +00:00
if ((uintptr_t) tcb->handle > (uintptr_t) my_tcb->handle)
2016-08-06 05:55:55 +00:00
return -1;
2016-08-28 00:20:38 +00:00
else if ((uintptr_t) tcb->handle == (uintptr_t) my_tcb->handle)
2016-08-06 05:55:55 +00:00
return 0;
2016-08-28 00:20:38 +00:00
else
return 1;
2016-08-06 05:55:55 +00:00
}
2017-02-01 03:26:08 +00:00
static handle_node_t *rfp_search_handle_node(handle_t handle)
2016-08-06 05:55:55 +00:00
{
2017-02-01 03:26:08 +00:00
avl_tree_node_t *result;
handle_node_t temp;
2016-08-28 00:20:38 +00:00
temp.handle = handle;
2017-02-01 03:26:08 +00:00
result = lb_avl_tree_search(&handle_tree, &temp.tree_node);
return result == NULL ? NULL : OBTAIN_STRUCT_ADDR(result, handle_node_t, tree_node);
2016-08-28 00:20:38 +00:00
}
2016-08-06 05:55:55 +00:00
status_t KABI rf_reference_setup(void)
2016-08-28 00:20:38 +00:00
{
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
{
2017-02-01 03:26:08 +00:00
lb_avl_tree_init(&handle_tree, rfp_handle_compare);
ke_spin_lock_init(&handle_tree_lock);
handle_base = K_HANDLE_BASE;
initialized = true;
2016-08-28 00:20:38 +00:00
}
return STATUS_SUCCESS;
2016-08-06 05:55:55 +00:00
}
2017-02-01 03:26:08 +00:00
status_t KABI rf_reference_create(ref_node_t *ref,
callback_func_t free_func)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
if (ref == NULL || free_func == NULL)
return REF_STATUS_INVALID_ARGUMENTS;
2016-08-06 05:55:55 +00:00
2016-08-28 09:14:22 +00:00
ref->free_routine = free_func;
2016-08-28 00:20:38 +00:00
ref->ref_count = 1;
2016-08-06 05:55:55 +00:00
2016-08-28 00:20:38 +00:00
return STATUS_SUCCESS;
}
2017-02-01 03:26:08 +00:00
status_t KABI rf_reference_obj(ref_node_t *ref_node)
2016-08-06 05:55:55 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
if (ref_node == NULL)
return REF_STATUS_INVALID_ARGUMENTS;
2016-09-13 04:41:09 +00:00
int32_t old_ref_count = ke_interlocked_increment_32(&ref_node->ref_count, 1);
2016-08-28 00:20:38 +00:00
2016-08-28 09:14:22 +00:00
ke_assert(old_ref_count >= 1);
2016-08-28 00:20:38 +00:00
return STATUS_SUCCESS;
2016-08-06 05:55:55 +00:00
}
2017-02-01 03:26:08 +00:00
status_t KABI rf_dereference_obj(ref_node_t *ref_node)
2016-08-06 05:55:55 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
if (ref_node == NULL)
return REF_STATUS_INVALID_ARGUMENTS;
2017-02-01 03:26:08 +00:00
status_t result = STATUS_SUCCESS;
2016-08-28 00:20:38 +00:00
2016-09-13 04:41:09 +00:00
int32_t old_ref_count = ke_interlocked_increment_32(&ref_node->ref_count, -1);
2016-08-28 00:20:38 +00:00
2016-08-28 09:14:22 +00:00
ke_assert(old_ref_count >= 1);
2016-08-28 00:20:38 +00:00
if (old_ref_count == 1)
{
2016-08-28 09:14:22 +00:00
ref_node->free_routine(ref_node, NULL);
2016-08-28 00:20:38 +00:00
}
return result;
}
2017-02-01 03:26:08 +00:00
static status_t KABI rf_open_obj_by_handle(handle_t handle, ref_node_t **out)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
{
return REF_STATUS_UNINITIALIZED;
}
if (out == NULL)
{
return REF_STATUS_INVALID_ARGUMENTS;
}
2017-02-01 03:26:08 +00:00
irql_t irql;
status_t status = STATUS_SUCCESS;
ref_node_t *ref = NULL;
2016-08-28 00:20:38 +00:00
2018-01-26 08:43:22 +00:00
irql = ke_spin_lock_raise_irql(&handle_tree_lock, IRQL_DPC_LEVEL);
2017-02-01 03:26:08 +00:00
handle_node_t *handle_node = rfp_search_handle_node(handle);
2016-08-28 00:20:38 +00:00
if (handle_node == NULL)
{
2016-08-28 09:14:22 +00:00
status = REF_STATUS_INVALID_HANDLE;
} else
2016-08-28 00:20:38 +00:00
{
ref = handle_node->ref;
}
// PREREQUISITE: Having a handle -> having a reference
// MUST GUARANTEE that handle exists while we reference
2016-08-28 09:14:22 +00:00
if (SX_SUCCESS(status))
2016-08-28 00:20:38 +00:00
{
// reference the object then return the reference
2017-02-01 03:26:08 +00:00
rf_reference_obj(ref);
2016-08-28 09:14:22 +00:00
*out = ref;
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
ke_spin_unlock_lower_irql(&handle_tree_lock, irql);
2016-08-28 00:20:38 +00:00
2016-08-28 09:14:22 +00:00
return status;
2016-08-06 05:55:55 +00:00
}
2017-02-01 03:26:08 +00:00
static status_t KABI rf_create_handle(ref_node_t *ref,
handle_node_t *node,
handle_t *out)
2016-08-06 05:55:55 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
return REF_STATUS_UNINITIALIZED;
if (ref == NULL || node == NULL || out == NULL)
return REF_STATUS_INVALID_ARGUMENTS;
2017-02-01 03:26:08 +00:00
status_t result = STATUS_SUCCESS;
irql_t irql;
2016-08-28 00:20:38 +00:00
2016-08-28 09:14:22 +00:00
if (SX_SUCCESS(result))
2016-08-28 00:20:38 +00:00
{
// TODO: CHECK OVERFLOW
2017-02-01 03:26:08 +00:00
node->handle = (handle_t) ke_interlocked_increment_32(&handle_base, 1);
2016-08-28 00:20:38 +00:00
node->ref = ref;
2018-01-26 08:43:22 +00:00
irql = ke_spin_lock_raise_irql(&handle_tree_lock, IRQL_DPC_LEVEL);
2017-02-01 03:26:08 +00:00
handle_node_t *existing_node = rfp_search_handle_node(node->handle);
2016-08-28 00:20:38 +00:00
if (existing_node == NULL)
{
2017-02-01 03:26:08 +00:00
lb_avl_tree_insert(&handle_tree, &node->tree_node);
2016-08-28 09:14:22 +00:00
} else
2016-08-28 00:20:38 +00:00
{
2016-08-28 09:14:22 +00:00
result = REF_STATUS_DUPLICATED_HANDLE;
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
ke_spin_unlock_lower_irql(&handle_tree_lock, irql);
2016-08-28 00:20:38 +00:00
}
2016-08-28 09:14:22 +00:00
if (SX_SUCCESS(result))
2016-08-28 00:20:38 +00:00
{
2017-02-01 03:26:08 +00:00
rf_reference_obj(ref);
2016-08-28 00:20:38 +00:00
*out = node->handle;
2016-08-28 09:14:22 +00:00
} else
2016-08-28 00:20:38 +00:00
{
2016-08-28 09:14:22 +00:00
node->free_routine(node, NULL);
2016-08-28 00:20:38 +00:00
}
return result;
}
2017-02-01 03:26:08 +00:00
static status_t KABI rf_close_handle(handle_t handle)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
return REF_STATUS_UNINITIALIZED;
2017-02-01 03:26:08 +00:00
irql_t irql;
status_t status = STATUS_SUCCESS;
ref_node_t *ref = NULL;
2016-08-28 09:14:22 +00:00
bool free = false;
2016-08-28 00:20:38 +00:00
2018-01-26 08:43:22 +00:00
irql = ke_spin_lock_raise_irql(&handle_tree_lock, IRQL_DPC_LEVEL);
2017-02-01 03:26:08 +00:00
handle_node_t *handle_node = rfp_search_handle_node(handle);
2016-08-28 00:20:38 +00:00
if (handle_node == NULL)
{
2016-08-28 09:14:22 +00:00
status = REF_STATUS_INVALID_HANDLE;
} else
2016-08-28 00:20:38 +00:00
{
ref = handle_node->ref;
2017-02-01 03:26:08 +00:00
lb_avl_tree_delete(&handle_tree, &handle_node->tree_node);
2016-08-28 09:14:22 +00:00
free = true;
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
ke_spin_unlock_lower_irql(&handle_tree_lock, irql);
2016-08-28 00:20:38 +00:00
2016-08-28 09:14:22 +00:00
if (free)
{
handle_node->free_routine(handle_node, NULL);
}
if (SX_SUCCESS(status))
2016-08-28 00:20:38 +00:00
{
// dereference the object
2017-02-01 03:26:08 +00:00
rf_dereference_obj(ref);
2016-08-28 00:20:38 +00:00
}
2016-08-28 09:14:22 +00:00
return status;
2016-08-28 00:20:38 +00:00
}
// ===========================
2017-02-01 03:26:08 +00:00
// SX Functions
2016-08-28 00:20:38 +00:00
// ===========================
2017-02-01 03:26:08 +00:00
status_t KABI sx_create_handle(ref_node_t *ref, handle_t *out)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
return REF_STATUS_UNINITIALIZED;
2017-02-01 03:26:08 +00:00
handle_node_t *node;
node = (handle_node_t *) ke_alloc(sizeof(handle_node_t));
2016-08-28 00:20:38 +00:00
if (node == NULL)
{
2016-08-28 09:14:22 +00:00
return REF_STATUS_ALLOCATION_FAILED;
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
node->free_routine = rfp_handle_node_free;
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
return rf_create_handle(ref, node, out);
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
status_t KABI sx_close_handle(handle_t handle)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
return REF_STATUS_UNINITIALIZED;
2016-08-28 09:14:22 +00:00
// need to keep sx version since need to do handle check here
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
return rf_close_handle(handle);
2016-08-28 00:20:38 +00:00
}
2017-02-01 03:26:08 +00:00
status_t KABI sx_open_obj_by_handle(handle_t handle, ref_node_t **out)
2016-08-28 00:20:38 +00:00
{
2018-01-26 08:43:22 +00:00
ke_assert(ke_get_irql() <= IRQL_DPC_LEVEL);
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
if (!initialized)
2016-08-28 00:20:38 +00:00
return REF_STATUS_UNINITIALIZED;
if (out == NULL)
return REF_STATUS_INVALID_ARGUMENTS;
// check special handles first
2016-08-28 09:14:22 +00:00
// if (handle == K_HANDLE_CURRENT_THREAD)
// {
// // no need to ref first since definitely current thread context
// hw_tcb_t *tcb = ke_current_thread();
// ke_reference_obj(&tcb->ref_node);
// *out = &tcb->ref_node;
// return STATUS_SUCCESS;
// }
2016-08-28 00:20:38 +00:00
2017-02-01 03:26:08 +00:00
return rf_open_obj_by_handle(handle, out);
2016-08-06 05:55:55 +00:00
}