BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / 4e8efebf78742fe6ce4b46bbd72be9eb5b3175dd / object / list.c

// Related

Nucleus

Barry Global object lists 5be6a64 (3 years, 3 months ago)
/*
 * 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 init_lock(Spinlock *lock);
void acquire(Spinlock *lock);
void release(Spinlock *lock);

/* Create an Object List */
ObjectList *
create_list(ObjectType *type)
{
	ObjectList *list = kmalloc(sizeof(ObjectList));
	init_lock(&list->lock);
	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);
}