diff --git a/include/kernel/object.h b/include/kernel/object.h index a20e7c4..be2e185 100644 --- a/include/kernel/object.h +++ b/include/kernel/object.h @@ -1,6 +1,7 @@ #ifndef KERNEL_OBJECT_H_ #define KERNEL_OBJECT_H_ +#include #include #include #include @@ -79,10 +80,7 @@ enum object_type_flags { }; struct object_ops { - kern_status_t (*destroy)(struct object *obj, struct queue *q); - kern_status_t (*destroy_recurse)( - struct queue_entry *entry, - struct object **out); + kern_status_t (*destroy)(struct object *obj); }; struct object_type { @@ -101,8 +99,7 @@ struct object { struct object_type *ob_type; spin_lock_t ob_lock; uint32_t ob_signals; - unsigned int ob_refcount; - unsigned int ob_handles; + atomic_t ob_refcount; struct queue_entry ob_list; struct waitqueue ob_wq; } __aligned(sizeof(long)); @@ -114,8 +111,6 @@ extern kern_status_t object_type_unregister(struct object_type *p); extern struct object *object_create(struct object_type *type); extern struct object *object_ref(struct object *obj); extern void object_unref(struct object *obj); -extern void object_add_handle(struct object *obj); -extern void object_remove_handle(struct object *obj); extern void object_lock(struct object *obj); extern void object_unlock(struct object *obj); extern void object_lock_irqsave(struct object *obj, unsigned long *flags); diff --git a/kernel/handle.c b/kernel/handle.c index ab4ce12..d1d0df9 100644 --- a/kernel/handle.c +++ b/kernel/handle.c @@ -46,7 +46,7 @@ static void do_handle_table_destroy_leaf(struct handle_table *tab) struct handle *child = &tab->t_handles.t_handle_list[index]; bitmap_clear(tab->t_subtables.t_subtable_map, index); if (child->h_object) { - object_remove_handle(child->h_object); + object_unref(child->h_object); child->h_object = NULL; } } @@ -195,7 +195,7 @@ kern_status_t handle_table_free_handle( = &tab->t_handles.t_handle_list[handle_index]; if (handle_entry->h_object) { - object_remove_handle(handle_entry->h_object); + object_unref(handle_entry->h_object); } memset(handle_entry, 0x0, sizeof *handle_entry); @@ -307,7 +307,7 @@ kern_status_t handle_table_transfer( dst_entry->h_object = src_entry->h_object; dst_entry->h_flags = src_entry->h_flags; - object_add_handle(dst_entry->h_object); + object_ref(dst_entry->h_object); handle_table_free_handle(src, src_handles[i].hnd_value); @@ -326,7 +326,7 @@ kern_status_t handle_table_transfer( dst_entry->h_object = src_entry->h_object; dst_entry->h_flags = src_entry->h_flags; - object_add_handle(dst_entry->h_object); + object_ref(dst_entry->h_object); dst_handle.hnd_mode = src_handles[i].hnd_mode; dst_handle.hnd_value = dst_value; @@ -371,7 +371,7 @@ kern_status_t handle_table_transfer( struct handle *src_entry = handle_table_get_handle(src, handle.hnd_value); if (src_entry) { - object_remove_handle(src_entry->h_object); + object_unref(src_entry->h_object); handle_table_free_handle(src, handle.hnd_value); } } diff --git a/kernel/object.c b/kernel/object.c index 4bd68de..58cff40 100644 --- a/kernel/object.c +++ b/kernel/object.c @@ -74,90 +74,28 @@ struct object *object_create(struct object_type *type) obj->ob_lock = SPIN_LOCK_INIT; obj->ob_magic = OBJECT_MAGIC; obj->ob_refcount = 1; - obj->ob_handles = 0; return obj; } struct object *object_ref(struct object *obj) { - obj->ob_refcount++; + atomic_add_fetch(&obj->ob_refcount, 1); return obj; } -static void __cleanup(struct object *obj, struct queue *queue) -{ - if (HAS_OP(obj, destroy)) { - obj->ob_type->ob_ops.destroy(obj, queue); - } - - vm_cache_free(&obj->ob_type->ob_cache, obj); -} - -static void object_cleanup(struct object *obj, unsigned long flags) -{ - if (obj->ob_refcount > 0 || obj->ob_handles > 0) { - spin_unlock_irqrestore(&obj->ob_lock, flags); - return; - } - - struct queue queue = QUEUE_INIT; - __cleanup(obj, &queue); - - if (!HAS_OP(obj, destroy_recurse)) { - return; - } - - while (!queue_empty(&queue)) { - struct queue_entry *entry = queue_pop_front(&queue); - struct object *child = NULL; - obj->ob_type->ob_ops.destroy_recurse(entry, &child); - if (!child) { - continue; - } - - if (child->ob_refcount > 1) { - child->ob_refcount--; - continue; - } - - if (child->ob_refcount == 0 && child->ob_handles == 0) { - __cleanup(child, &queue); - } - } -} - void object_unref(struct object *obj) { - unsigned long flags; - spin_lock_irqsave(&obj->ob_lock, &flags); - - if (obj->ob_refcount == 0) { - spin_unlock_irqrestore(&obj->ob_lock, flags); + int ref = atomic_sub_fetch(&obj->ob_refcount, 1); + if (ref > 0) { return; } - obj->ob_refcount--; - object_cleanup(obj, flags); -} - -void object_add_handle(struct object *obj) -{ - obj->ob_handles++; -} - -void object_remove_handle(struct object *obj) -{ - unsigned long flags; - spin_lock_irqsave(&obj->ob_lock, &flags); - - if (obj->ob_handles == 0) { - spin_unlock_irqrestore(&obj->ob_lock, flags); - return; + if (HAS_OP(obj, destroy)) { + obj->ob_type->ob_ops.destroy(obj); } - obj->ob_handles--; - object_cleanup(obj, flags); + vm_cache_free(&obj->ob_type->ob_cache, obj); } void object_lock(struct object *obj) diff --git a/kernel/port.c b/kernel/port.c index f82a9c7..3071d83 100644 --- a/kernel/port.c +++ b/kernel/port.c @@ -17,7 +17,7 @@ static struct object_type port_type = { }, }; -static kern_status_t port_cleanup(struct object *obj, struct queue *q) +static kern_status_t port_cleanup(struct object *obj) { struct port *port = PORT_CAST(obj); port_disconnect(port); diff --git a/sched/task.c b/sched/task.c index 89902e7..504b204 100644 --- a/sched/task.c +++ b/sched/task.c @@ -334,11 +334,10 @@ void task_exit(int status) self->t_name, self->t_id, cur_thread->tr_id); - tracek("task %s[%u] killed (%u, %u)", + tracek("task %s[%u] killed (%u)", self->t_name, self->t_id, - self->t_base.ob_refcount, - self->t_base.ob_handles); + self->t_base.ob_refcount); spin_unlock_irqrestore(handles_lock, flags); while (1) { @@ -359,7 +358,7 @@ kern_status_t task_open_handle( return status; } - object_add_handle(obj); + object_ref(obj); handle_data->h_object = obj; handle_data->h_flags = flags; diff --git a/syscall/task.c b/syscall/task.c index 9b2f72a..2b04346 100644 --- a/syscall/task.c +++ b/syscall/task.c @@ -38,7 +38,7 @@ kern_status_t sys_task_self(kern_handle_t *out) return status; } - object_add_handle(&self->t_base); + object_ref(&self->t_base); handle_slot->h_object = &self->t_base; *out = handle; @@ -129,8 +129,8 @@ kern_status_t sys_task_create( child_handle_slot->h_object = &child->t_base; space_handle_slot->h_object = &child->t_address_space->s_base; - object_add_handle(&child->t_base); - object_add_handle(&child->t_address_space->s_base); + object_ref(&child->t_base); + object_ref(&child->t_address_space->s_base); object_unref(parent_obj); @@ -199,7 +199,7 @@ kern_status_t sys_task_create_thread( thread_init_user(thread, ip, sp, args, nr_args); target_handle->h_object = &thread->tr_base; - object_add_handle(&thread->tr_base); + object_ref(&thread->tr_base); task_unlock_irqrestore(target, flags); object_unref(target_obj); @@ -254,7 +254,7 @@ kern_status_t sys_task_get_address_space( } handle_slot->h_object = &task->t_address_space->s_base; - object_add_handle(&task->t_address_space->s_base); + object_ref(&task->t_address_space->s_base); task_unlock_irqrestore(self, flags); object_unref(task_obj); @@ -286,7 +286,7 @@ kern_status_t sys_thread_self(kern_handle_t *out) return status; } - object_add_handle(&self_thread->tr_base); + object_ref(&self_thread->tr_base); handle_slot->h_object = &self_thread->tr_base; *out = handle; diff --git a/syscall/vm-controller.c b/syscall/vm-controller.c index 31c1257..a1c756e 100644 --- a/syscall/vm-controller.c +++ b/syscall/vm-controller.c @@ -186,8 +186,6 @@ kern_status_t sys_vm_controller_create_object( } out_slot->h_object = &out_vmo->vo_base; - object_add_handle(&out_vmo->vo_base); - object_unref(&out_vmo->vo_base); *out = out_handle; return KERN_OK; diff --git a/vm/address-space.c b/vm/address-space.c index 78c8883..60d1ee3 100644 --- a/vm/address-space.c +++ b/vm/address-space.c @@ -47,7 +47,7 @@ enum search_direction { SEARCH_RIGHT, }; -static kern_status_t address_space_cleanup(struct object *obj, struct queue *q); +static kern_status_t address_space_cleanup(struct object *obj); static struct object_type address_space_type = { .ob_name = "address-space", @@ -664,9 +664,10 @@ static void area_unmap(struct vm_area *area) } } -static kern_status_t address_space_cleanup(struct object *obj, struct queue *q) +static kern_status_t address_space_cleanup(struct object *obj) { struct address_space *space = ADDRESS_SPACE_CAST(obj); + tracek("begin address space cleanup %p", space); struct btree_node *cur = btree_first(&space->s_mappings); while (cur) { struct btree_node *next = btree_next(cur); @@ -680,6 +681,20 @@ static kern_status_t address_space_cleanup(struct object *obj, struct queue *q) cur = next; } + cur = btree_first(&space->s_reserved); + while (cur) { + struct btree_node *next = btree_next(cur); + struct vm_area *area + = BTREE_CONTAINER(struct vm_area, vma_node, cur); + btree_delete(&space->s_reserved, cur); + + delete_area(area, space); + vm_cache_free(&vm_area_cache, area); + + cur = next; + } + + tracek("end address space cleanup %p", space); return KERN_OK; } diff --git a/vm/vm-object.c b/vm/vm-object.c index 0a028e0..9ee6005 100644 --- a/vm/vm-object.c +++ b/vm/vm-object.c @@ -15,7 +15,7 @@ (p) += VM_PAGE_SIZE; \ } -static kern_status_t vm_object_cleanup(struct object *obj, struct queue *q) +static kern_status_t vm_object_cleanup(struct object *obj) { struct vm_object *vmo = vm_object_cast(obj); struct btree_node *cur = btree_first(&vmo->vo_pages);