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 】中的函数。