121 auto init(kobject::kobject_type type)
noexcept ->
void {
123 install_bobject_finalizer(object_core::finalize_last_put);
127 for (u32 i = 0; i < N; ++i) {
128 if (!ensure_slot_block(i / BLOCK_SIZE))
return;
129 next_ptr(i) = (i + 1 < N) ? (i + 1) : ~0U;
133 m_count.store(0, memory_order::relaxed);
134 m_initialized =
true;
140 [[nodiscard]]
auto alloc(kobject::kobject_type requested_type = kobject::kobject_type::none)
noexcept
141 -> std::expected<kobject::robject<T, lifecycle_state::embryo>, lib::kernel_error>
143 if (!m_initialized) [[unlikely]]
144 return std::unexpected(
145 lib::kernel_error::from_generic(lib::generic_error::uninitialized));
147 const sync::irq_lock_guard guard{m_table_lock};
149 if (m_free_head == ~0U)
150 return std::unexpected(
151 lib::kernel_error::from_memory(lib::memory_error::out_of_memory));
153 const u32 slot = m_free_head;
154 m_free_head = next_ptr(slot);
155 next_ptr(slot) = ~0U;
157 if (!ensure_object_block(slot / BLOCK_SIZE)) {
158 next_ptr(slot) = m_free_head;
160 return std::unexpected(lib::kernel_error::from_memory(
161 lib::memory_error::out_of_memory));
163 auto* obj_ptr =
static_cast<T*>(allocate(
sizeof(T)));
165 next_ptr(slot) = m_free_head;
167 return std::unexpected(lib::kernel_error::from_memory(
168 lib::memory_error::out_of_memory));
170 std::construct_at(obj_ptr);
171 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] = obj_ptr;
173 obj.ko.generation = ++generation_ptr(slot);
174 const auto object_type = requested_type == kobject::kobject_type::none
175 ? m_type : requested_type;
176 obj.ko.initialize(slot, object_type);
177 auto metadata_result = object_core::register_object(obj.ko);
178 if (!metadata_result) {
179 next_ptr(slot) = m_free_head;
183 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] =
nullptr;
184 return std::unexpected(metadata_result.error());
186 auto reclaimer_result = object_core::set_reclaimer(obj.ko, reclaim_object);
187 if (!reclaimer_result) {
188 discard_value object_core::unregister_object(obj.ko);
189 next_ptr(slot) = m_free_head;
193 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] =
nullptr;
194 return std::unexpected(reclaimer_result.error());
197 discard_value m_count.fetch_add(1, memory_order::relaxed);
199 return kobject::robject<T, lifecycle_state::embryo>{&obj};
204 [[nodiscard]]
auto alloc_at(u32 id)
noexcept
205 -> std::expected<kobject::robject<T, lifecycle_state::embryo>, lib::kernel_error>
207 if (!m_initialized) [[unlikely]]
208 return std::unexpected(
209 lib::kernel_error::from_generic(lib::generic_error::uninitialized));
212 return std::unexpected(
213 lib::kernel_error::from_generic(lib::generic_error::invalid_arg));
215 const sync::irq_lock_guard guard{m_table_lock};
217 if (object_ptr(id) !=
nullptr)
218 return std::unexpected(
219 lib::kernel_error::from_locking(
220 lib::locking_error::already_locked));
222 if (m_free_head == ~0U)
223 return std::unexpected(
224 lib::kernel_error::from_memory(lib::memory_error::out_of_memory));
226 if (m_free_head == id) {
227 m_free_head = next_ptr(id);
229 u32 prev = m_free_head;
230 while (prev != ~0U && next_ptr(prev) != id)
231 prev = next_ptr(prev);
233 return std::unexpected(
234 lib::kernel_error::from_locking(
235 lib::locking_error::already_locked));
237 next_ptr(prev) = next_ptr(id);
241 if (!ensure_object_block(id / BLOCK_SIZE)) {
242 next_ptr(id) = m_free_head;
244 return std::unexpected(lib::kernel_error::from_memory(
245 lib::memory_error::out_of_memory));
247 auto* obj_ptr =
static_cast<T*>(allocate(
sizeof(T)));
249 next_ptr(id) = m_free_head;
251 return std::unexpected(lib::kernel_error::from_memory(
252 lib::memory_error::out_of_memory));
255 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] = obj_ptr;
257 obj.ko.generation = ++generation_ptr(id);
258 obj.ko.initialize(id, m_type);
259 auto metadata_result = object_core::register_object(obj.ko);
260 if (!metadata_result) {
261 next_ptr(id) = m_free_head;
265 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
266 return std::unexpected(metadata_result.error());
268 auto reclaimer_result = object_core::set_reclaimer(obj.ko, reclaim_object);
269 if (!reclaimer_result) {
270 discard_value object_core::unregister_object(obj.ko);
271 next_ptr(id) = m_free_head;
275 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
276 return std::unexpected(reclaimer_result.error());
279 discard_value m_count.fetch_add(1, memory_order::relaxed);
281 return kobject::robject<T, lifecycle_state::embryo>{&obj};
324 [[nodiscard]]
auto release(u32 id)
noexcept
325 -> std::expected<
void, lib::kernel_error>
328 return std::unexpected(
329 lib::kernel_error::from_generic(lib::generic_error::invalid_arg));
331 T* retired =
nullptr;
333 const sync::irq_lock_guard guard{m_table_lock};
334 auto* obj_ptr = object_ptr(id);
335 if (!obj_ptr)
return std::unexpected(
336 lib::kernel_error::from_generic(lib::generic_error::not_found));
338 if (obj.ko.state == lifecycle_state::embryo ||
339 obj.ko.state == lifecycle_state::active ||
340 obj.ko.state == lifecycle_state::suspended) {
341 if (!obj.ko.transition(lifecycle_state::dying)) {
342 return std::unexpected(lib::kernel_error::from_generic(
343 lib::generic_error::invalid_arg));
346 if (obj.ko.state != lifecycle_state::dying) {
347 return std::unexpected(lib::kernel_error::from_generic(
348 lib::generic_error::invalid_arg));
350 auto metadata_result = object_core::unregister_object(obj.ko);
351 if (!metadata_result)
return std::unexpected(metadata_result.error());
352 discard_value obj.ko.transition(lifecycle_state::destroyed);
353 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
354 discard_value m_count.fetch_sub(1, memory_order::relaxed);
367 auto destroy_if(Pred&& pred, Cleanup&& cleanup)
noexcept -> u32 {
370 for (u32 i = 0; i < N; ++i) {
371 auto ref = acquire_ref<lifecycle_state::active>(i);
372 if (!ref || !pred(*ref))
continue;
374 if (release(i)) ++destroyed;
409 auto for_each(Fn&& fn)
noexcept -> u32 {
411 for (u32 block = 0; block < BLOCK_COUNT; ++block) {
412 auto* slots = m_slot_blocks[block];
413 if (!slots)
continue;
414 for (u32 i = 0; i < BLOCK_SIZE; ++i) {
415 auto* obj = slots[i];
417 auto s = obj->ko.state;
418 if (s != lifecycle_state::embryo &&
419 s != lifecycle_state::active &&
420 s != lifecycle_state::suspended &&
421 s != lifecycle_state::dying)
continue;
423 if (!fn(*obj))
return visited;