#include #include #include #include #include #include #include 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); }