xenomai内核解析---内核对象注册表—xnregistry(重要组件)

1. 概述

上篇文章xenomai内核解析--同步互斥机制(一)--优先级倒置讲到,对于全部内核对象:html

xnregistry:保存内核对象,提供内核对象存储和快速检索。node

xnsynch:资源抽象,提供线程与资源的同步互斥管理机制。linux

举个应用例子,有两个xenoami任务,使用semaphore作互斥,任务1建立一个名为/test-sem的semaphore,任务2打开这个semaphore,以这个过程为例,带你了解xnregistry。dom

/*任务1*/
    sem_t *dome_sem;
.....
	dome_sem = sem_open("/test-sem", O_CREAT | O_EXCL, 0666, 0);
	if (dome_sem == SEM_FAILED)
			error(1, errno, "sem_open()");
.....
    sem_wait(dome_sem);
.....
	sem_post(dome_sem);
.....
/*任务2*/
    sem_t *dome_sem;
.....
	dome_sem = sem_open("/test-sem", 0);
	if (dome_sem == SEM_FAILED)
			error(1, errno, "sem_open()");
.....
    sem_wait(dome_sem);
.....
	sem_post(dome_sem);
.....
  • 问题1:任务1建立的这个semaphore是如何管理的?
  • 问题2:任务2又是如何经过name找到它的?

本片文章解析xenomai内核中的xnregistry。至于xenomai semaphore具体的内核机制及建立流程,之后文章介绍,敬请关注。post

2. 命名内核对象管理

xnregistry用于保存xenomai全局内核对象。这些对象分为两种,一种有name,经常使用于两个及以上进程间,能够经过name来找到同一对象。另外一种没有name,经常使用于同一进程空间。线程

涉及经过字符串name来查找的内核对象称为命名内核对象,xenomai内核中名内核对象有:有名信号量(sem)、有名消息队列(mq)、进程间经过label相互通信的xddp/bufp/iddp等。code

建立命名对象的时候,orm

  1. 先从register_obj_solts中分配一个xnobject;
  2. 而后将name做为xnobject成员key具体对象(cobalt_sem)的地址做为value保存到xnobject的成员objaddr中。
  3. 向xnregistry中存储该xnobject时,会将name做为key通过hash运算,根据运算获得的hash值s,选择合适的hash bucket,该bucket在xenomai中为object_index[],而后将xnobject插入选定的object_index[s]链表中。
  4. 当另外一个线程open同一name的对象时,经过name可从object_index[]中快速获得该内核对象。

name只在建立和经过name查找时使用,一个对象经过name查找或建立后会保存一个xnhandlet,后续操做使用xnhandlet代替,提升xnobjet的访问速度。htm

建立时注册cobalt_sem流程以下所示。对象

xnregister-semopen

  • register_obj_solts用于保存型号量这个xnobject,上面的问题1.
  • object_index用于检索,上面的问题2。

咱们接着来看建立后保存的这个xnhandlet,cobalt_sem建立完成后会保存xnhandlet到信号量句柄sem_t中,并拷贝到用户空间,咱们能够来看一下libcobalt中的句柄sem_t的形式:

struct cobalt_sem_shadow {
    __u32 magic;
    __s32 state_offset;
    xnhandle_t handle;
} shadow_sem;

从上面图中咱们能够看到xnhandlet是一个偏移量,表示这个xnobject基于register_obj_solts的地址偏移,为何要直接保存到句柄sem_t中呢?sem_wait()/sem_post()操做进入内核的时候就能够直接去获取xnobject作相应的操做了。

另外想一下,一个运行在用户态的实时应用,每次PV操做的时候都须要执行系统调用,对实时系统来讲不太友好,毕竟系统调用也是须要花费时间的,xnhandlet只能解决内核里定位xnobject的速度问题,咱们能不能不要每次都执行系统调用呢?答案是确定的,xenomai有相应的机制,请关注后续文章,呵呵~~。

3. 未命名内核对象管理

上面说完了命名内核对象,下面来看未命名内核对象,即非跨进程共享的。

对于没有name的内核对象,经过xnregistry提供的匿名接口来保存。所谓的匿名保存,key为NULL,具体对象(cobalt_sem)的地址做为value到一个分配的结构体xnobject后,不经hash运算,直接计算xnobject基于某个固定地址的偏移量xnhandle_t,一般xnhandle_t会在用户空间的对象结构体中保存一份,好比sem_t、pthread_mutex_t等;以后用户空间对该对象发起系统调用时就能够经过xnhandle_t快速从xnregistry获取该对象,使用匿名的内核对象有:进程间的互斥量mutex、未命名信号量sem、条件变量condition variable、事件event、monitor。

