BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 4d3c382801026ca46da937de6d7261f1f6805d9e

// Related

Nucleus

Barry Object Lists + replacing Task Queues 4d3c382 (3 years, 3 months ago)
diff --git a/include/nucleus/object.h b/include/nucleus/object.h
index 3103736..7386984 100644
--- a/include/nucleus/object.h
+++ b/include/nucleus/object.h
@@ -2,15 +2,18 @@
 #define _NUCLEUS_OBJECT_H
 
 #include <sys/types.h>
+#include <stddef.h>
 #include <nucleus/cpu.h>
 
+typedef struct Spinlock Spinlock;
 typedef struct ObjectType ObjectType;
-struct Object;
 typedef struct Object Object;
-typedef struct Spinlock Spinlock;
+typedef struct ObjectList ObjectList;
 
 typedef struct Task Task; /* Just a pointer, no need for full definition */
 
+typedef int (*callback_t)(void *object, void *data);
+
 /* Spinlock */
 struct Spinlock {
 	char locked;
@@ -25,7 +28,10 @@ struct Spinlock {
 struct ObjectType {
 	unsigned int count;
 	refcount_t usage;
-	void *(*new)(void);
+	size_t size;
+	void *(*alloc)(void);
+	void (*free)(Object *);
+	void (*new)(Object *);
 	void (*delete)(Object *);
 };
 
@@ -36,10 +42,21 @@ struct Object {
 	Spinlock lock;
 };
 
+extern ObjectType listType;
+
 void *get(void *addr);
 void put(void *addr);
 void *new(ObjectType *type);
 void lock(void *addr);
 void unlock(void *addr);
 
+ObjectList *create_list(ObjectType *type);
+void destroy_list(ObjectList *list);
+void add(ObjectList *list, void *addr);
+void remove(ObjectList *list, void *addr);
+void *pop_from_start(ObjectList *list);
+void *pop_from_end(ObjectList *list);
+size_t count(ObjectList *list);
+void iterate(ObjectList *list, callback_t callback, void *data);
+
 #endif
diff --git a/include/nucleus/task.h b/include/nucleus/task.h
index f017d11..3548782 100644
--- a/include/nucleus/task.h
+++ b/include/nucleus/task.h
@@ -8,7 +8,6 @@
 #include <nucleus/memory.h>
 
 typedef struct Task Task;
-typedef struct TaskQueue TaskQueue;
 
 /* Task priorities */
 enum Priority {
@@ -36,11 +35,9 @@ struct Task {
 
 	uintptr_t esp, ebp, eip;
 	page_dir_t pageDir;
-	Task *next;
 };
 
 extern ObjectType taskType;
-extern ObjectType taskQueueType;
 
 extern Task *currentTask[];
 #define current currentTask[CPUID]
@@ -49,9 +46,4 @@ void init_tasking(void);
 void schedule(void);
 pid_t clone(int flags);
 
-void add_to_queue(TaskQueue *queue, Task *task);
-void remove_from_queue(TaskQueue *queue, Task *task);
-Task *pop_from_queue(TaskQueue *queue);
-size_t tasks_in_queue(TaskQueue *queue);
-
 #endif
diff --git a/object/list.c b/object/list.c
new file mode 100644
index 0000000..75725e5
--- /dev/null
+++ b/object/list.c
@@ -0,0 +1,146 @@
+/*
+ * This file implements Object Lists.  Objects can be a part of multiple lists
+ * that can be managed automatically by the Object Manager.  This prevents
+ * subsystems having to implement their own object lists for sub-objects.  Each
+ * list is implemented as an Object itself, which allows the common object
+ * routines to be used on them.
+ */
+
+#include <nucleus/object.h>
+#include <nucleus/memory.h>
+
+/* Structure for a List Entry */
+struct ListEntry {
+	struct ListEntry *next;
+	Object *obj;
+};
+/* Structure for an Object List */
+struct ObjectList {
+	struct ListEntry *start, *end;
+	size_t entries;
+	ObjectType *type;
+	Spinlock lock;
+};
+
+void acquire(Spinlock *lock);
+void release(Spinlock *lock);
+
+/* Create an Object List */
+ObjectList *
+create_list(ObjectType *type)
+{
+	ObjectList *list = kmalloc(sizeof(ObjectList));
+	list->type = type;
+	return list;
+}
+
+/* Destroy an Object List */
+void
+destroy_list(ObjectList *list)
+{
+	while (list->start)
+		remove(list, list->start);
+}
+
+/* Add an Object to a List */
+void
+add(ObjectList *list, void *addr)
+{
+	Object *obj = addr;
+	if (list->type && obj->type != list->type)
+		return;
+
+	acquire(&list->lock);
+	struct ListEntry *entry = kmalloc(sizeof(struct ListEntry));
+	if (!list->start)
+		list->start = entry;
+	else
+		list->end->next = entry;
+	list->end = entry;
+	entry->obj = get(obj);
+	list->entries++;
+	release(&list->lock);
+}
+
+/* Remove an Object from a List */
+void
+remove(ObjectList *list, void *addr)
+{
+	Object *obj = addr;
+	if (!list->start)
+		return;
+	if (list->type && obj->type != list->type)
+		return;
+	acquire(&list->lock);
+
+	/* Start of list */
+	struct ListEntry *entry, *prev = NULL;
+	if (list->start->obj == obj) {
+		entry = list->start;
+		list->start = entry->next;
+		goto found;
+	}
+
+	/* Search for object */
+	for (prev = list->start; prev->next; prev = prev->next)
+		if (prev->next->obj == obj)
+			break;
+	if (!prev->next)
+		goto end;
+	entry = prev->next;
+	prev->next = entry->next;
+
+found:
+	if (list->end->obj == obj)
+		list->end = prev;
+	put(obj);
+	list->entries--;
+	kfree(entry);
+end:
+	release(&list->lock);
+}
+
+/* Pop the first Object in a List */
+void *
+pop_from_start(ObjectList *list)
+{
+	if (!list->start)
+		return NULL;
+	acquire(&list->lock);
+	Object *head = get(list->start->obj);
+	remove(list, head);
+	release(&list->lock);
+	return head;
+}
+
+/* Pop the last Object in a List */
+void *
+pop_from_end(ObjectList *list)
+{
+	if (!list->end)
+		return NULL;
+	acquire(&list->lock);
+	Object *tail = get(list->end->obj);
+	remove(list, tail);
+	release(&list->lock);
+	return tail;
+}
+
+/* Count the number of Objects in a List */
+size_t
+count(ObjectList *list)
+{
+	return list->entries;
+}
+
+/* Iterate a List with a callback */
+void
+iterate(ObjectList *list, callback_t callback, void *data)
+{
+	acquire(&list->lock);
+	struct ListEntry *entry;
+	for (entry = list->start; entry; entry = entry->next)
+		if (callback(entry->obj, data))
+			break;
+	release(&list->lock);
+}
diff --git a/object/manager.c b/object/manager.c
index a330d15..124ebbc 100644
--- a/object/manager.c
+++ b/object/manager.c
@@ -7,6 +7,8 @@
  */
 
 #include <nucleus/object.h>
+#include <nucleus/memory.h>
+#include <nucleus/panic.h>
 
 void acquire(Spinlock *lock);
 void release(Spinlock *lock);
@@ -30,14 +32,25 @@ put(void *addr)
 	if (__atomic_sub_fetch(&obj->usage, 1, __ATOMIC_RELAXED))
 		return;
 	__atomic_sub_fetch(&obj->type->count, 1, __ATOMIC_RELAXED);
-	obj->type->delete(obj);
+	if (obj->type->delete)
+		obj->type->delete(obj);
+	if (obj->type->free)
+		obj->type->free(obj);
+	else
+		kfree(obj);
 }
 
 /* Create a new instance of an object */
 void *
 new(ObjectType *type)
 {
-	Object *obj = type->new();
+	Object *obj;
+	if (type->alloc)
+		obj = type->alloc();
+	else
+		obj = kmalloc(type->size);
+	if (type->new)
+		type->new(obj);
 	obj->type = type;
 	__atomic_add_fetch(&type->count, 1, __ATOMIC_RELAXED);
 	return get(obj);
diff --git a/task/clone.c b/task/clone.c
index 5e425fa..41cbc48 100644
--- a/task/clone.c
+++ b/task/clone.c
@@ -6,7 +6,7 @@
 #include <sys/types.h>
 #include <nucleus/task.h>
 
-extern TaskQueue *readyQueue[];
+extern ObjectList *readyQueue[];
 
 /* Clone a task */
 pid_t
@@ -24,7 +24,7 @@ clone(int flags)
 	child->eip = (uintptr_t) &&end;
 	asm volatile("mov %%esp, %0" : "=r" (child->esp));
 	asm volatile("mov %%ebp, %0" : "=r" (child->ebp));
-	add_to_queue(readyQueue[child->priority], child);
+	add(readyQueue[child->priority], child);
 	tid = child->tid;
 	put(child);
 end:
diff --git a/task/queue.c b/task/queue.c
deleted file mode 100644
index 7d82c87..0000000
--- a/task/queue.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * This file implements the Task Queue object and contains all the functions for
- * dealing with them.  A Task Queue holds a reference to every Task it contains.
- * There is a single reference per task for the entire queue, and tasks do not
- * hold references to their neighbour, nor the queue its end.
- */
-
-#include <nucleus/object.h>
-#include <nucleus/task.h>
-
-/* Structure for a Task Queue */
-struct TaskQueue {
-	Object obj;
-	Task *start, *end;
-	size_t tasks;
-};
-
-static void *task_queue_new(void);
-static void task_queue_delete(Object *);
-
-/* Task Queue object type */
-ObjectType taskQueueType = {
-	.new = task_queue_new,
-	.delete = task_queue_delete,
-};
-
-/* Create a new Task Queue */
-static void *
-task_queue_new(void)
-{
-	TaskQueue *queue = kmalloc(sizeof(TaskQueue));
-}
-
-/* Destroy a Task Queue */
-static void
-task_queue_delete(Object *obj)
-{
-	TaskQueue *queue = (void *) obj;
-	while (queue->start)
-		put(pop_from_queue(queue));
-	kfree(queue);
-}
-
-/* Add a Task to a Task Queue */
-void
-add_to_queue(TaskQueue *queue, Task *task)
-{
-	lock(queue);
-	if (!queue->start)
-		queue->start = get(task);
-	else
-		queue->end->next = get(task);
-	queue->end = task;
-	task->next = NULL;
-	queue->tasks++;
-	unlock(queue);
-}
-
-/* Remove a Task from a Task Queue */
-void
-remove_from_queue(TaskQueue *queue, Task *task)
-{
-	lock(queue);
-
-	/* Start of queue */
-	if (queue->start == task) {
-		queue->start = task->next;
-		goto found;
-	}
-
-	/* Search */
-	Task *prev;
-	for (prev = queue->start; prev->next; prev = prev->next)
-		if (prev->next == task)
-			break;
-	if (!prev->next) {
-		unlock(queue);
-		return;
-	}
-
-	prev->next = task->next;
-
-found:
-	if (queue->end == task)
-		queue->end = NULL;
-
-	task->next = NULL;
-	put(task);
-	queue->tasks--;
-	unlock(queue);
-}
-
-/* Remove the first Task from a Task Queue */
-Task *
-pop_from_queue(TaskQueue *queue)
-{
-	lock(queue);
-	Task *head = get(queue->start);
-	remove_from_queue(queue, queue->start);
-	unlock(queue);
-	return head;
-}
-
-/* Count the tasks in a queue */
-size_t
-tasks_in_queue(TaskQueue *queue)
-{
-	return queue->tasks;
-}
diff --git a/task/scheduler.c b/task/scheduler.c
index 06012ae..7b08fc2 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -11,7 +11,7 @@
 
 #define PRIORITY_COUNT 6
 
-TaskQueue *readyQueue[PRIORITY_COUNT];
+ObjectList *readyQueue[PRIORITY_COUNT];
 
 /* Switch to a task */
 static void
@@ -41,12 +41,12 @@ end:
 }
 
 /* Find the next schedulable ready queue */
-static TaskQueue *
+static ObjectList *
 highest_priority_queue(void)
 {
 	enum Priority p;
 	for (p = PRIORITY_COUNT - 1; p > 0; p--) {
-		if (tasks_in_queue(readyQueue[p]))
+		if (count(readyQueue[p]))
 			return readyQueue[p];
 	}
 	return NULL;
@@ -57,15 +57,15 @@ void
 schedule(void)
 {
 	Task *task = current;
-	TaskQueue *queue = highest_priority_queue();
+	ObjectList *queue = highest_priority_queue();
 
 	/* Next schedulable task */
 	if (queue) {
-		task = pop_from_queue(queue);
+		task = pop_from_start(queue);
 		task->state = RUNNING;
 		if (current->state == RUNNING) {
 			current->state = READY;
-			add_to_queue(readyQueue[current->priority], current);
+			add(readyQueue[current->priority], current);
 		}
 		switch_to_task(task);
 	/* Idle */
@@ -76,7 +76,7 @@ schedule(void)
 			asm volatile("hlt");
 		asm volatile("cli");
 		current = task;
-		task = pop_from_queue(queue);
+		task = pop_from_start(queue);
 		task->state = RUNNING;
 		switch_to_task(task);
 	}
@@ -88,5 +88,5 @@ init_scheduler(void)
 {
 	enum Priority p;
 	for (p = 0; p < PRIORITY_COUNT; p++)
-		readyQueue[p] = new(&taskQueueType);
+		readyQueue[p] = create_list(&taskType);
 }
diff --git a/task/task.c b/task/task.c
index 9fafc6f..8b64df0 100644
--- a/task/task.c
+++ b/task/task.c
@@ -14,34 +14,25 @@
 void init_scheduler(void);
 void timer_handler(struct InterruptFrame *frame);
 
-static void *task_new(void);
-static void task_delete(Object *);
+static void task_new(Object *);
 
 /* Task object type */
 ObjectType taskType = {
+	.size = sizeof(Task),
 	.new = task_new,
-	.delete = task_delete,
 };
 
 Task *currentTask[MAX_CPUS];
 pid_t nextTid = 1;
 
 /* Create a new Task */
-static void *
-task_new(void)
+static void
+task_new(Object *obj)
 {
-	Task *task = kmalloc(sizeof(Task));
+	Task *task = (void *) obj;
 	task->tid = nextTid++;
 	task->priority = NORMAL;
 	task->state = READY;
-	return task;
-}
-
-/* Destroy a Task */
-static void
-task_delete(Object *obj)
-{
-	kfree(obj);
 }
 
 extern char stackTop[];