kobj顾名思意,即内核object,其层次表现上为一颗倒置的树,用来管理包括各种驱动模块,核心组件,运行时状态等。在文件系统中,通过sysfs接口绑定kobj节点,来实现对该节点的读写操作。sysfs接口有两种最基本的用途:1,组件的外部操作接口,比如应用可以通过此接口操作设备。2,调试驱动模块,或查看运行时状态。</span>
实现kobj可以对任何形态的组件实现高度抽象,是各种组件的基石,系统中提供了一组API,以方便管理kobj。理解kobj,对后面理解xboot中的各种组件而言有相当大的帮助,建议细心阅读。
kobj有两种基本类型,一个是目录,其可以挂接子节点,另一个是文件,代表一颗树的末端,不可拥有子节点,但提供了读或者写该节点的操作,声明如下:
enum kobj_type_t {
KOBJ_TYPE_DIR,
KOBJ_TYPE_REG,
};
kobj结构体拥有名字,节点类型,父节点指针,当前节点链表,子节点链表头,节点锁,读写接口函数及一个私有数据指针,详细定义如下:
struct kobj_t
{
/* kobj name */
char * name;
/* kobj type DIR or REG */
enum kobj_type_t type;
/* kobj's parent */
struct kobj_t * parent;
/* kobj's entry */
struct list_head entry;
/* kobj's children */
struct list_head children;
/* kobj lock */
spinlock_t lock;
/* kobj read */
ssize_t (*read)(struct kobj_t * kobj, void * buf, size_t size);
/* kobj write */
ssize_t (*write)(struct kobj_t * kobj, void * buf, size_t size);
/* private data */
void * priv;
};
其为一内部函数,主要是分配一段内存,然后利用传递的参数进行初始化,并返回分配的kobj节点。
static struct kobj_t * __kobj_alloc(const char * name, enum kobj_type_t type, kobj_read_t read, kobj_write_t write, void * priv)
{
struct kobj_t * kobj;
if(!name)
return NULL;
kobj = malloc(sizeof(struct kobj_t));
if(!kobj)
return NULL;
kobj->name = strdup(name);
kobj->type = type;
kobj->parent = kobj;
init_list_head(&kobj->entry);
init_list_head(&kobj->children);
spin_lock_init(&kobj->lock);
kobj->read = read;
kobj->write = write;
kobj->priv = priv;
return kobj;
}
struct kobj_t * kobj_alloc_directory(const char * name)
{
return __kobj_alloc(name, KOBJ_TYPE_DIR, NULL, NULL, NULL);
}
struct kobj_t * kobj_alloc_regular(const char * name, kobj_read_t read, kobj_write_t write, void * priv)
{
return __kobj_alloc(name, KOBJ_TYPE_REG, read, write, priv);
}
将动态分配的内存进行回收,实现如下:
bool_t kobj_free(struct kobj_t * kobj)
{
if(!kobj)
return FALSE;
free(kobj->name);
free(kobj);
return TRUE;
}
struct kobj_t * kobj_search(struct kobj_t * parent, const char * name)
{
struct kobj_t * pos, * n;
if(!parent)
return NULL;
if(parent->type != KOBJ_TYPE_DIR)
return NULL;
if(!name)
return NULL;
list_for_each_entry_safe(pos, n, &(parent->children), entry)
{
if(strcmp(pos->name, name) == 0)
return pos;
}
return NULL;
}
struct kobj_t * kobj_search_directory_with_create(struct kobj_t * parent, const char * name)
{
struct kobj_t * kobj;
if(!parent)
return NULL;
if(parent->type != KOBJ_TYPE_DIR)
return NULL;
if(!name)
return NULL;
kobj = kobj_search(parent, name);
if(!kobj)
{
kobj = kobj_alloc_directory(name);
if(!kobj)
return NULL;
if(!kobj_add(parent, kobj))
{
kobj_free(kobj);
return NULL;
}
}
else if(kobj->type != KOBJ_TYPE_DIR)
{
return NULL;
}
return kobj;
}
bool_t kobj_add(struct kobj_t * parent, struct kobj_t * kobj)
{
if(!parent)
return FALSE;
if(parent->type != KOBJ_TYPE_DIR)
return FALSE;
if(!kobj)
return FALSE;
if(kobj_search(parent, kobj->name))
return FALSE;
spin_lock_irq(&parent->lock);
spin_lock_irq(&kobj->lock);
kobj->parent = parent;
list_add_tail(&kobj->entry, &parent->children);
spin_unlock_irq(&kobj->lock);
spin_unlock_irq(&parent->lock);
return TRUE;
}
bool_t kobj_remove(struct kobj_t * parent, struct kobj_t * kobj)
{
struct kobj_t * pos, * n;
if(!parent)
return FALSE;
if(parent->type != KOBJ_TYPE_DIR)
return FALSE;
if(!kobj)
return FALSE;
list_for_each_entry_safe(pos, n, &(parent->children), entry)
{
if(pos == kobj)
{
spin_lock_irq(&parent->lock);
spin_lock_irq(&kobj->lock);
pos->parent = pos;
list_del(&(pos->entry));
spin_unlock_irq(&kobj->lock);
spin_unlock_irq(&parent->lock);
return TRUE;
}
}
return FALSE;
}
bool_t kobj_add_directory(struct kobj_t * parent, const char * name)
{
struct kobj_t * kobj;
if(!parent)
return FALSE;
if(parent->type != KOBJ_TYPE_DIR)
return FALSE;
if(!name)
return FALSE;
if(kobj_search(parent, name))
return FALSE;
kobj = kobj_alloc_directory(name);
if(!kobj)
return FALSE;
if(!kobj_add(parent, kobj))
kobj_free(kobj);
return TRUE;
}
bool_t kobj_add_regular(struct kobj_t * parent, const char * name, kobj_read_t read, kobj_write_t write, void * priv)
{
struct kobj_t * kobj;
if(!parent)
return FALSE;
if(parent->type != KOBJ_TYPE_DIR)
return FALSE;
if(!name)
return FALSE;
if(kobj_search(parent, name))
return FALSE;
kobj = kobj_alloc_regular(name, read, write, priv);
if(!kobj)
return FALSE;
if(!kobj_add(parent, kobj))
kobj_free(kobj);
return TRUE;
}
bool_t kobj_remove_self(struct kobj_t * kobj)
{
struct kobj_t * parent;
struct kobj_t * pos, * n;
bool_t ret;
if(!kobj)
return FALSE;
if(kobj->type == KOBJ_TYPE_DIR)
{
list_for_each_entry_safe(pos, n, &(kobj->children), entry)
{
kobj_remove_self(pos);
}
}
parent = kobj->parent;
if(parent && (parent != kobj))
{
ret = kobj_remove(parent, kobj);
if(ret)
kobj_free(kobj);
return ret;
}
kobj_free(kobj);
return TRUE;
}
系统启动时,会自动创建一个根节点,名为"kobj",该节点为一个全局静态变量,是顶层目录节点,在mount文件系统时会挂接到sysfs接口。
void do_init_kobj(void)
{
__kobj_root = kobj_alloc_directory("kobj");
}
struct kobj_t * kobj_get_root(void);
struct kobj_t * kobj_search(struct kobj_t * parent, const char * name);
struct kobj_t * kobj_search_directory_with_create(struct kobj_t * parent, const char * name);
struct kobj_t * kobj_alloc_directory(const char * name);
struct kobj_t * kobj_alloc_regular(const char * name, kobj_read_t read, kobj_write_t write, void * priv);
bool_t kobj_free(struct kobj_t * kobj);
bool_t kobj_add(struct kobj_t * parent, struct kobj_t * kobj);
bool_t kobj_remove(struct kobj_t * parent, struct kobj_t * kobj);
bool_t kobj_add_directory(struct kobj_t * parent, const char * name);
bool_t kobj_add_regular(struct kobj_t * parent, const char * name, kobj_read_t read, kobj_write_t write, void * priv);
bool_t kobj_remove_self(struct kobj_t * kobj);