一样以未命名信号量为例,内核对象cobalt_sem注册流程以下。

xnregister-seminit

4. xnregistry初始化流程

图中resitry_obj_slots[]其大小内核构建时CONFIG_XENO_OPT_REGISTRY_NRSLOTS指定,默认大小512,具体内存在xenomai初始化时调用xnregistry_init()初始化xnregistry时分配。

static int __init xenomai_init(void)
    ->sys_init()
    	->xnregistry_init()

xnregistry_init()具体流程以下。

int xnregistry_init(void)
{
	int n, ret __maybe_unused;

	registry_obj_slots = kmalloc(CONFIG_XENO_OPT_REGISTRY_NRSLOTS *
				     sizeof(struct xnobject), GFP_KERNEL);
	.....
#ifdef CONFIG_XENO_OPT_VFILE
	ret = xnvfile_init_dir("registry", &registry_vfroot, &cobalt_vfroot);
	ret = xnvfile_init_regular("usage", &usage_vfile, &registry_vfroot);
 	proc_apc = xnapc_alloc("registry_export", &registry_proc_schedule, NULL);
#endif /* CONFIG_XENO_OPT_VFILE */
	next_object_stamp = 0;

	for (n = 0; n < CONFIG_XENO_OPT_REGISTRY_NRSLOTS; n++) {
		registry_obj_slots[n].objaddr = NULL;
		list_add_tail(&registry_obj_slots[n].link,
                      &free_object_list);
	}
	/* Slot #0 is reserved/invalid. */
	list_get_entry(&free_object_list, struct xnobject, link);
	nr_active_objects = 1;

	nr_object_entries = xnregistry_hash_size();
	object_index = kmalloc(sizeof(*object_index) *
				      nr_object_entries, GFP_KERNEL);
    
	for (n = 0; n < nr_object_entries; n++)
		INIT_HLIST_HEAD(&object_index[n]);
    
	xnsynch_init(&register_synch, XNSYNCH_FIFO, NULL);
	return 0;
}

1.先分配CONFIG_XENO_OPT_REGISTRY_NRSLOTS个xnobject的空间,xenomai运行过程当中的xnobject从registry_obj_slots中直接获取,这样就避免频繁的内存申请影响实时性。struct xnobject结构以下:

struct xnobject {
	void *objaddr;
	const char *key;	  /* !< Hash key. May be NULL if anonynous. */
	unsigned long cstamp;		  /* !< Creation stamp. */
#ifdef CONFIG_XENO_OPT_VFILE
	struct xnpnode *pnode;	/* !< v-file information class. */
	union {
		struct {
			struct xnvfile_rev_tag tag;
			struct xnvfile_snapshot file;
		} vfsnap; /* !< virtual snapshot file. */
		struct xnvfile_regular vfreg; /* !< virtual regular file */
		struct xnvfile_link link;     /* !< virtual link. */
	} vfile_u;
	struct xnvfile *vfilp;
#endif /* CONFIG_XENO_OPT_VFILE */
	struct hlist_node hlink; /* !< Link in h-table */
	struct list_head link;
};

objaddr指向具体的内核对象,如cobalt_semcobalt_mutex等。

*key 对象的name或label,用户程序可以使用name来操做内核对象,具备name的内核对象会保存到一个hash表中,方便经过name查找。若是key为NULL,则不用。

vfilpvfile_upnode 注册到linux虚拟文件系统经常使用变量。

hlink用于加入hash链表。

link 该对象若是未使用则用于加入空闲链表free_object_list,不然用于加入已使用链表busy_object_list。

  1. 在linux虚拟文件系统proc目录下建立registry目录,以及文件usage,注册后可经过/proc/xenomai/registry/usage查看xnobject的使用状况。
$ cat /proc/xenomai/registry/usage 
7/512
  1. 将刚分配的空闲xnobject插入free_object_list链表。
  2. 将free_object_list的第一个xnobject节点保留,记录xnobject已使用数nr_active_objects。
  3. 分配散列表object_index[]的空间,并初始化。
  4. 初始化registry资源同步对象register_synch,register_synch

5. xnregistry总结

xnregistry:保存内核对象,提供内核对象存储和快速检索。

xnsynch:资源抽象,提供线程与资源的同步互斥管理机制。

xnsynchxnregistry是xenomai内核机制很是重要的组件,明白他们xenomai的资源管理机制就明白大半了。

相关文章
相关标签/搜索