rt_list_entry() 函數


在rt_thread_find()函數中,調用了rt_list_entry()函數:

rt_thread_t rt_thread_find(char *name)
{
    struct rt_object_information *information;
    struct rt_object *object;
    struct rt_list_node *node;

    /* enter critical */
    if (rt_thread_self() != RT_NULL)
        rt_enter_critical();

    /* try to find device object */
    information = rt_object_get_information(RT_Object_Class_Thread);
    RT_ASSERT(information != RT_NULL);
    for (node  = information->object_list.next;
         node != &(information->object_list);
         node  = node->next)
    {
        object = rt_list_entry(node, struct rt_object, list); if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            if (rt_thread_self() != RT_NULL)
                rt_exit_critical();

            return (rt_thread_t)object;
        }
    }

    /* leave critical */
    if (rt_thread_self() != RT_NULL)
        rt_exit_critical();

    /* not found */
    return RT_NULL;
}
RTM_EXPORT(rt_thread_find);


information(rt_object_information)的定義如下:

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的定義如下:

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 */

    rt_list_t  list;                                    /**< list node of kernel object */
};


在對象初始化時--rt_object_init()函數,會將該對象指針(rt_list_t list)插入到information的鏈表中進行管理。

/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));


在下面這段代碼中information->object_list 是記錄RT_Object_Class_Thread類型對象指針的鏈表。
object = rt_list_entry(node, struct rt_object, list);
node是information->object_list中的某個對象指針,來自於某個rt_object結構體中的成員rt_list_t list。

調用rt_list_entry()函數,根據成員(rt_list_t list)的地址獲得結構體 rt_object 的地址(對象指針)。

information = rt_object_get_information(RT_Object_Class_Thread);
for (node  = information->object_list.next;
     node != &(information->object_list);
     node  = node->next)
{
    object = rt_list_entry(node, struct rt_object, list);
    /////
}


下面來看下具體是怎么實現的。

/**
 * @brief get the struct for this entry
 * @param node the entry point
 * @param type the type of structure
 * @param member the name of list in structure
 */
#define rt_list_entry(node, type, member) \
    rt_container_of(node, type, member)

/**
 * rt_container_of - return the member address of ptr, if the type of ptr is the
 * struct type.
 */
#define rt_container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

 

在rt_container_of()函數中

輸入值  ptr: object->list, type: struct rt_object, member: rt_list_t list
返回值  object

((type *)0)                     把0地址強制轉換成了(type *)類型的指針,代入例子就是地址為0的虛擬 (rt_object *) 對象
((type *)0)->member     指向了該type的成員(rt_object下的list)
&((type *)0)->member   獲得該成員(list)的地址

因為是從0開始的,因此上述得到的地址也就是list成員在rt_object結構體中的偏移地址

 

(char *)(ptr)                    以字節為單位得到object->list的實際地址

object->list的實際地址 = object的實際地址        + list成員在rt_object結構體中的偏移地址

將這個式子反一下:
object的實際地址         = object->list的實際地址 - list成員在rt_object結構體中的偏移地址

(char *)(ptr) - (unsigned long)(&((type *)0)->member)

 

最后將該地址強制轉換為對象指針(type *)返回

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM