RT_Thread内核源码分析(二)——链表和对象管理

news2024/11/24 18:28:42

        实时操作系统基本上都是通过一些链表进行线程、信号、队列的管理,RT_Thread也不例外,本章主要讲解RT_Thread的链表结构和对象管理。

本章基于RT_Thread Nano V3.1.5版本分析

      

1、链表

          RT_Thread使用的链表非常简单,链表节点只有节点指针,各节点在实例结构体中定义,可以通过头节点定位链表,可以通过节点在结构体中的偏移定位实例结构体。

1.1 双向链表

1.1.1 链表结构

        双向链表结构声明如下

struct rt_list_node
{
    struct rt_list_node *next;                          /**< 指向下一个节点. */
    struct rt_list_node *prev;                          /**< 指向上一个节点. */
};

        双向链表通过一个头节点对整个链表管理,如下所示,NODE1为头节点,用于定位链表,NODE2~NODEn为被链表管理的节点。

        双向链表主要用于对象、线程、定时器等实例管理,这些管理均需要提前设置头节点,如下所示,为系统内核定义的双链表头节点,还有一些头节点在结构体中定义,此处不再详述。

/********线程全局变量********/
extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; // 就绪线程链表数组
extern rt_list_t rt_thread_defunct;                                // 失效线程链表
/* 软件定时器链表 soft timer list */
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
/* 硬件定时器 hard timer list */
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];


1.1.2 链表操作

        链表操作采用内联函数和宏定义的方式,可以免去操作时的环境存储与恢复,提高运行效率。操作接口主要有初始化、插入节点(表头或表尾)、删除节点。

初始化

/*节点初始化(节点指针均指向自己)*/
#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }

/*链表头节点初始化(节点指针均指向自己)*/
rt_inline void rt_list_init(rt_list_t *l)
{
    l->next = l->prev = l;
}

插入节点至表头

/*节点n插入到链表l的头部*/
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{
    l->next->prev = n;
    n->next = l->next;

    l->next = n;
    n->prev = l;
}

  NODE1为头节点,用于定位链表,NODE2~NODEn为链表管理的节点,NewNode为新插入的节点。

   插入节点至表尾

/*节点n插入到链表l的尾部*/
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
{
    l->prev->next = n;
    n->prev = l->prev;

    l->prev = n;
    n->next = l;
}

         NODE1为头节点,用于定位链表,NODE2~NODEn为链表管理的节点,NewNode为新插入的节点。

删除节点

/*链表移除节点n*/ 
rt_inline void rt_list_remove(rt_list_t *n)
{
    n->next->prev = n->prev;
    n->prev->next = n->next;
    n->next = n->prev = n;
}

         NODE1为头节点,用于定位链表,DeleteNode、NODE2~NODEn为链表管理的节点,该图为删除节点DeleteNode。

1.1.3 链表遍历

        链表遍历接口采用内联函数和宏定义的方式,可以免去操作时的环境存储与恢复,提高运行效率。

        链表节点多数存储在各类对象的结构体中,当遍历到一个节点时,可通过节点在结构体中的偏移获取结构体指针。所以链表本质上是对对象(结构体)的管理,因此,链表遍历不仅可以遍历节点,还可以遍历对象(结构体)。

/****判断链表条目数为空****/ 
rt_inline int rt_list_isempty(const rt_list_t *l)
{
    return l->next == l;
}
/****获取链表长度****/
rt_inline unsigned int rt_list_len(const rt_list_t *l)
{
    unsigned int len = 0;
    const rt_list_t *p = l;
    while (p->next != l)
    {
        p = p->next;
        len ++;
    }
    return len;
}
/****遍历链表节点(pos为遍历出的节点,head为头节点)*/
#define rt_list_for_each(pos, head)       \  
for(pos=(head)->next;pos!= (head);pos = pos->next)

/*****遍历链表节点(安全模式,防止误删除,pos为遍历出的节点,n指向pos下个节点,head为头节点) */
#define rt_list_for_each_safe(pos, n, head) \
for(pos=(head)->next,n=pos->next; pos!=(head); pos=n, n=pos->next)

/****定位对象(根据节点定位)***/
#define rt_container_of(ptr,type,member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/****获取元素*/
#define rt_list_entry(node, type, member) rt_container_of(node, type, member)

