File: [local] / prex / sys / ipc / object.c (download)
Revision 1.1.1.1 (vendor branch), Tue Aug 19 12:46:56 2008 UTC (15 years, 10 months ago) by nbrk
Branch: MAIN, KOHSUKE
CVS Tags: PREX_0_8_BASE, HEAD Changes since 1.1: +0 -0 lines
Initial import of Prex, Portable Real-time Embedded POSIX microkernel system.
I have totally new directions in my development (more focused on real hardware, not virtual one).
Old hacks are available in prex-old module. They will be carefully re-designed and merged soon.
|
/*-
* 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
*/
/*
* General Design:
*
* 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 its
* 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, hash_link);
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(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];
task_t self;
size_t len = 0;
if (name != NULL) {
if (umem_strnlen(name, MAXOBJNAME, &len))
return EFAULT;
if (len >= MAXOBJNAME)
return ENAMETOOLONG;
if (umem_copyin(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);
self = cur_task();
obj->owner = self;
obj->magic = OBJECT_MAGIC;
queue_init(&obj->sendq);
queue_init(&obj->recvq);
list_insert(&obj_table[object_hash(name)], &obj->hash_link);
list_insert(&self->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->hash_link);
kmem_free(obj);
}
sched_unlock();
return err;
}
void
object_init(void)
{
int i;
for (i = 0; i < OBJ_MAXBUCKETS; i++)
list_init(&obj_table[i]);
}