2009.5.9
从今天开始研究
freertos
的代码,特别注重内核的一些细节的实现和大的架构。
在
main
函数中调用了
vTaskinit
函数,该函数主要就是为初始化系统为启动
task
和任务调度做准备。这个函数有一个
timer
的实现,而在这个实现中有一个互斥体的应用。而在
freertos
系统中是没有直接提供这个实现的。现在就说下互斥的相关工作流程。
首先
SDL_CreateMutex
函数用来创建一个互斥体的,返回类型是
SDL_mutex
。可以追踪看到下面的定义
#define SDL_mutex xSemaphoreHandle
typedef xQueueHandle xSemaphoreHandle;
【
source\include\semphr.h
】
再看下
xQueueHandle
的定义,有两个,分别是:
typedef void * xQueueHandle;
【
source\include\queue.h
】
typedef xQUEUE * xQueueHandle;
【
source\queue.c
】
typedef struct QueueDefinition
{
signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
signed portCHAR *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
unsigned portBASE_TYPE uxItemSize;/*< The size of each items that the queue will hold. */
signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
} xQUEUE;
不管怎么样
void *
总是没错的【这里为什么如此调用,待后续研究】,在
semphr.h
中也有
#include "queue.h"
这样的语句。
这样知道了
SDL_mutex
的实际类型,再来看下
SDL_CreateMutex
函数的实现,直接返回
xSemaphoreCreateMutex()
。那我们由此可以知道,互斥体的实现其实就是对信号量的封装。
接着走,发现
#define xSemaphoreCreateMutex() xQueueCreateMutex()
【
source\include\semphr.h
】。那就看下
xQueueCreateMutex
的实现吧,这回是个函数了。
xQueueHandle xQueueCreateMutex( void )
{
xQUEUE *pxNewQueue;
pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
/* Ensure the event queues start with the correct state. */
vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
/* Start with the semaphore in the expected state. */
xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );
}
从函数名字就知道是怎么回事了,通过
queue
来实现最终的互斥体。这个函数主要做了
3
件事:
pvPortMalloc
;
vListInitialise
;
xQueueGenericSend
。分别是
3
个函数的调用。直接返回的就是
xQUEUE *
。
既然来了,就坐下聊聊吧。下面说下那
3
个函数的情况。
void *pvPortMalloc( unsigned portSHORT usWantedSize )
【
source\portable\wizc\pic18\port.c
】
{
void *pvReturn;
vTaskSuspendAll();
{
pvReturn = malloc( ( malloc_t ) usWantedSize );
}
xTaskResumeAll();
return pvReturn;
}
void vListInitialise( xList *pxList )//
就是实现了一个空的链表
【
source\list.c
】
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
pxList->uxNumberOfItems = 0;
}
signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
这个函数,这里只给出个原型,待在介绍
queue
的时候再做详细介绍
。
除了
SDL_CreateMutex
,互斥体相关的函数还有
SDL_DestroyMutex
;
SDL_mutexP
;
SDL_mutexV
。从这些函数的名字上,我们应该很容易知道互斥体的用法了。
实现如下:
void SDL_mutexP(SDL_mutex mutex)
{
//TODO
xSemaphoreTake( mutex, portMAX_DELAY);
}
void SDL_mutexV(SDL_mutex mutex)
{
//TODO
xSemaphoreGive(mutex);
}
SDL_mutex SDL_CreateMutex(void)
{
//TODO
return(xSemaphoreCreateMutex());
}
void SDL_DestroyMutex(SDL_mutex mutex)
{
//TODO
vQueueDelete(mutex);
}
这些函数最终都会调用【
source\queue.c
】中的函数。