/*****遍历对象*/
#define rt_list_for_each_entry(pos, head, member) \
for(pos=rt_list_entry((head)->next,typeof(*pos),member);&pos->member!=(head);pos = rt_list_entry(pos->member.next, typeof(*pos), member)

/******遍历对象(安全模式,防止误删除)  */
#define rt_list_for_each_entry_safe(pos, n, head, member) \
    for (pos = rt_list_entry((head)->next, typeof(*pos), member), \
         n = rt_list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head); \
         pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))

/*****获取链表第一个对象*/
#define rt_list_first_entry(ptr, type, member)  rt_list_entry((ptr)->next, type, member)

举例,比如遍历定时器,定时器结构体和链表如下所示:

/* 软件定时器链表 */
static rt_list_t rt_soft_timer_list;
/* 定时器结构体 */
struct rt_timer
{
    struct rt_object parent;                        /**< 基类对象*/
    rt_list_t   row;                                /**< 定时器链表节点*/
    void (*timeout_func)(void *parameter);          /**< 定时器函数指针 */
    void *parameter;                                /**< 定时器函数参数*/
    rt_tick_t        init_tick;                     /**< 定时器定时时间*/
    rt_tick_t        timeout_tick;                  /**< 定时器定时时刻*/
};
typedef struct rt_timer *rt_timer_t;
/*临时定时器*/
rt_timer_t  timerTemp;

         定时器链表节点在定时器结构体上的内存偏移为((struct rt_timer*)(0x0)->row),假设节点n为某个定时器的链表节点,获取定时器指针方法如下:

// 直接计算
struct rt_timer* pTimer=&n-((struct rt_timer*)(0x0)->row);
// 使用系统接口
struct rt_timer* pTimer=rt_container_of(&n,struct rt_timer*,row);

        假设定时器timerTemp已经插入到了链表rt_soft_timer_list中,在链表rt_soft_timer_list中定位到timerTemp的方法如下

/*在链表中定位定时器链表节点timerTemp.row*/ 
rt_list_for_each(&timerTemp->row, rt_soft_timer_list, row) 

/*在链表中定位定时器timerTemp*/
rt_list_for_each_entry(&timerTemp, rt_soft_timer_list, row) 

        由上述代码可见,rt_list_for_each与rt_list_for_each_entry接口作用相同,rt_list_for_each无疑性能更优,所以内核代码中并未使用rt_list_for_each_entry,而rt_list_for_each主要用于计算节点个数或判断节点是否连接在链表。

1.2 单向链表

        单向链表主要在内存池管理中使用,本章只罗列单向链表接口,其详细使用过程可以参考双向链表,二者接口相似。

1.2.1 链表结构 

struct rt_slist_node
{
    struct rt_slist_node *next;                         /**< 指向下一个节点*/
};

  1.2.2 链表操作

/*****对象节点初始化(初始化被管理的节点)*****/
#define RT_SLIST_OBJECT_INIT(object) { RT_NULL }

/****链表头节点初始化***/
rt_inline void rt_slist_init(rt_slist_t *l)
{
    l->next = RT_NULL;
}

/*****节点n插入到链表l的尾部*****/
rt_inline void rt_slist_append(rt_slist_t *l, rt_slist_t *n)
{
    struct rt_slist_node *node;
    node = l;
    while (node->next) node = node->next;
    node->next = n;
    n->next = RT_NULL;
}

/*****节点n插入到链表l的头部*****/
rt_inline void rt_slist_insert(rt_slist_t *l, rt_slist_t *n)
{
    n->next = l->next;
    l->next = n;
}

/*****从链表l移除节点n*****/
rt_inline rt_slist_t *rt_slist_remove(rt_slist_t *l, rt_slist_t *n)
{
    struct rt_slist_node *node = l;
    while (node->next && node->next != n) node = node->next;
    if (node->next != (rt_slist_t *)0) node->next = node->next->next;
    return l;
}

  1.2.3 链表遍历

 /********定位元素member所在的结构体指针,结构体类型为type**********/
#define rt_container_of(ptr, type, member)   ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))


