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[];