BarryServer : Git

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

// Related

Nucleus

Barry Object manager and heap in kernel library 08afe80 (3 years, 2 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 <stdarg.h>
#include <nucleus/kernel.h>
#include <nucleus/memory.h>
#include <nucleus/object.h>

/* Structure for a List Entry */
struct ListEntry {
	struct ListEntry *prev, *next;
	Object *obj;
};
/* Structure for an Object List */
struct ObjectList {
	struct ListEntry *start, *end;
	size_t entries;
	ObjectType *type;
	enum ListMode mode;
	compare_callback_t compare;
	Spinlock lock;
};
/* Iterator */
struct Iterator {
	ObjectList *list;
	struct ListEntry *prev, *entry, *next;
	off_t pos;
};

void init_lock(Spinlock *lock);
void acquire(Spinlock *lock);
void release(Spinlock *lock);

/* Create an Object List */
ObjectList *
create_list(ObjectType *type, enum ListMode mode, ...)
{
	ObjectList *list = kmalloc(sizeof(ObjectList));
	init_lock(&list->lock);
	list->type = type;
	list->mode = mode;

	if (mode == LIST_ORDERED) {
		va_list args;
		va_start(args, mode);
		list->compare = va_arg(args, compare_callback_t);
		va_end(args);
	}

	return list;
}

/* Destroy an Object List */
void
destroy_list(ObjectList *list)
{
	while (list->entries > 0)
		remove(list, list->start->obj);
}

/* Add an Object to a List */
void
add(ObjectList *list, void *addr)
{
	Object *obj = addr;
	ASSERT(obj->magic == OBJECT_MAGIC);
	if (list->type && obj->type != list->type)
		return;

	if (list->mode != LIST_LOCKLESS)
		acquire(&list->lock);

	struct ListEntry *entry, *next;
	entry = kmalloc(sizeof(struct ListEntry));
	entry->obj = get(obj);
	list->entries++;

	if (!list->start) {
		/* Only item in list */
		list->start = list->end = entry;
	} else if (list->compare) {
		/* Find next item */
		for (next = list->start; next; next = next->next) {
			if (list->compare(next->obj, obj) > 0)
				break;
		}
		if (!next)
			goto end;
		/* Add in */
		entry->prev = next->prev;
		entry->next = next;
		next->prev = entry;
		if (entry->prev)
			entry->prev->next = entry;
		else
			list->start = entry;
	} else {
end:
		/* Add to end of list */
		list->end->next = entry;
		entry->prev = list->end;
		list->end = entry;
	}

	if (list->mode != LIST_LOCKLESS)
		release(&list->lock);
}

/* Remove an Object from a List */
void
remove(ObjectList *list, void *addr)
{
	Object *obj = addr;
	ASSERT(obj->magic == OBJECT_MAGIC);
	if (!list->start)
		return;
	if (list->type && obj->type != list->type)
		return;
	if (list->mode != LIST_LOCKLESS)
		acquire(&list->lock);

	/* Search for object */
	struct ListEntry *entry;
	for (entry = list->start;
	     entry && entry->obj != obj;
	     entry = entry->next);
	if (!entry) {
		release(&list->lock);
		return;
	}

	/* Unlink list */
	if (list->start == entry)
		list->start = entry->next;
	if (list->end == entry)
		list->end = entry->prev;

	/* Unlink neighbours */
	if (entry->prev)
		entry->prev->next = entry->next;
	if (entry->next)
		entry->next->prev = entry->prev;

	/* Release resources */
	if (__builtin_expect(!!(obj->usage), 1))
		put(obj);
	list->entries--;
	kfree(entry);
	if (list->mode != LIST_LOCKLESS)
		release(&list->lock);
}

/* Pop the first Object in a List */
void *
pop_from_start(ObjectList *list)
{
	if (!list->start)
		return NULL;
	if (list->mode != LIST_LOCKLESS)
		acquire(&list->lock);
	Object *head = get(list->start->obj);
	remove(list, head);
	if (list->mode != LIST_LOCKLESS)
		release(&list->lock);
	return head;
}

/* Pop the last Object in a List */
void *
pop_from_end(ObjectList *list)
{
	if (!list->end)
		return NULL;
	if (list->mode != LIST_LOCKLESS)
		acquire(&list->lock);
	Object *tail = get(list->end->obj);
	remove(list, tail);
	if (list->mode != LIST_LOCKLESS)
		release(&list->lock);
	return tail;
}

/* Count the number of Objects in a List */
size_t
count(ObjectList *list)
{
	return list->entries;
}

/* Get the nth Object in a List */
void *
get_nth_item(ObjectList *list, off_t n)
{
	if (n > list->entries - 1)
		return NULL;

	struct ListEntry *entry;
	if (n < (list->entries >> 1)) {
		for (entry = list->start; entry; entry = entry->next)
			if (n-- == 0)
				break;
	} else {
		n = list->entries - 1 - n;
		for (entry = list->end; entry; entry = entry->prev)
			if (n-- == 0)
				break;
	}
	return entry->obj;
}

/* Copy list */
ObjectList *
copy_list(ObjectList *list)
{
	ObjectList *newlist = create_list(list->type, list->mode,
	                                  list->compare);
	if (list->mode != LIST_LOCKLESS)
		acquire(&list->lock);
	struct ListEntry *entry;
	for (entry = list->start; entry; entry = entry->next)
		add(newlist, entry->obj);
	if (list->mode != LIST_LOCKLESS)
		release(&list->lock);
	return newlist;
}

/* Concatenate one list onto the end of another */
void
concat_list(ObjectList *src, ObjectList *dest)
{
	if (src->mode != LIST_LOCKLESS)
		acquire(&src->lock);
	struct ListEntry *entry;
	for (entry = src->start; entry; entry = entry->next)
		add(dest, entry->obj);
	if (src->mode != LIST_LOCKLESS)
		release(&src->lock);
}

/* Iterate a List */
Iterator *
iterate(ObjectList *list)
{
	Iterator *i = kmalloc(sizeof(Iterator));
	i->list = list;
	return i;
}

/* Get first iteratable element */
void *
first(Iterator *iter)
{
	iter->entry = iter->list->start;
	if (iter->entry) {
		iter->next = iter->entry->next;
		iter->pos = 0;
		return iter->entry->obj;
	}
	return NULL;
}

/* Get last iteratable element */
void *
last(Iterator *iter)
{
	iter->entry = iter->list->end;
	if (iter->entry) {
		iter->prev = iter->entry->prev;
		iter->pos = iter->list->entries - 1;
		return iter->entry->obj;
	}
	return NULL;
}

/* Get next iteratable element */
void *
next(Iterator *iter)
{
	iter->entry = iter->next;
	if (iter->entry) {
		iter->prev = iter->entry->prev;
		iter->next = iter->entry->next;
		iter->pos++;
		return iter->entry->obj;
	}
	return NULL;
}

/* Get previous iteratable element */
void *
prev(Iterator *iter)
{
	iter->entry = iter->prev;
	if (iter->entry) {
		iter->prev = iter->entry->prev;
		iter->next = iter->entry->next;
		iter->pos--;
		return iter->entry->obj;
	}
	return NULL;
}

/* End iteration */
int
done_iterating(Iterator *iter)
{
	kfree(iter);
	return 0;
}