/******链表节点个数******/
rt_inline unsigned int rt_slist_len(const rt_slist_t *l)
{
    unsigned int len = 0;
    const rt_slist_t *list = l->next;
    while (list != RT_NULL)
    {
        list = list->next;
        len ++;
    }

    return len;
}
/*******单链表第一个节点*******/
rt_inline rt_slist_t *rt_slist_first(rt_slist_t *l)
{
    return l->next;
}
/*******单链表最后一个节点*******/
rt_inline rt_slist_t *rt_slist_tail(rt_slist_t *l)
{
    while (l->next) l = l->next;
    return l;
}
/*******节点n的下一个节点*******/
rt_inline rt_slist_t *rt_slist_next(rt_slist_t *n)
{
    return n->next;
}
/*******单链表为空*******/
rt_inline int rt_slist_isempty(rt_slist_t *l)
{
    return l->next == RT_NULL;
}

/********获取节点所在的结构体*******/
#define rt_slist_entry(node, type, member)  rt_container_of(node, type, member)

/********遍历链表的节点********/
#define rt_slist_for_each(pos, head) for(pos=(head)->next; pos!=RT_NULL; pos=pos->next)

/*********遍历链表节点对应的结构体****/
#define rt_slist_for_each_entry(pos, head, member) \
  for(pos=rt_slist_entry((head)->next,typeof(*pos),member); &pos->member!=(RT_NULL); \
      pos=rt_slist_entry(pos->member.next,typeof(*pos),member))

/**********获取链表第一个节点对应的结构体 *********/
#define rt_slist_first_entry(ptr, type, member) rt_slist_entry((ptr)->next, type, member)

/**********获取链表最后一个节点对应的结构体*********/
#define rt_slist_tail_entry(ptr,type,member) rt_slist_entry(rt_slist_tail(ptr),type,member)

2、对象

       RT_Thread操作系统为方便统一管理,采用的面相对象的思想,系统定义了内核对象(等同于C++中的基类),线程、信号、消息、内存池等继承内核对象(线程、信号、消息等同于派生类)。

2.1 内核对象结构

        内核对象节点list用于链表管理,flag参数在不同对象中起着不同的含义,比如在定时器对象中表示定时器状态和定时器类型。type参数表示对象类型,见【2.2内核对象分类】

 /*基类  内核对象*/
struct rt_object
{
    char       name[RT_NAME_MAX];                       /**< 内核对象名称 */
    rt_uint8_t type;                                    /**< 内核对象类型 */
    rt_uint8_t flag;                                    /**< 内核对象标志  */
    rt_list_t  list;                                    /**< 内核对象链表节点  */
};

 2.2 内核对象分类

        内核结构中type元素表示对象类型,对象类型如下所示,其中【静态对象掩码】并不是一类独立对象,而是表示对象的属性,即对象是静态对象(静态存储)还是动态对象(申请动态内存存储)。例如:静态内存创建的线程,其类型为RT_Object_Class_Thread+RT_Object_Class_Static=0x81

 /*对象类型枚举*/
enum rt_object_class_type
{
    RT_Object_Class_Null          = 0x00,       /**< 未使用. */
    RT_Object_Class_Thread        = 0x01,       /**< 线程对象. */
    RT_Object_Class_Semaphore     = 0x02,       /**< 信号对象. */
    RT_Object_Class_Mutex         = 0x03,       /**< 互斥对象. */
    RT_Object_Class_Event         = 0x04,       /**< 事件对象. */
    RT_Object_Class_MailBox       = 0x05,       /**< 邮件对象 */
    RT_Object_Class_MessageQueue  = 0x06,       /**< 消息对象. */
    RT_Object_Class_MemHeap       = 0x07,       /**< 内存堆对象. */
    RT_Object_Class_MemPool       = 0x08,       /**< 内存池对象. */
    RT_Object_Class_Device        = 0x09,       /**< 设备驱动对象. */
    RT_Object_Class_Timer         = 0x0a,       /**< 定时器对象. */
    RT_Object_Class_Unknown       = 0x0c,       /**< 未知对象. */
    
    RT_Object_Class_Static        = 0x80        /**< 静态对象掩码. */
};

2.3 内核对象容器

        内核对象容器,主要通过双向链表管理对象,其结构体中的链表节点即为链表头节点。

        对象容器结构体

