操作系统的句柄:
在使用操作系统时,经常会用到句柄。那么,什么是句柄?
简而言之,句柄就是一个 void * 指针,指向了一块内存空间,这块内存才是我们需要的数据结构。
以FreeRTOS为例:
typedef void * TimerHandle_t;
1 这里首先定义了,定时器句柄为 void 类型指针。接下来,创建两个句柄;
TimerHandle_t auto_reload_timer_handle; // 周期定时器句柄
TimerHandle_t one_shot_timer_handle; // 单次定时器句柄
句柄既然是指针,那么在32位mcu中,就应该只占据 4 字节的空间,如下所示:
ok,已经知道句柄是一个 void 类型指针了,既然是指针,就得指向一块内存,如下所示:
在创建任务之前,我们创建的的句柄一直指向0地址,这很正常,因为指针还没有进行初始化,因此不指向任何内存空间。
2 接下来进入开始任务,创建定时器并返回定时器句柄:
在开始任务中,调用了定时器创建函数,返回值为定时器句柄。因此,可以预计这个函数实际上给句柄指针赋值。
函数内部如下所示,其实就时创建一个结构体指针 Timer_t,然后给指针申请内存,最后返回指针给句柄:
接下来,单步调试,观察定时器句柄的指针值:
3 使用句柄:
之前提到,句柄虽然是 void 类型指针,但却真实的指向了一段存在的内存空间,所以,当使用句柄时,只需要进行强制类型转换(void类型指针可以强制类型转换成任意一种类型),就能还原这片内存空间:
以下是回调函数中,通过句柄获取定时器ID的源码:
/* The definition of the timers themselves. */
typedef struct tmrTimerControl
{
const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
UBaseType_t uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one-shot timer. */
void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
} xTIMER;
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID )
{
// 将定时器句柄强制类型转换成 Timer_t 类型
Timer_t * const pxTimer = ( Timer_t * ) xTimer;
configASSERT( xTimer );
taskENTER_CRITICAL();
{
// 获取 Timer_t 结构体成员 pvTimerID
pxTimer->pvTimerID = pvNewID;
}
taskEXIT_CRITICAL();
}
以下是调试过程,在调元这个函数前,两个任务句柄的值如下所示:
在执行此函数过程中,变量的状态如下所示:
这就是创建句柄,初始化句柄和使用句柄的过程。