Files
zinnia/kernel/core/namespace.c
T
2026-08-11 17:48:20 +02:00

116 lines
3.5 KiB
C

#include <zinnia/handle.h>
#include <zinnia/rights.h>
#include <zinnia/status.h>
#include <kernel/alloc.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).
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);
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;
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);
}