struct rt_object_information
{
    enum rt_object_class_type type;                     /**< 对象类型 */
    rt_list_t                 object_list;              /**< 对象链表 */
    rt_size_t                 object_size;              /**< 对象大小 */
};

        对象容器定义

        通过定义可见,对象容器是一数组,可根据宏定义自动裁剪。

 /*对象容器枚举*/
enum rt_object_info_type
{
    RT_Object_Info_Thread = 0,                         /**< 线程对象. */
#ifdef RT_USING_SEMAPHORE
    RT_Object_Info_Semaphore,                          /**< 信号对象. */
#endif
#ifdef RT_USING_MUTEX
    RT_Object_Info_Mutex,                              /**< 互斥对象. */
#endif
#ifdef RT_USING_EVENT
    RT_Object_Info_Event,                              /**< 事件对象 */
#endif
#ifdef RT_USING_MAILBOX
    RT_Object_Info_MailBox,                            /**< 邮件对象 */
#endif
#ifdef RT_USING_MESSAGEQUEUE
    RT_Object_Info_MessageQueue,                       /**< 消息对象. */
#endif
#ifdef RT_USING_MEMHEAP
    RT_Object_Info_MemHeap,                            /**< 堆对象*/
#endif
#ifdef RT_USING_MEMPOOL
    RT_Object_Info_MemPool,                            /**< 内存池对象. */
#endif
#ifdef RT_USING_DEVICE
    RT_Object_Info_Device,                             /**< 驱动对象 */
#endif
    RT_Object_Info_Timer,                              /**< 定时器对象 */
    RT_Object_Info_Unknown,                            /**< 未知对象. */
};

// 对象监视器初始化(指针指向自己)
#define _OBJ_CONTAINER_LIST_INIT(c) \
{&(rt_object_container[c].object_list),&(rt_object_container[c].object_list)}

// 对象容器
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
{
    /* 初始化对象容器(线程) */
    {RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},

#ifdef RT_USING_SEMAPHORE
    /* 初始化对象容器(信号) */
    {RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},

#endif

#ifdef RT_USING_MUTEX
    /* 初始化对象容器(互斥信号) */
    {RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
    /* 初始化对象容器(事件) */
    {RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
    /* 初始化对象容器(邮件)  */
    {RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif

#ifdef RT_USING_MESSAGEQUEUE
    /* 初始化对象容器(队列)  */
    {RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif

#ifdef RT_USING_MEMHEAP
    /* 初始化对象容器(内存堆) */
    {RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif

#ifdef RT_USING_MEMPOOL
    /* 初始化对象容器(内存池) */
    {RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif

#ifdef RT_USING_DEVICE
    /* 初始化对象容器(驱动) */
    {RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
    /* 初始化对象容器(定时器) */
    {RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
};

对象容器管理图示,容器有2个线程对象。

2.4 内核对象继承 

        线程、信号、互斥等对象的结构体,第一个成员必须是内核对象,等同于C++的public继承;如下例所示:

        

2.5 内核对象操作

/*系统对象(静态对象)初始化*/
void rt_system_object_init(void){}

 /*获取对象所在的容器(依据类型枚举)*/
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 (rt_object_container[index].type == type) return &rt_object_container[index];
    return RT_NULL;
}

/*获取对象所在链表长度,既同类对象个数 (依据类型枚举)*/
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();
    /*计算有效对象个数*/
    rt_list_for_each(node, &(information->object_list))
    {
        count ++;
    }
	// 退出临界区
    rt_hw_interrupt_enable(level);
    return count;
}

 /* 复制type类型的对象指针至pointers中,最大maxlen个*/
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();
    /* 检索节点,并复制对象指针*/
    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;
}

/*初始化静态内核对象 */
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;
    /*获取对象容器*/
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);
    /* 退出线程调度*/
    rt_enter_critical();
	
    /* 检查对象,避免重复初始化*/
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)
        {
        	/*检查是否存在重复初始化*/
            RT_ASSERT(obj != object);
        }
    }
    /* 恢复线程调度*/
    rt_exit_critical();
    /* 设置静态标识*/
    object->type = type | RT_Object_Class_Static;
    /* 设置名称 */
    rt_strncpy(object->name, name, RT_NAME_MAX);
	/* 对象新增函数调用钩子*/
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
    /* 进入临界区lock interrupt */
    temp = rt_hw_interrupt_disable();
    /*对象插入值链表头部*/
    rt_list_insert_after(&(information->object_list), &(object->list));
    /* 退出临界区*/
    rt_hw_interrupt_enable(temp);
}
 /*移除静态内核对象*/
void rt_object_detach(rt_object_t object)
{
    register rt_base_t temp;
    /* 断言*/
    RT_ASSERT(object != RT_NULL);
	/* 执行对象移除钩子 */
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
    /*清除对象类型*/
    object->type = 0;
    /* 进入临界区*/
    temp = rt_hw_interrupt_disable();
    /* 从链表 移除对象*/
    rt_list_remove(&(object->list));
    /* 退出临界区 */
    rt_hw_interrupt_enable(temp);
}
 /*初始化动态内核对象(依据类型分配)*/
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;
	/*中断断言*/
    RT_DEBUG_NOT_IN_INTERRUPT;
    /* 获取对象容器*/
    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)
    {
        /*动态内存申请失败*/
        return RT_NULL;
    }
    /* 动态内存初始化为0*/
    rt_memset(object, 0x0, information->object_size);
    /* 设置对象类型 */
    object->type = type;
    /* 清除对象标志 */
    object->flag = 0;
    /* 设置名称 */
    rt_strncpy(object->name, name, RT_NAME_MAX);
	/* 执行钩子 */
    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
    /* 进入临界区*/
    temp = rt_hw_interrupt_disable();
    /* 插入对象至管理器链表头部*/
    rt_list_insert_after(&(information->object_list), &(object->list));
    /* 退出临界区*/
    rt_hw_interrupt_enable(temp);
    /* 返回对象指针*/
    return object;
}

