Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
namespaces.c
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <lxsameer@lxsameer.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
19
20#include "serene/rt/context.h"
21#include "serene/rt/core.h"
22#include "serene/rt/engine.h"
23#include "serene/rt/errors.h"
25#include "serene/rt/strings.h"
26#include "serene/rt/symbols.h"
27#include "serene/utils.h"
28
31 PANIC_IF_NULL(engine);
32 PANIC_IF_NULL(name);
33 // TODO(lxsameer): Return these panics as errors. This is fine for now!
34 UNUSED(err);
35 PANIC_IF(srn_string_is_empty(name), "Empty namespace name is not allowed");
38 "Namespace name exceeds the length limit"
39 );
40 srn_context_t *parent_ctx = engine->root_context;
41
42 // The key is the raw bytes of the namespace name (no struct header,
43 // no null terminator). The map copies the key into its pinned context, so
44 // a stack struct is enough here. Find by C string must use the same byte
45 // range as the key.
46 hmap_key_t k = {.data = (void *)name->buffer, .len = srn_string_length(name)};
47
48 // Readers never take `ns_lock`. Every published head is immutable, so an
49 // acquire load is enough to see a fully built map.
50 auto namespaces = atomic_load_explicit(&engine->namespaces, memory_order_acquire);
51 auto ns_ptr = srn_context_find_namespace(parent_ctx, (const char *)name->buffer);
52
53 if (ns_ptr != nullptr) {
54 // A namespace with the same name is already registered.
55 return (srn_namespace_t *)ns_ptr;
56 }
57
58 srn_namespace_t *ns = nullptr;
59
60 // Writers are serialized by `ns_lock`. Creating and publishing the
61 // namespace both happen while it is held.
62 WITH_LOCK(engine->ns_lock, {
63 // Another fiber may have registered the same name between the unlocked
64 // lookup and taking the lock, so the lookup is repeated here.
65 namespaces = atomic_load_explicit(&engine->namespaces, memory_order_relaxed);
66 ns = hmap_lookup(namespaces, &k, nullptr);
67
68 if (ns == nullptr) {
69 ns = ALLOC_OR_PANIC(parent_ctx, srn_namespace_t);
70 ns->name = srn_string_copy(parent_ctx, name);
71 ns->id = srn_allocate_object_id(engine);
72 ns->root_context = srn_context_make(engine);
73
74 // The symbol table outlives the creating context, so it is pinned to the
75 // namespace's own root context; the table's keys and trie nodes land in
76 // that chain rather than in the creating caller's block. The namespace
77 // is not visible to anyone yet, so the atomic is initialized rather
78 // than stored.
79 hmap_t *sym_table = ALLOC_OR_PANIC(ns->root_context, hmap_t);
80 *sym_table = hmap_empty(ns->root_context);
81 atomic_init(&ns->sym_table, sym_table);
82 // No node to begin with
83 ns->node = nullptr;
84
85 ns->sym_table_lock = ALLOC_OR_PANIC(ns->root_context, srn_fiber_mutex_t);
86 srn_fiber_mutex_init(ns->sym_table_lock);
87
88 // Every head is immutable once published, so the new version gets its
89 // own allocation and the old one stays valid for readers that already
90 // loaded it.
91 hmap_t *next = ALLOC_OR_PANIC(parent_ctx, hmap_t);
92 *next = hmap_insert(namespaces, &k, ns);
93
94 atomic_store_explicit(&engine->namespaces, next, memory_order_release);
95 }
96 });
97
98 return ns;
99}
100
102 PANIC_IF_NULL(ns);
103 return nullptr;
104}
Error handling for the runtime.
This is an implementation of Compressed Hash-Array Mapped Prefix-tree, which is a bit-partitioned,...
#define WITH_LOCK(lock, body)
Run body with lock held.
Definition mutex.h:84
srn_namespace_t * srn_namespace_load(srn_namespace_t *ns)
Load the namespace's source from the filesystem into src_buffer, parse it, and populate the symbol ta...
Definition namespaces.c:101
srn_namespace_t * srn_namespace_get_or_create(srn_engine_t *engine, srn_string_t *name, srn_error_t **err)
Create a new and empty namespace if it is not already created in the engine, if it exists,...
Definition namespaces.c:30
A namespace is an isolation for names nad technically a compilation unit.
size_t srn_string_length(const srn_string_t *s)
Definition strings.c:34
bool srn_string_is_empty(const srn_string_t *s)
Definition strings.c:49
Note: For key equality we use the memcpy function.
Definition hashmap.h:66
srn_limits_config_t limits
Engine is a structure to own the long living and main pieces of the compiler.
Definition engine.h:54
srn_configuration_t config
The runtime's tunable knobs, the single source for every configurable value (see configuration....
Definition engine.h:65
A runtime error, a tag classifying the failure and a human-readable message.
Definition errors.h:173
size_t ns_name_max_len
Longest namespace name accepted, in bytes.
uint8_t buffer[]
The buffer that holds the WTF8 sequence.
Definition strings.h:66
#define PANIC_IF_NULL(ptr)
Definition utils.h:66
#define PANIC_IF(cond, msg)
Definition utils.h:59
#define UNUSED(x)
Definition utils.h:45