/*- * 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 #include #include #include #include #include #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]); }