/**删除并释放动态对象*/
void rt_object_delete(rt_object_t object)
{
    register rt_base_t temp;
    /* 断言 */
    RT_ASSERT(object != RT_NULL);
    RT_ASSERT(!(object->type & RT_Object_Class_Static));
    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));
    /* 清除类型 */
    object->type = RT_Object_Class_Null;
    /* 进入临界区 */
    temp = rt_hw_interrupt_disable();
    /* 从链表移除*/
    rt_list_remove(&(object->list));
    /* 退出临界区*/
    rt_hw_interrupt_enable(temp);
    /* 释放对象内存 */
    RT_KERNEL_FREE(object);
}
#endif

/**检查对象类型是否为系统类型(静态类型)*/
rt_bool_t rt_object_is_systemobject(rt_object_t object)
{
    /* 对象断言*/
    RT_ASSERT(object != RT_NULL);
    if (object->type & RT_Object_Class_Static)
        return RT_TRUE;
    return RT_FALSE;
}

/**获取对象类型*/
rt_uint8_t rt_object_get_type(rt_object_t object)
{
    /*断言*/
    RT_ASSERT(object != RT_NULL);
    return object->type & ~RT_Object_Class_Static;
}

/*查找对象(name对象名称,type对象类型,依据对象名称和类型,该函数不能在中断调用)*/
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);
    /* 参数检查 */
    if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;
    /* which is invoke in interrupt status */
    RT_DEBUG_NOT_IN_INTERRUPT;
    /* 退出线程调度*/
    rt_enter_critical();
    /* 遍历对象节点 */
    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)
        {
            /* 恢复线程调度*/
            rt_exit_critical();
            return object;
        }
    }
    /* 恢复线程调度 */
    rt_exit_critical();
    return RT_NULL;
}

2.6 内核对象钩子

        操作系统通过钩子(函数指针)给用户侧提供调试、监视或其他用途的接口,这些接口分布在对象操作的重要位置,用户侧可以根据需求选配使用。

/*****对象钩子*****/
static void (*rt_object_attach_hook)(struct rt_object *object); // 对象增加调用钩子
static void (*rt_object_detach_hook)(struct rt_object *object); // 对象移除调用钩子
void (*rt_object_trytake_hook)(struct rt_object *object);       // 对象将被占用调用钩子
void (*rt_object_take_hook)(struct rt_object *object);          // 对象已经被占用调用钩子
void (*rt_object_put_hook)(struct rt_object *object);           // 对象被释放调用钩子


 /*****对象动态增加调用钩子设置*****/
