内核对象基类object
这个基类是内核所有对象的基类
在rt-thread/include/rtdef.h文件里有对内核对象基类object的定义
/**
* Base structure of Kernel object
*/
struct rt_object
{
char name[RT_NAME_MAX]; /**< name of kernel object */
rt_uint8_t type; /**< type of kernel object */
rt_uint8_t flag; /**< flag of kernel object */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< list node of kernel object */
};
typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */
object属性有 内核对象名字 , 内核对象类型 , 内核对象标志,还有一个链表节点。
内核对象信息结构体
/**
* The information of the kernel object
*/
struct rt_object_information
{
enum rt_object_class_type type; /**< object class type */
rt_list_t object_list; /**< object list */
rt_size_t object_size; /**< object size */
};
其中rt_object_class_type是一个枚举类型,定义如下
/**
* The object type can be one of the follows with specific
* macros enabled:
* - Thread
* - Semaphore
* - Mutex
* - Event
* - MailBox
* - MessageQueue
* - MemHeap
* - MemPool
* - Device
* - Timer
* - Module
* - Unknown
* - Static
*/
enum rt_object_class_type
{
RT_Object_Class_Null = 0x00, /**< The object is not used. */
RT_Object_Class_Thread = 0x01, /**< The object is a thread. */
RT_Object_Class_Semaphore = 0x02, /**< The object is a semaphore. */
RT_Object_Class_Mutex = 0x03, /**< The object is a mutex. */
RT_Object_Class_Event = 0x04, /**< The object is a event. */
RT_Object_Class_MailBox = 0x05, /**< The object is a mail box. */
RT_Object_Class_MessageQueue = 0x06, /**< The object is a message queue. */
RT_Object_Class_MemHeap = 0x07, /**< The object is a memory heap. */
RT_Object_Class_MemPool = 0x08, /**< The object is a memory pool. */
RT_Object_Class_Device = 0x09, /**< The object is a device. */
RT_Object_Class_Timer = 0x0a, /**< The object is a timer. */
RT_Object_Class_Module = 0x0b, /**< The object is a module. */
RT_Object_Class_Memory = 0x0c, /**< The object is a memory. */
RT_Object_Class_Unknown = 0x0e, /**< The object is unknown. */
RT_Object_Class_Static = 0x80 /**< The object is a static object. */
};
有我们常见的线程,信号量等等,最后一个静态类型 就是 第一位 置1。
这里我们只关注 设备类 ,也就是 RT_Object_Class_Device
它们之间具体是个什么关系呢
具体我们来看rt-thread/src/object.c文件
对象容器
对象容器就是一个rt_object_information类型的数组,数组名_object_container,数组长度为RT_Object_Info_Unknown,这个数组中的每个值都是rt_object_information类型。
static struct rt_object_information _object_container[RT_Object_Info_Unknown] =
{
/* initialize object container - thread */
{RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
#ifdef RT_USING_SEMAPHORE
/* initialize object container - semaphore */
{RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
#endif
#ifdef RT_USING_MUTEX
/* initialize object container - mutex */
{RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
/* initialize object container - event */
{RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
/* initialize object container - mailbox */
{RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif
#ifdef RT_USING_MESSAGEQUEUE
/* initialize object container - message queue */
{RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif
#ifdef RT_USING_MEMHEAP
/* initialize object container - memory heap */
{RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif
#ifdef RT_USING_MEMPOOL
/* initialize object container - memory pool */
{RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif
#ifdef RT_USING_DEVICE
/* initialize object container - device */
{RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
/* initialize object container - timer */
{RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
#ifdef RT_USING_MODULE
/* initialize object container - module */
{RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
#endif
#ifdef RT_USING_HEAP
/* initialize object container - small memory */
{RT_Object_Class_Memory, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Memory), sizeof(struct rt_memory)},
#endif
};
这个容器(数组)到底有多大呢,也就是RT_Object_Info_Unknown为几呢?
还是在object.c文件中有一个枚举类型定义rt_object_info_type我们来看一下它。
/*
* define object_info for the number of _object_container items.
*/
enum rt_object_info_type
{
RT_Object_Info_Thread = 0, /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
RT_Object_Info_Semaphore, /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
RT_Object_Info_Mutex, /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
RT_Object_Info_Event, /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
RT_Object_Info_MailBox, /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
RT_Object_Info_MessageQueue, /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
RT_Object_Info_MemHeap, /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
RT_Object_Info_MemPool, /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
RT_Object_Info_Device, /**< The object is a device */
#endif
RT_Object_Info_Timer, /**< The object is a timer. */
#ifdef RT_USING_MODULE
RT_Object_Info_Module, /**< The object is a module. */
#endif
#ifdef RT_USING_HEAP
RT_Object_Info_Memory, /**< The object is a memory. */
#endif
RT_Object_Info_Unknown, /**< The object is unknown. */
};
可以看到是由宏定义决定的,宏定义在rtconfig.h文件中。
在这个枚举类型中RT_Object_Info_Thread,RT_Object_Info_Timer,RT_Object_Info_Unknown, 是必然有的。而且RT_Object_Info_Unknown放在最后一个位置。
那么我们现在定义了RT_USING_DEVICE,开启设备类。那么这个枚举类型中一共有四个元素,所以RT_Object_Info_Unknown = 3。
然后 对象容器的长度 就也为3 。里面分别有线程,定时器,还有设备的对象信息rt_object_information。
这个容器直接进行了初试化,每个元素的第二个成员也就是链表通过宏,指向本身进行初始化,也就是这个链表头(哨卫)前后都指向本身。这个链表用来链接同类的对象,后面会学习到。
#define _OBJ_CONTAINER_LIST_INIT(c) \
{&(_object_container[c].object_list), &(_object_container[c].object_list)}
内核对象函数
rt_object_get_information
/**
* @brief This function will return the specified type of object information.
*
* @param type is the type of object, which can be
* RT_Object_Class_Thread/Semaphore/Mutex... etc
*
* @return the object type information or RT_NULL
*/
struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
{
int index;
for (index = 0; index < RT_Object_Info_Unknown; index ++)
if (_object_container[index].type == type) return &_object_container[index];
return RT_NULL;
}
这个函数用于获取对象的类型信息,输入值是rt_object_class_type ,返回值是rt_object_information 指针。它们俩的关系是rt_object_class_type 是rt_object_information 的第一个成员。也就是说通过类型来获取这个类型的对象的具体信息(后面为了要链表)。
它是咋实现的呢。
通过遍历对象容器_object_container来实现。
rt_object_get_length
/**
* @brief This function will return the length of object list in object container.
*
* @param type is the type of object, which can be
* RT_Object_Class_Thread/Semaphore/Mutex... etc
*
* @return the length of object list
*/
int rt_object_get_length(enum rt_object_class_type type)
{
int count = 0;
rt_ubase_t level;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
information = rt_object_get_information((enum rt_object_class_type)type);
if (information == RT_NULL) return 0;
level = rt_hw_interrupt_disable();
/* get the count of objects */
rt_list_for_each(node, &(information->object_list))
{
count ++;
}
rt_hw_interrupt_enable(level);
return count;
}
这个函数用于获取对象链表的长度,输入值是rt_object_class_type ,也就是哪一类对象,然后获取这类对象上的链表链接的长度。
rt_list_for_each是一个宏,用来遍历链表。
/**
* rt_list_for_each - iterate over a list
* @pos: the rt_list_t * to use as a loop cursor.
* @head: the head for your list.
*/
#define rt_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
具体实现:先获取类型的对象信息,对象信息里有一个链表节点,这个节点是链表头(哨卫),从次开始遍历链表,从而获取链表长度,注意这个长度是不包含哨卫的。
rt_object_get_pointers
/**
* @brief This function will copy the object pointer of the specified type,
* with the maximum size specified by maxlen.
*
* @param type is the type of object, which can be
* RT_Object_Class_Thread/Semaphore/Mutex... etc
*
* @param pointers is the pointer will be saved to.
*
* @param maxlen is the maximum number of pointers can be saved.
*
* @return the copied number of object pointers.
*/
int rt_object_get_pointers(enum rt_object_class_type type, rt_object_t *pointers, int maxlen)
{
int index = 0;
rt_ubase_t level;
struct rt_object *object;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
if (maxlen <= 0) return 0;
information = rt_object_get_information((enum rt_object_class_type)type);
if (information == RT_NULL) return 0;
level = rt_hw_interrupt_disable();
/* retrieve pointer of object */
rt_list_for_each(node, &(information->object_list))
{
object = rt_list_entry(node, struct rt_object, list);
pointers[index] = object;
index ++;
if (index >= maxlen) break;
}
rt_hw_interrupt_enable(level);
return index;
}
首先看一下register关键字:register用于向编译器建议将变量存储在寄存器中,而不是存储在内存中。寄存器是CPU内部的高速存储单元,访问速度比内存快得多。因此,使用register关键字可以提高变量的访问速度,从而提高程序的执行效率。不能对register变量使用取地址运算符&,因为寄存器没有内存地址。register变量的作用域和生命周期与普通变量相同,但它们不能用于全局变量。
这个函数用于获取对象的指针,看一下咋实现的。先使用函数rt_object_get_information获取对象的类型信息,然后遍历这个内核对象的类型信息上链接的链表节点。(比如对于设备类,设备类有一个信息结构体,然后这个结构体中的链表挂载这设备类的对象设备1,设备2…)遍历链表节点,然后rt_list_entry通过链表节点得到这个节点所在的对象,其实就是在遍历这个链表上挂载的对象,然后把它放在我们传进来的参数pointers指针里面,(这里可以简单的把指针当做数组了),然后存够maxlen就可以了,返回值也是存的个数,其实也就是maxlen。
rt_object_init
/**
* @brief This function will initialize an object and add it to object system
* management.
*
* @param object is the specified object to be initialized.
*
* @param type is the object type.
*
* @param name is the object name. In system, the object's name must be unique.
*/
void rt_object_init(struct rt_object *object,
enum rt_object_class_type type,
const char *name)
{
register rt_base_t temp;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information;
#ifdef RT_USING_MODULE
struct rt_dlmodule *module = dlmodule_self();
#endif /* RT_USING_MODULE */
/* get object information */
information = rt_object_get_information(type);
RT_ASSERT(information != RT_NULL);
/* check object type to avoid re-initialization */
/* enter critical */
rt_enter_critical();
/* try to find object */
for (node = information->object_list.next;
node != &(information->object_list);
node = node->next)
{
struct rt_object *obj;
obj = rt_list_entry(node, struct rt_object, list);
if (obj) /* skip warning when disable debug */
{
RT_ASSERT(obj != object);
}
}
/* leave critical */
rt_exit_critical();
/* initialize object's parameters */
/* set object type to static */
object->type = type | RT_Object_Class_Static;
/* copy name */
rt_strncpy(object->name, name, RT_NAME_MAX);
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
/* lock interrupt */
temp = rt_hw_interrupt_disable();
#ifdef RT_USING_MODULE
if (module)
{
rt_list_insert_after(&(module->object_list), &(object->list));
object->module_id = (void *)module;
}
else
#endif /* RT_USING_MODULE */
{
/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));
}
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
}
这个函数很重要了,它用来初始化对象并把它放在对象系统中,也就是把它挂载到对象容器的对象信息结构体的链表中。
来看具体实现,首先传进来具体的对象rt_object,还有它的类型rt_object_class_type ,还有它的名字(这个名字要唯一),通过类型找到信息结构体。
下一步是检查有没有重复定义,遍历链表节点,RT_ASSERT(obj != object);这句话是括号里的内容为真时才会继续往下执行,也就是两个对象指针不相当,确保链表里没有这个对象。
下一步就是初始化这个对象的参数, object->type = type | RT_Object_Class_Static;将它的类型,或上RT_Object_Class_Static,也就是第一位置1。然后复制名字。
最后把这个对象插入在信息结构体的链表里,初始化结束。
rt_strncpy(object->name, name, RT_NAME_MAX);
这个函数用于将name复制给object->name。
rt_object_detach
/**
* @brief This function will detach a static object from object system,
* and the memory of static object is not freed.
*
* @param object the specified object to be detached.
*/
void rt_object_detach(rt_object_t object)
{
register rt_base_t temp;
/* object check */
RT_ASSERT(object != RT_NULL);
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
/* reset object type */
object->type = 0;
/* lock interrupt */
temp = rt_hw_interrupt_disable();
/* remove from old list */
rt_list_remove(&(object->list));
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
}
这个函数用于在对象系统中移除指定对象,但是静态对象不会被释放内存,仅仅是将它在链表中移除。
它的实现也很简单,先复位它的类型,然后将它在链表里移除就可以了。
rt_object_allocate
如果使用HEAP,#ifdef RT_USING_HEAP ,则有这两个函数rt_object_allocate和rt_object_delete
/**
* @brief This function will allocate an object from object system.
*
* @param type is the type of object.
*
* @param name is the object name. In system, the object's name must be unique.
*
* @return object
*/
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
{
struct rt_object *object;
register rt_base_t temp;
struct rt_object_information *information;
#ifdef RT_USING_MODULE
struct rt_dlmodule *module = dlmodule_self();
#endif /* RT_USING_MODULE */
RT_DEBUG_NOT_IN_INTERRUPT;
/* get object information */
information = rt_object_get_information(type);
RT_ASSERT(information != RT_NULL);
object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size);
if (object == RT_NULL)
{
/* no memory can be allocated */
return RT_NULL;
}
/* clean memory data of object */
rt_memset(object, 0x0, information->object_size);
/* initialize object's parameters */
/* set object type */
object->type = type;
/* set object flag */
object->flag = 0;
/* copy name */
rt_strncpy(object->name, name, RT_NAME_MAX);
RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
/* lock interrupt */
temp = rt_hw_interrupt_disable();
#ifdef RT_USING_MODULE
if (module)
{
rt_list_insert_after(&(module->object_list), &(object->list));
object->module_id = (void *)module;
}
else
#endif /* RT_USING_MODULE */
{
/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));
}
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
/* return object */
return object;
}
如果使用HEAP才会有这个函数,它和rt_object_init是一样的,只是传参数的时候,无需传*object。在这个函数里是通过对象信息结构体中的对象大小来在系统中分配内存object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size);
其它实现是一样的。好像这就是静态初始化和动态初始化的区别吧。
rt_object_delete
/**
* @brief This function will delete an object and release object memory.
*
* @param object is the specified object to be deleted.
*/
void rt_object_delete(rt_object_t object)
{
register rt_base_t temp;
/* object check */
RT_ASSERT(object != RT_NULL);
RT_ASSERT(!(object->type & RT_Object_Class_Static));
RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
/* reset object type */
object->type = RT_Object_Class_Null;
/* lock interrupt */
temp = rt_hw_interrupt_disable();
/* remove from old list */
rt_list_remove(&(object->list));
/* unlock interrupt */
rt_hw_interrupt_enable(temp);
/* free the memory of object */
RT_KERNEL_FREE(object);
}
这个函数和rt_object_detach相似,区别就是它会释放内存。
rt_object_is_systemobject
/**
* @brief This function will judge the object is system object or not.
*
* @note Normally, the system object is a static object and the type
* of object set to RT_Object_Class_Static.
*
* @param object is the specified object to be judged.
*
* @return RT_TRUE if a system object, RT_FALSE for others.
*/
rt_bool_t rt_object_is_systemobject(rt_object_t object)
{
/* object check */
RT_ASSERT(object != RT_NULL);
if (object->type & RT_Object_Class_Static)
return RT_TRUE;
return RT_FALSE;
}
这个函数用于判断对象是否在对象系统中,它的实现很简单,和RT_Object_Class_Static做按位与,就是判断对象的类型的最高位是否为1。
rt_object_get_type
/**
* @brief This function will return the type of object without
* RT_Object_Class_Static flag.
*
* @param object is the specified object to be get type.
*
* @return the type of object.
*/
rt_uint8_t rt_object_get_type(rt_object_t object)
{
/* object check */
RT_ASSERT(object != RT_NULL);
return object->type & ~RT_Object_Class_Static;
}
这个函数用于获取对象的类型,因为对象初始化后,类型的最高位都置1了,所以获取它原来的类型值,这里就将最高位置0,其他位保留。
rt_object_find
/**
* @brief This function will find specified name object from object
* container.
*
* @param name is the specified name of object.
*
* @param type is the type of object
*
* @return the found object or RT_NULL if there is no this object
* in object container.
*
* @note this function shall not be invoked in interrupt status.
*/
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
{
struct rt_object *object = RT_NULL;
struct rt_list_node *node = RT_NULL;
struct rt_object_information *information = RT_NULL;
information = rt_object_get_information((enum rt_object_class_type)type);
/* parameter check */
if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;
/* which is invoke in interrupt status */
RT_DEBUG_NOT_IN_INTERRUPT;
/* enter critical */
rt_enter_critical();
/* try to find object */
rt_list_for_each(node, &(information->object_list))
{
object = rt_list_entry(node, struct rt_object, list);
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
{
/* leave critical */
rt_exit_critical();
return object;
}
}
/* leave critical */
rt_exit_critical();
return RT_NULL;
}
这个函数很重要,通过对象的名字对对象容器中查找它。依然是先找到信息结构体,然后遍历链表,这个函数rt_strncmp用于比较两个字符串,如果两个字符串相等则返回0。就是这么找的,所以对象的名字得唯一才可以。