From f52ca2f1e2f2620d67a462d5dd95fb771b3990ea Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 6 May 2023 19:48:14 +0100 Subject: [PATCH] obj: object header is no longer allocated automatically --- dev/core.c | 10 ++++++---- doc/objects.rst | 37 +++++++++++++------------------------ include/socks/device.h | 2 ++ include/socks/kext.h | 2 ++ include/socks/object.h | 10 ++++++++-- include/socks/sched.h | 12 ++++++++---- kxld/kext.c | 18 +++++++++++------- obj/namespace.c | 16 ++++++++++++---- obj/object.c | 2 +- obj/set.c | 31 ++++++++++++++++++------------- sched/task.c | 4 +++- sched/thread.c | 4 +++- test/obj.c | 15 ++++++++++----- 13 files changed, 97 insertions(+), 66 deletions(-) diff --git a/dev/core.c b/dev/core.c index a8d34a6..15f6712 100644 --- a/dev/core.c +++ b/dev/core.c @@ -2,6 +2,8 @@ #include #include +#define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p) + static struct device *root_device = NULL; static struct object_type device_type = { .ob_name = "device", @@ -20,10 +22,10 @@ kern_status_t device_init(void) kern_status_t set_root_device(struct device *dev) { if (root_device) { - object_deref(object_header(root_device)); + object_deref(&root_device->dev_base); } - object_ref(object_header(dev)); + object_ref(&dev->dev_base); root_device = dev; return KERN_OK; @@ -35,6 +37,6 @@ struct device *device_alloc(void) if (!dev_object) { return NULL; } - - return object_data(dev_object); + + return DEVICE_CAST(dev_object); } diff --git a/doc/objects.rst b/doc/objects.rst index 1ca1cab..fc9d6e0 100644 --- a/doc/objects.rst +++ b/doc/objects.rst @@ -21,15 +21,15 @@ An object is made up of two distinct halves: the **header** and the system, while the data is the programmer-defined part of the object, and can be used however the object-creator wants. -Object behaviour is defined by an `object_type_t` instance. -An `object_type_t` provides the object system with all the information +Object behaviour is defined by a `struct object_type` instance. +A `struct object_type` provides the object system with all the information it needs to instantiate and interact with your objects. The Object Header ----------------- -The object header is defined in `include/socks/object.h` as `object_t`. +The object header is defined in `include/socks/object.h` as `struct object`. It contains information that is used by the object system, and typically should not be directly accessed outside of the object system. @@ -37,10 +37,10 @@ The contents of the object header include: * `ob_magic`: A magic value used to identify active objects. Functions that retrieve an object's header from its data (and vice versa) - do not have type checking (i.e. they convert between `object_t *` and `void *` + do not have type checking (i.e. they convert between `struct object *` and `void *` using simple pointer arithmetic), so checking for this magic number helps protect against non-objects being passed to functions expecting objects. -* `ob_type`: A pointer to the `object_type_t` that was used to create the +* `ob_type`: A pointer to the `struct object_type` that was used to create the object. Outside of the object system, this can be used as a read-only way to query type information about an object. * `ob_lock`: A general-purpose per-object lock. This lock is *not* reserved @@ -56,35 +56,24 @@ The contents of the object header include: queue entry. -The Object Data ---------------- - -The object data section is the programmer-defined part of the object, and -can be used for any purpose, although it is typically used as storage space -for a C structure. For example the data section of a `task` object is used -to store an instance of a `task_t` C structure containing the task data. - -The object header and data are allocated together in a single contiguous -chunk, with the data coming after the header. **However**, you should -interactive with the object as if you don't know this. The only safe -way to convert between an object header pointer and data pointer is to -use the `object_header()` and `object_data()` functions respectively. - -The object data pointer is guaranteed to be aligned on a `long` boundary. - +When defining a C structure for use when creating objects, you should +define a member of type `struct object` somewhere within the structure. +It does not have to be the first member in the struct. The object system +provides a number of macros to simplify converting a `struct object *` +to a pointer of your structure. The Object Type --------------- The object type defines the name, size, and behaviour of an object. -It is defined using the `object_type_t` C structure. +It is defined using the `struct object_type` C structure. -Some notable parts of `object_type_t` include: +Some notable parts of `struct object_type` include: * `ob_name`: Human-readable name of the object type. For example: "namespace", "set", "task", etc. * `ob_size`: The length of the data section of the object in bytes. -* `ob_cache`: An instance of `vm_cache_t` from which objects of this +* `ob_cache`: An instance of `struct vm_cache` from which objects of this type are allocated. This cache is initialised and managed by the object system on behalf of the programmer, so this can be ignored outside of the object system. diff --git a/include/socks/device.h b/include/socks/device.h index 2bcd03c..4727b57 100644 --- a/include/socks/device.h +++ b/include/socks/device.h @@ -3,6 +3,7 @@ #include #include +#include struct device; @@ -67,6 +68,7 @@ struct bus_device { }; struct device { + struct object dev_base; enum device_type dev_type; struct device *dev_parent; struct queue dev_children; diff --git a/include/socks/kext.h b/include/socks/kext.h index 1d8a332..7e67f45 100644 --- a/include/socks/kext.h +++ b/include/socks/kext.h @@ -2,6 +2,7 @@ #define SOCKS_KEXT_H_ #include +#include #include #include @@ -69,6 +70,7 @@ struct kext_info { }; struct kext { + struct object k_base; enum kext_flags k_flags; char k_ident[KEXT_IDENT_MAX]; uint64_t k_ident_hash; diff --git a/include/socks/object.h b/include/socks/object.h index 33d67a8..3fe59af 100644 --- a/include/socks/object.h +++ b/include/socks/object.h @@ -13,6 +13,13 @@ extern "C" { #define OBJECT_MAGIC 0xBADDCAFE #define OBJECT_NAME_MAX 64 +#define OBJECT_CAST(to_type, to_type_member, p) \ + ((to_type *)((uintptr_t)p) - offsetof(to_type, to_type_member)) +#define OBJECT_C_CAST(c_type, c_type_member, obj_type, objp) \ + OBJECT_IS_TYPE(objp, obj_type) ? OBJECT_CAST(c_type, c_type_member, (objp)) : NULL +#define OBJECT_IS_TYPE(obj, type_ptr) \ + ((obj)->ob_type == (type_ptr)) + struct object; struct object_attrib; @@ -63,6 +70,7 @@ extern kern_status_t object_type_unregister(struct object_type *p); extern struct object_namespace *global_namespace(void); extern struct object_namespace *object_namespace_create(void); +extern struct object *ns_header(struct object_namespace *ns); extern kern_status_t object_namespace_get_object(struct object_namespace *ns, const char *path, struct object **out); extern kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj); extern kern_status_t object_unpublish(struct object_namespace *ns, struct object *obj); @@ -72,8 +80,6 @@ extern struct object *object_ref(struct object *obj); extern void object_deref(struct object *obj); extern void object_lock(struct object *obj, unsigned long *flags); extern void object_unlock(struct object *obj, unsigned long flags); -extern void *object_data(struct object *obj); -extern struct object *object_header(void *p); static inline kern_status_t object_get(const char *path, struct object **out) { return object_namespace_get_object(global_namespace(), path, out); diff --git a/include/socks/sched.h b/include/socks/sched.h index ff8803d..ca7f4f5 100644 --- a/include/socks/sched.h +++ b/include/socks/sched.h @@ -53,6 +53,8 @@ enum sched_mode { }; struct task { + struct object t_base; + struct task *t_parent; unsigned int t_id; enum task_state t_state; @@ -66,6 +68,8 @@ struct task { }; struct thread { + struct object thr_base; + enum thread_state tr_state; enum thread_flags tr_flags; struct task *tr_parent; @@ -131,8 +135,8 @@ static inline void rq_unlock(struct runqueue *rq, unsigned long flags) extern struct runqueue *cpu_rq(unsigned int cpu); extern struct task *task_alloc(void); -static inline struct task *task_ref(struct task *task) { return (struct task *)object_data(object_ref(object_header(task))); } -static inline void task_deref(struct task *task) { object_deref(object_header(task)); } +static inline struct task *task_ref(struct task *task) { return OBJECT_CAST(struct task, t_base, object_ref(&task->t_base)); } +static inline void task_deref(struct task *task) { object_deref(&task->t_base); } extern struct task *task_from_pid(unsigned int pid); extern struct task *kernel_task(void); extern struct task *idle_task(void); @@ -150,12 +154,12 @@ extern void end_charge_period(void); static inline void task_lock_irqsave(struct task *task, unsigned long *flags) { - object_lock(object_header(task), flags); + object_lock(&task->t_base, flags); } static inline void task_unlock_irqrestore(struct task *task, unsigned long flags) { - object_unlock(object_header(task), flags); + object_unlock(&task->t_base, flags); } extern struct thread *thread_alloc(void); diff --git a/kxld/kext.c b/kxld/kext.c index b1df5a9..f921ac2 100644 --- a/kxld/kext.c +++ b/kxld/kext.c @@ -5,13 +5,17 @@ #include #include +#define KEXT_CAST(p) OBJECT_C_CAST(struct kext, k_base, &kext_type, p) + static spin_lock_t kext_tree_lock = SPIN_LOCK_INIT; static struct object *kext_set; struct btree kext_tree; +static struct object_type kext_type; + static kern_status_t kext_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) { - struct kext *kext = object_data(obj); + struct kext *kext = KEXT_CAST(obj); strncpy(out, kext->k_ident, OBJECT_NAME_MAX - 1); out[OBJECT_NAME_MAX - 1] = 0; return KERN_OK; @@ -19,7 +23,7 @@ static kern_status_t kext_query_name(struct object *obj, char out[OBJECT_NAME_MA static kern_status_t kext_destroy(struct object *obj) { - struct kext *kext = object_data(obj); + struct kext *kext = KEXT_CAST(obj); if (kext->k_dependencies) { kfree(kext->k_dependencies); } @@ -103,7 +107,7 @@ struct kext *kext_get_by_id(const char *ident) struct kext *kext = kext_get(ident); if (kext) { - struct object *kext_obj = object_header(kext); + struct object *kext_obj = &kext->k_base; object_ref(kext_obj); } @@ -126,12 +130,12 @@ struct kext *kext_alloc(void) return NULL; } - return object_data(kext_obj); + return KEXT_CAST(kext_obj); } void kext_release(struct kext *kext) { - object_deref(object_header(kext)); + object_deref(&kext->k_base); } kern_status_t kext_register(struct kext *kext) @@ -145,8 +149,8 @@ kern_status_t kext_register(struct kext *kext) return KERN_NAME_EXISTS; } - struct object *kext_obj = object_header(kext); - object_ref(object_header(kext)); + struct object *kext_obj = &kext->k_base; + object_ref(kext_obj); kext_add(kext); set_add_object(kext_set, kext_obj); diff --git a/obj/namespace.c b/obj/namespace.c index f14efe8..f21b5a8 100644 --- a/obj/namespace.c +++ b/obj/namespace.c @@ -1,9 +1,13 @@ #include +#define NAMESPACE_CAST(p) OBJECT_C_CAST(struct object_namespace, ns_base, &ns_type, p) + +static struct object_type ns_type; static struct object_namespace *global_ns; struct object_namespace { /* root directory set object */ + struct object ns_base; struct object *ns_root; }; @@ -16,13 +20,13 @@ static kern_status_t ns_query_name(struct object *obj, char out[OBJECT_NAME_MAX] static kern_status_t ns_get_child_at(struct object *obj, size_t at, struct object **out) { - struct object_namespace *ns = object_data(obj); + struct object_namespace *ns = NAMESPACE_CAST(obj); return object_get_child_at(ns->ns_root, at, out); } static kern_status_t ns_get_child_named(struct object *obj, const char *name, struct object **out) { - struct object_namespace *ns = object_data(obj); + struct object_namespace *ns = NAMESPACE_CAST(obj); return object_get_child_named(ns->ns_root, name, out); } @@ -36,7 +40,6 @@ static struct object_type ns_type = { }, }; - void init_global_namespace(void) { object_type_register(&ns_type); @@ -51,7 +54,7 @@ struct object_namespace *global_namespace(void) struct object_namespace *object_namespace_create(void) { struct object *ns_object = object_create(&ns_type); - struct object_namespace *ns = object_data(ns_object); + struct object_namespace *ns = NAMESPACE_CAST(ns_object); ns->ns_root = set_create("/"); return ns; } @@ -93,6 +96,11 @@ static void cleanup_object_path(char *path, size_t len, size_t *parts) path[final_len] = 0; } +struct object *ns_header(struct object_namespace *ns) +{ + return &ns->ns_base; +} + kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj) { if (*path != '/') { diff --git a/obj/object.c b/obj/object.c index 8b40f18..36e2916 100644 --- a/obj/object.c +++ b/obj/object.c @@ -22,7 +22,7 @@ kern_status_t object_type_register(struct object_type *p) spin_unlock_irqrestore(&object_types_lock, flags); p->ob_cache.c_name = p->ob_name; - p->ob_cache.c_obj_size = sizeof(struct object) + p->ob_size; + p->ob_cache.c_obj_size = p->ob_size; p->ob_cache.c_page_order = VM_PAGE_16K; vm_cache_init(&p->ob_cache); diff --git a/obj/set.c b/obj/set.c index acb5732..b5f33d7 100644 --- a/obj/set.c +++ b/obj/set.c @@ -1,22 +1,27 @@ #include +#define SET_CAST(p) OBJECT_C_CAST(struct set, s_base, &set_type, p) + struct set { + struct object s_base; struct queue s_list; char s_name[OBJECT_NAME_MAX]; }; +static struct object_type set_type; + static kern_status_t set_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) { - struct set *set = object_data(obj); + struct set *set = SET_CAST(obj); strncpy(out, set->s_name, OBJECT_NAME_MAX - 1); out[OBJECT_NAME_MAX - 1] = 0; - + return KERN_OK; } static kern_status_t set_get_child_at(struct object *obj, size_t at, struct object **out) { - struct set *set = object_data(obj); + struct set *set = SET_CAST(obj); size_t i = 0; queue_foreach(struct object, child, &set->s_list, ob_list) { if (i == at) { @@ -26,15 +31,15 @@ static kern_status_t set_get_child_at(struct object *obj, size_t at, struct obje i++; } - + return KERN_NO_ENTRY; } static kern_status_t set_get_child_named(struct object *obj, const char *name, struct object **out) { - struct set *set = object_data(obj); + struct set *set = SET_CAST(obj); char child_name[OBJECT_NAME_MAX]; - + queue_foreach(struct object, child, &set->s_list, ob_list) { kern_status_t status = object_query_name(child, child_name); if (status != KERN_OK) { @@ -46,7 +51,7 @@ static kern_status_t set_get_child_named(struct object *obj, const char *name, s return KERN_OK; } } - + return KERN_NO_ENTRY; } @@ -72,7 +77,7 @@ struct object *set_create(const char *name) return NULL; } - struct set *set = object_data(set_obj); + struct set *set = SET_CAST(set_obj); set->s_list = QUEUE_INIT; strncpy(set->s_name, name, sizeof set->s_name - 1); set->s_name[sizeof set->s_name - 1] = 0; @@ -85,12 +90,12 @@ kern_status_t set_add_object(struct object *set_obj, struct object *obj) if (!object_is_set(set_obj)) { return KERN_INVALID_ARGUMENT; } - - struct set *set = object_data(set_obj); + + struct set *set = SET_CAST(set_obj); char child_name[OBJECT_NAME_MAX]; char obj_name[OBJECT_NAME_MAX]; - + kern_status_t status = object_query_name(obj, obj_name); if (status != KERN_OK) { return status; @@ -114,8 +119,8 @@ kern_status_t set_remove_object(struct object *set_obj, struct object *obj) if (!object_is_set(set_obj)) { return KERN_INVALID_ARGUMENT; } - - struct set *set = object_data(set_obj); + + struct set *set = SET_CAST(set_obj); queue_delete(&set->s_list, &obj->ob_list); object_deref(obj); diff --git a/sched/task.c b/sched/task.c index 413c41c..a3acbad 100644 --- a/sched/task.c +++ b/sched/task.c @@ -6,6 +6,8 @@ #include #include +#define TASK_CAST(p) OBJECT_C_CAST(struct task, t_base, &task_type, p) + static struct object_type task_type = { .ob_name = "task", .ob_size = sizeof(struct task), @@ -144,7 +146,7 @@ struct task *task_alloc(void) return NULL; } - struct task *t = object_data(task_obj); + struct task *t = TASK_CAST(task_obj); memset(t, 0x00, sizeof *t); return t; } diff --git a/sched/thread.c b/sched/thread.c index f6e2f29..afe3e4a 100644 --- a/sched/thread.c +++ b/sched/thread.c @@ -3,6 +3,8 @@ #include #include +#define THREAD_CAST(p) OBJECT_C_CAST(struct thread, thr_base, &thread_type, p) + static struct object_type thread_type = { .ob_name = "thread", .ob_size = sizeof(struct thread), @@ -20,7 +22,7 @@ struct thread *thread_alloc(void) return NULL; } - struct thread *t = object_data(thread_obj); + struct thread *t = THREAD_CAST(thread_obj); memset(t, 0x00, sizeof *t); return t; } diff --git a/test/obj.c b/test/obj.c index c8aa450..f8be774 100644 --- a/test/obj.c +++ b/test/obj.c @@ -3,13 +3,18 @@ #include #include +#define TEST_CAST(p) OBJECT_C_CAST(struct test_object, base, &test_type, p) + struct test_object { + struct object base; char name[OBJECT_NAME_MAX]; }; +static struct object_type test_type; + static kern_status_t test_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) { - struct test_object *test = object_data(obj); + struct test_object *test = TEST_CAST(obj); strncpy(out, test->name, OBJECT_NAME_MAX); out[OBJECT_NAME_MAX - 1] = 0; return KERN_OK; @@ -37,10 +42,10 @@ static void print_object_tree(struct object *obj, int depth) len += snprintf(msg + len, sizeof msg - len, "%s", name); printk(msg); - + struct object *child = NULL; size_t i = 0; - + while (1) { kern_status_t status = object_get_child_at(obj, i, &child); if (status != KERN_OK) { @@ -58,7 +63,7 @@ static int run_obj_tests(void) object_type_register(&test_type); struct object *test_obj = object_create(&test_type); - struct test_object *test = object_data(test_obj); + struct test_object *test = TEST_CAST(test_obj); snprintf(test->name, sizeof test->name, "object1"); kern_status_t status = object_publish(global_namespace(), "/misc/objects", test_obj); if (status == KERN_OK) { @@ -73,7 +78,7 @@ static int run_obj_tests(void) return -1; } - print_object_tree(object_header(global_namespace()), 0); + print_object_tree(ns_header(global_namespace()), 0); return 0; }