[BACK]Return to object.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / ipc

File: [local] / prex-old / sys / ipc / object.c (download)

Revision 1.1, Tue Jun 3 09:38:46 2008 UTC (15 years, 11 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*-
 * Copyright (c) 2005-2007, Kohsuke Ohtani
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * object.c - object service
 */

/*
 * An object represents service, state, or policies etc. To manipulate
 * objects, kernel provide 3 functions: create, delete, lookup.
 * Prex task will create an object to provide its interface to other
 * tasks. The tasks will communicate by sending a message to the object
 * each other. For example, a server task creates some objects and client
 * task will send a request message to it.
 *
 * A substance of object is stored in kernel space, and it is protected
 * from user mode code. Each object data is managed with the hash table
 * by using its name string. Usually, an object has a unique name within
 * a system. Before a task sends a message to the specific object, it must
 * obtain the object ID by looking up the name of the target object.
 *
 * An object can be created without its name. These object can be used as
 * private objects that are used by threads in same task.
 */

#include <kernel.h>
#include <queue.h>
#include <kmem.h>
#include <sched.h>
#include <task.h>
#include <ipc.h>

#define OBJ_MAXBUCKETS	32	/* Size of object hash buckets */

/*
 * Object hash table
 *
 * All objects are hashed by its name string. If an object has no
 * name, it is linked to index zero.
 * The scheduler must be locked when this table is touched.
 */
static struct list obj_table[OBJ_MAXBUCKETS];

/*
 * Calculate the hash index for specified name string.
 * The name can be NULL if the object does not have name.
 */
static u_int
object_hash(const char *name)
{
	u_int h = 0;

	if (name == NULL)
		return 0;
	while (*name)
		h = ((h << 5) + h) + *name++;
	return h & (OBJ_MAXBUCKETS - 1);
}

/*
 * Helper function to find the object from the specified name.
 * Returns NULL if not found.
 */
static object_t
object_find(const char *name)
{
	list_t head, n;
	object_t obj = NULL;

	head = &obj_table[object_hash(name)];
	for (n = list_first(head); n != head; n = list_next(n)) {
		obj = list_entry(n, struct object, name_link);
		ASSERT(obj->magic == OBJECT_MAGIC);
		if (!strncmp(obj->name, name, MAXOBJNAME))
			break;
	}
	if (n == head)
		return NULL;
	return obj;
}

/*
 * Search an object in the object name space. The object name must
 * be null-terminated string. The object ID is returned in obj
 * on success.
 */
int
object_lookup(const char *name, object_t *objp)
{
	object_t obj;
	size_t len;
	char str[MAXOBJNAME];

	if (umem_strnlen(name, MAXOBJNAME, &len))
		return EFAULT;
	if (len == 0 || len >= MAXOBJNAME)
		return ESRCH;
	if (umem_copyin((void *)name, str, len + 1))
		return EFAULT;

	sched_lock();
	obj = object_find(str);
	sched_unlock();

	if (obj == NULL)
		return ENOENT;
	if (umem_copyout(&obj, objp, sizeof(object_t)))
		return EFAULT;
	return 0;
}

/*
 * Create a new object.
 *
 * The ID of the new object is stored in pobj on success.
 * The name of the object must be unique in the system. Or, the
 * object can be created without name by setting NULL as name
 * argument. This object can be used as a private object which
 * can be accessed only by threads in same task.
 */
int
object_create(const char *name, object_t *objp)
{
	object_t obj = 0;
	char str[MAXOBJNAME];
	size_t len;

	if (name != NULL) {
		if (umem_strnlen(name, MAXOBJNAME, &len))
			return EFAULT;
		if (len >= MAXOBJNAME)
			return ENAMETOOLONG;
		if (umem_copyin((void *)name, str, len + 1))
			return EFAULT;
		str[len] = '\0';
	}
	sched_lock();

	/*
	 * Check user buffer first. This can reduce the error
	 * recovery for the subsequence resource allocations.
	 */
	if (umem_copyout(&obj, objp, sizeof(object_t))) {
		sched_unlock();
		return EFAULT;
	}
	if (object_find(str) != NULL) {
		sched_unlock();
		return EEXIST;
	}
	if ((obj = kmem_alloc(sizeof(struct object))) == NULL) {
		sched_unlock();
		return ENOMEM;
	}
	if (name != NULL)
		strlcpy(obj->name, str, len + 1);

	queue_init(&obj->sendq);
	queue_init(&obj->recvq);
	obj->owner = cur_task();
	obj->magic = OBJECT_MAGIC;
	list_insert(&obj_table[object_hash(name)], &obj->name_link);
	list_insert(&(cur_task()->objects), &obj->task_link);

	umem_copyout(&obj, objp, sizeof(object_t));
	sched_unlock();
	return 0;
}

/*
 * Destroy an object.
 *
 * A thread can delete the object only when the target object is
 * created by the thread of the same task.
 * All pending messages related to the deleted object are
 * automatically canceled.
 */
int
object_destroy(object_t obj)
{
	int err = 0;

	sched_lock();
	if (!object_valid(obj)) {
		err = EINVAL;
	}
	else if (obj->owner != cur_task()) {
		err = EACCES;
	}
	else {
		obj->magic = 0;
		msg_cancel(obj);
		list_remove(&obj->task_link);
		list_remove(&obj->name_link);
		kmem_free(obj);
	}
	sched_unlock();
	return err;
}

#if defined(DEBUG) && defined(CONFIG_KDUMP)
void
object_dump(void)
{
	int i;
	list_t head, n;
	object_t obj;

	printk("Object dump:\n");
	printk(" object   owner task name\n");
	printk(" -------- ---------- ----------------\n");

	for (i = 0; i < OBJ_MAXBUCKETS; i++) {
		head = &obj_table[i];
		for (n = list_first(head); n != head; n = list_next(n)) {
			obj = list_entry(n, struct object, name_link);
			printk(" %08x %08x   %s\n", obj, obj->owner,
			       (obj->name ? obj->name : "NoName"));
		}
	}
}
#endif

void
object_init(void)
{
	int i;

	for (i = 0; i < OBJ_MAXBUCKETS; i++)
		list_init(&obj_table[i]);
}