118 auto init(kobject::kobject_type type)
noexcept ->
void {
120 install_bobject_finalizer(object_core::finalize_last_put);
124 for (u32 i = 0; i < N; ++i) {
125 if (!ensure_slot_block(i / BLOCK_SIZE))
return;
126 next_ptr(i) = (i + 1 < N) ? (i + 1) : ~0U;
130 m_count.store(0, memory_order::relaxed);
131 m_initialized =
true;
137 [[nodiscard]]
auto alloc(kobject::kobject_type requested_type = kobject::kobject_type::none)
noexcept
138 -> std::expected<kobject::robject<T, lifecycle_state::embryo>, lib::kernel_error>
140 if (!m_initialized) [[unlikely]]
141 return std::unexpected(
142 lib::kernel_error::from_generic(lib::generic_error::uninitialized));
144 const sync::irq_lock_guard guard{m_table_lock};
146 if (m_free_head == ~0U)
147 return std::unexpected(
148 lib::kernel_error::from_memory(lib::memory_error::out_of_memory));
150 const u32 slot = m_free_head;
151 m_free_head = next_ptr(slot);
152 next_ptr(slot) = ~0U;
154 if (!ensure_object_block(slot / BLOCK_SIZE)) {
155 next_ptr(slot) = m_free_head;
157 return std::unexpected(lib::kernel_error::from_memory(
158 lib::memory_error::out_of_memory));
160 auto* obj_ptr =
static_cast<T*>(allocate(
sizeof(T)));
162 next_ptr(slot) = m_free_head;
164 return std::unexpected(lib::kernel_error::from_memory(
165 lib::memory_error::out_of_memory));
167 std::construct_at(obj_ptr);
168 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] = obj_ptr;
170 obj.ko.generation = ++generation_ptr(slot);
171 const auto object_type = requested_type == kobject::kobject_type::none
172 ? m_type : requested_type;
173 obj.ko.initialize(slot, object_type);
174 auto metadata_result = object_core::register_object(obj.ko);
175 if (!metadata_result) {
176 next_ptr(slot) = m_free_head;
180 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] =
nullptr;
181 return std::unexpected(metadata_result.error());
183 auto reclaimer_result = object_core::set_reclaimer(obj.ko, reclaim_object);
184 if (!reclaimer_result) {
185 discard_value object_core::unregister_object(obj.ko);
186 next_ptr(slot) = m_free_head;
190 m_slot_blocks[slot / BLOCK_SIZE][slot % BLOCK_SIZE] =
nullptr;
191 return std::unexpected(reclaimer_result.error());
194 discard_value m_count.fetch_add(1, memory_order::relaxed);
196 return kobject::robject<T, lifecycle_state::embryo>{&obj};
201 [[nodiscard]]
auto alloc_at(u32 id)
noexcept
202 -> std::expected<kobject::robject<T, lifecycle_state::embryo>, lib::kernel_error>
204 if (!m_initialized) [[unlikely]]
205 return std::unexpected(
206 lib::kernel_error::from_generic(lib::generic_error::uninitialized));
209 return std::unexpected(
210 lib::kernel_error::from_generic(lib::generic_error::invalid_arg));
212 const sync::irq_lock_guard guard{m_table_lock};
214 if (object_ptr(id) !=
nullptr)
215 return std::unexpected(
216 lib::kernel_error::from_locking(
217 lib::locking_error::already_locked));
219 if (m_free_head == ~0U)
220 return std::unexpected(
221 lib::kernel_error::from_memory(lib::memory_error::out_of_memory));
223 if (m_free_head == id) {
224 m_free_head = next_ptr(id);
226 u32 prev = m_free_head;
227 while (prev != ~0U && next_ptr(prev) != id)
228 prev = next_ptr(prev);
230 return std::unexpected(
231 lib::kernel_error::from_locking(
232 lib::locking_error::already_locked));
234 next_ptr(prev) = next_ptr(id);
238 if (!ensure_object_block(id / BLOCK_SIZE)) {
239 next_ptr(id) = m_free_head;
241 return std::unexpected(lib::kernel_error::from_memory(
242 lib::memory_error::out_of_memory));
244 auto* obj_ptr =
static_cast<T*>(allocate(
sizeof(T)));
246 next_ptr(id) = m_free_head;
248 return std::unexpected(lib::kernel_error::from_memory(
249 lib::memory_error::out_of_memory));
252 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] = obj_ptr;
254 obj.ko.generation = ++generation_ptr(id);
255 obj.ko.initialize(id, m_type);
256 auto metadata_result = object_core::register_object(obj.ko);
257 if (!metadata_result) {
258 next_ptr(id) = m_free_head;
262 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
263 return std::unexpected(metadata_result.error());
265 auto reclaimer_result = object_core::set_reclaimer(obj.ko, reclaim_object);
266 if (!reclaimer_result) {
267 discard_value object_core::unregister_object(obj.ko);
268 next_ptr(id) = m_free_head;
272 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
273 return std::unexpected(reclaimer_result.error());
276 discard_value m_count.fetch_add(1, memory_order::relaxed);
278 return kobject::robject<T, lifecycle_state::embryo>{&obj};
321 [[nodiscard]]
auto release(u32 id)
noexcept
322 -> std::expected<
void, lib::kernel_error>
325 return std::unexpected(
326 lib::kernel_error::from_generic(lib::generic_error::invalid_arg));
328 T* retired =
nullptr;
330 const sync::irq_lock_guard guard{m_table_lock};
331 auto* obj_ptr = object_ptr(id);
332 if (!obj_ptr)
return std::unexpected(
333 lib::kernel_error::from_generic(lib::generic_error::not_found));
335 if (obj.ko.state == lifecycle_state::embryo ||
336 obj.ko.state == lifecycle_state::active ||
337 obj.ko.state == lifecycle_state::suspended) {
338 if (!obj.ko.transition(lifecycle_state::dying)) {
339 return std::unexpected(lib::kernel_error::from_generic(
340 lib::generic_error::invalid_arg));
343 if (obj.ko.state != lifecycle_state::dying) {
344 return std::unexpected(lib::kernel_error::from_generic(
345 lib::generic_error::invalid_arg));
347 auto metadata_result = object_core::unregister_object(obj.ko);
348 if (!metadata_result)
return std::unexpected(metadata_result.error());
349 discard_value obj.ko.transition(lifecycle_state::destroyed);
350 m_slot_blocks[id / BLOCK_SIZE][id % BLOCK_SIZE] =
nullptr;
351 discard_value m_count.fetch_sub(1, memory_order::relaxed);
364 auto destroy_if(Pred&& pred, Cleanup&& cleanup)
noexcept -> u32 {
367 for (u32 i = 0; i < N; ++i) {
368 auto ref = acquire_ref<lifecycle_state::active>(i);
369 if (!ref || !pred(*ref))
continue;
371 if (release(i)) ++destroyed;
406 auto for_each(Fn&& fn)
noexcept -> u32 {
408 for (u32 block = 0; block < BLOCK_COUNT; ++block) {
409 auto* slots = m_slot_blocks[block];
410 if (!slots)
continue;
411 for (u32 i = 0; i < BLOCK_SIZE; ++i) {
412 auto* obj = slots[i];
414 auto s = obj->ko.state;
415 if (s != lifecycle_state::embryo &&
416 s != lifecycle_state::active &&
417 s != lifecycle_state::suspended &&
418 s != lifecycle_state::dying)
continue;
420 if (!fn(*obj))
return visited;