void rt_object_attach_sethook(void (*hook)(struct rt_object *object))
{
    rt_object_attach_hook = hook;
}
 /*****对象移除调用钩子设置*****/
void rt_object_detach_sethook(void (*hook)(struct rt_object *object))
{
    rt_object_detach_hook = hook;
}
 /*****对象将要占用调用钩子设置,主要应用于信号、互斥信号、事件、邮件、消息队列将要阻塞线程时*****/
void rt_object_trytake_sethook(void (*hook)(struct rt_object *object))
{
    rt_object_trytake_hook = hook;
}
 /*****对象已经占用调用钩子设置,主要应用于信号、互斥信号、事件、邮件、消息队列、定时器返回线程,检测阻塞***/
void rt_object_take_sethook(void (*hook)(struct rt_object *object))
{
    rt_object_take_hook = hook;
}
/****对象释放调用钩子设置,比如消息对象发送消息,释放线程****/
void rt_object_put_sethook(void (*hook)(struct rt_object *object))
{
    rt_object_put_hook = hook;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2161542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

随机梯度下降的学习

梯度下降&#xff08;Gradient-Descent&#xff09; 在机器学习的旅途中&#xff0c;不可避免需要与它打交道&#xff0c;那么该如何初步理解它的用途呢&#xff1f; 好的&#xff0c;想象你在一个山谷中&#xff0c;想要找到最低点&#xff08;山谷的底部&#xff09;。你现…

A50期指

A50期指是什么? A50期指一般指的是中国A股市场的富时中国A50指数期货。富时中国A50指数(FTSE China A50 Index)是由富时罗素公司编制的一个权益指数,包含了中国A股市场中市值最大的50只股票,代表了中国A股市场的核心企业。 富时中国A50指数期货是基于富时中国A50指数的衍…

系统滴答定时器

定时器 目录 定时器 回顾GPIO、中断 定时器的分类 一、系统滴答定时器 应用&#xff1a;非阻塞轮询思想 回顾GPIO、中断 理论&#xff1a; GPIO&#xff1a;八种模式概念&#xff0c;能够根据电路的实际情况&#xff0c;去分析该使用哪一种模式。 上拉 下拉 浮空 模拟 推…

【2024W32】肖恩技术周刊(第 10 期):太阳神鸟

周刊内容: 对一周内阅读的资讯或技术内容精品&#xff08;个人向&#xff09;进行总结&#xff0c;分类大致包含“业界资讯”、“技术博客”、“开源项目”和“工具分享”等。为减少阅读负担提高记忆留存率&#xff0c;每类下内容数一般不超过3条。 更新时间: 星期天 历史收录:…

uboot无法使用nfs下载文件的问题

一、系统环境 见这篇博客。 二、问题描述 uboot使用nfs下载文件出现 “T T T”&#xff0c;一直无法下载 三、解决方法 编辑/etc/nfs.conf文件&#xff1a; sudo xed /etc/nfs.conf开启udp: udpy之后重启nfs服务器&#xff1a; sudo /etc/init.d/nfs-kernel-server re…

(学习记录)使用HAL库 STM32CubeMX——GPIO引脚输入配置

STM32F103C8T6的GPIO引脚输入配置 时钟配置 &#xff08;学习记录&#xff09;使用 STM32CubeMX——配置时钟&#xff08;入门&#xff09;https://blog.csdn.net/Wang2869902214/article/details/142423522 GPIO 引脚输出配置 &#xff08;学习记录&#xff09;使用 STM32…

优青博导团队指导-组蛋白甲基化修饰、实验设计、实验结果分析、测序分析及SCI论文辅助,精准高效,为农医学科研保驾护航!

组蛋白甲基化修饰工具(H3K4me3 ChIP-seq) 组蛋白甲基化类型也有很多种&#xff0c;包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守&#xff0c;是被研究最多的组蛋白修饰之一。

相亲交友网站为不同年龄层提供的服务差异

随着互联网技术的飞速发展&#xff0c;相亲交友网站已经成为现代人寻找伴侣的重要途径之一。无论是年轻人还是中老年人&#xff0c;都可以通过相亲交友网站找到自己的另一半。然而&#xff0c;不同年龄层的人在使用相亲交友网站时的需求和服务体验上存在显著差异。本文将探讨这…

【视频讲解】非参数重采样bootstrap的逻辑回归Logistic应用及模型差异Python实现

全文链接&#xff1a;https://tecdat.cn/?p37759 原文出处&#xff1a;拓端数据部落公众号 分析师&#xff1a;Anting Li 本文将深入探讨逻辑回归在心脏病预测中的应用与优化。通过对加州大学欧文分校提供的心脏病数据集进行分析&#xff0c;我们将揭示逻辑回归模型的原…

思维可视化:2024年四大创新思维导图软件排行榜!

在快节奏的现代生活中&#xff0c;如何提高工作效率、整理繁杂信息成为许多人关注的焦点。思维导图作为一种高效的信息梳理工具&#xff0c;越来越受到职场人士的喜爱。今天&#xff0c;就为大家推荐几款优秀的思维导图软件&#xff0c;助您轻松应对各种工作场景。 福昕思维导…

《程序猿之设计模式实战 · 适配器模式》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

C++(学习)2024.9.24

目录 容器 1.标准模板库STL 2.概念 3.顺序容器 &#xff08;1&#xff09;array数组 &#xff08;2&#xff09;vector向量 &#xff08;3&#xff09;list列表 &#xff08;4&#xff09;deque 队列 4.关联容器 5.迭代器 面向对象核心 继承 概念 构造函数 1.派生…

软件需求规格说明书编制模板参考(Doc原件)

1 范围 1.1 系统概述 1.2 文档概述 1.3 术语及缩略语 2 引用文档 3 需求 3.1 要求的状态和方式 3.2 系统能力需求 3.3 系统外部接口需求 3.3.1 管理接口 3.3.2 业务接口 3.4 系统内部接口需求 3.5 系统内部数据需求 3.6 适应性需求 3.7 安全性需求 3.8 保密性需…

项目实战总结-Kafka实战应用核心要点

Kafka实战应用核心要点 一、前言二、Kafka避免重复消费2.1 消费者组机制2.2 幂等生产者2.3 事务性生产者/消费者2.4 手动提交偏移量2.5 外部存储管理偏移量2.6 去重逻辑2.7 幂等消息处理逻辑2.8 小结 三、Kafka持久化策略3.1 持久化文件3.2 segment 分段策略3.3 数据文件刷盘策…

Leetcode面试经典150题-39.组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。如…

加固与脱壳01 - 环境搭建

虚拟机 VMWare 多平台可用&#xff0c;而且可以直接激活&#xff0c;需要先注册一个账号 https://support.broadcom.com/group/ecx/productdownloads?subfamilyVMwareWorkstationPro KALI 类Ubuntu系统&#xff0c;官方提供了 vmware 版本&#xff0c;直接下载就可以使用。…

【Python机器学习】NLP信息提取——提取人物/事物关系

目录 词性标注 实体名称标准化 实体关系标准化和提取 单词模式 文本分割 断句 断句的方式 使用正则表达式进行断句 词性标注 词性&#xff08;POS&#xff09;标注可以使用语言模型来完成&#xff0c;这个语言模型包含词及其所有可能词性组成的字典。然后&#xff0c;该…

三子棋小游戏

使用C语言编写代码&#xff0c;实现一个简单小游戏---三子棋 这里创建1个game.h文件&#xff0c;用来声明函数、宏的文件&#xff0c;一个game.c文件用来实现函数game&#xff08;&#xff09;&#xff0c;一个play.h文件用来作为该游戏的源文件。 具体代码如下&#xff1a; …

利用大型语言模型轻松打造浪漫时刻

当情人节年年如约而至&#xff0c;每每都需费尽心思为对方营造一场令人难忘的仪式&#xff0c;却因缺乏创意与思路而倍感困扰。今天&#xff0c;我决定让大型语言模型为我们提供一些灵感和建议&#xff0c;让我们能够轻松实现这一目标。让我们开始行动吧&#xff01;此前&#…

问卷是否要做信效度分析,5类信度与4类效度常用指标及评价标准

论文问卷进行分析时&#xff0c;大家是否有这样的疑惑—— 我收集的问卷是否需要进行信效度分析呢&#xff1f; 下面一文给大家梳理问卷信效度分析的相关内容&#xff0c;包括什么样的题目需要进行信效度分析、5类信度分析与4类效度分析常用指标及评价标准。 一、问卷是否需…