122 lines
3.6 KiB
C
122 lines
3.6 KiB
C
#include <zinnia/handle.h>
|
|
#include <zinnia/rights.h>
|
|
#include <zinnia/status.h>
|
|
#include <kernel/alloc.h>
|
|
#include <kernel/mutex.h>
|
|
#include <kernel/namespace.h>
|
|
#include <stdatomic.h>
|
|
|
|
zn_status_t namespace_new(struct namespace** out) {
|
|
if (!out)
|
|
return ZN_ERR_INTERNAL;
|
|
|
|
struct namespace* namespace = mem_alloc(sizeof(struct namespace), 0);
|
|
if (!namespace)
|
|
return ZN_ERR_NO_MEMORY;
|
|
|
|
namespace->mutex = (struct mutex){0};
|
|
namespace->next_handle = 1;
|
|
hashmap_init(&namespace->descriptors);
|
|
|
|
*out = namespace;
|
|
return ZN_OK;
|
|
}
|
|
|
|
zn_status_t namespace_add_desc(struct namespace* namespace, struct namespace_desc desc, zn_handle_t* out) {
|
|
if (!namespace)
|
|
return ZN_ERR_INTERNAL;
|
|
|
|
// Skip over handles that are already in use (e.g. hard-coded handles).
|
|
// mutex_lock(&namespace->mutex);
|
|
zn_handle_t handle;
|
|
do {
|
|
handle = atomic_fetch_add_explicit(&namespace->next_handle, 1, memory_order_acq_rel);
|
|
if (handle <= ZN_HANDLE_INVALID)
|
|
continue;
|
|
} while (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr);
|
|
|
|
zn_status_t status =
|
|
hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
|
|
// mutex_unlock(&namespace->mutex);
|
|
|
|
if (status != ZN_OK)
|
|
return status;
|
|
|
|
*out = handle;
|
|
return ZN_OK;
|
|
}
|
|
|
|
zn_status_t namespace_add_desc_at(struct namespace* namespace, struct namespace_desc desc, zn_handle_t handle) {
|
|
if (!namespace)
|
|
return ZN_ERR_INTERNAL;
|
|
|
|
// Skip Invalid or reserved handles.
|
|
if (handle <= ZN_HANDLE_INVALID)
|
|
return ZN_ERR_BAD_HANDLE;
|
|
|
|
// Fail if a descriptor already exists at this handle.
|
|
if (hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default) != nullptr)
|
|
return ZN_ERR_ALREADY_EXISTS;
|
|
|
|
return hashmap_insert(&namespace->descriptors, handle, desc, hashmap_hash_default, hashmap_eq_default);
|
|
}
|
|
|
|
zn_status_t namespace_get(struct namespace* namespace, zn_handle_t handle, struct namespace_desc* out) {
|
|
if (!namespace)
|
|
return ZN_ERR_INTERNAL;
|
|
if (!out)
|
|
return ZN_ERR_INTERNAL;
|
|
|
|
if (handle <= ZN_HANDLE_INVALID)
|
|
return ZN_ERR_BAD_HANDLE;
|
|
|
|
struct namespace_desc* desc =
|
|
hashmap_get(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default);
|
|
if (!desc)
|
|
return ZN_ERR_BAD_HANDLE;
|
|
|
|
*out = *desc;
|
|
return ZN_OK;
|
|
}
|
|
|
|
zn_status_t namespace_del_desc(struct namespace* namespace, zn_handle_t handle) {
|
|
if (!namespace)
|
|
return ZN_ERR_INTERNAL;
|
|
|
|
if (handle <= ZN_HANDLE_INVALID)
|
|
return ZN_ERR_BAD_HANDLE;
|
|
|
|
if (!hashmap_remove(&namespace->descriptors, handle, hashmap_hash_default, hashmap_eq_default))
|
|
return ZN_ERR_BAD_HANDLE;
|
|
|
|
return ZN_OK;
|
|
}
|
|
|
|
zn_status_t namespace_clone_desc(
|
|
struct namespace* ns,
|
|
struct namespace_desc* desc,
|
|
zn_rights_t cloned_rights,
|
|
zn_handle_t* out
|
|
) {
|
|
// The source handle must have the clone right.
|
|
if (!(desc->rights & ZN_RIGHT_CLONE))
|
|
return ZN_ERR_BAD_PERMS;
|
|
|
|
// Determine the rights for the cloned handle.
|
|
zn_rights_t new_rights;
|
|
if (cloned_rights & ZN_RIGHTS_IDENTICAL) {
|
|
new_rights = desc->rights;
|
|
} else {
|
|
// The requested rights must be a subset of the original rights.
|
|
if (cloned_rights & ~desc->rights)
|
|
return ZN_ERR_BAD_PERMS;
|
|
new_rights = cloned_rights;
|
|
}
|
|
|
|
// Create the cloned descriptor.
|
|
struct namespace_desc new_desc = *desc;
|
|
new_desc.rights = new_rights;
|
|
|
|
return namespace_add_desc(ns, new_desc, out);
|
|
}
|