9-FreeRTOS之静态内存分配与动态内存分配

简介: 9-FreeRTOS之静态内存分配与动态内存分配

1-简介


从9.0版本之后,FreeRTOS允许用户自己定义内存的大小,允许在以下对象创建而不用创建内存的分配:

  • 任务
  • 软件定时器
  • 队列
  • 事件组
  • 二进制信号量
  • 计数信号量
  • 递归信号量
  • 互斥体


使用静态内存分配还是动态内存分配取决于应用程序,以及应用程序编写人员的偏好。这两种方法各有优缺点,可以在同一个RTOS应用程序中应用。在FreeRTOS/Source/WIN32-MSVC-Static-Allocation-Only 目录中目录下有对应的堆演示实验。


2- 动态创建FreeRTOS对象


创建对象时需要的函数参数较少。

内存分配在RTOS API函数中自动进行。

应用程序编写人员不需要关心分配内存的问题。

如果删除RTOS对象,则可以重新使用该对象所使用的RAM,从而可能减少应用程序的最大RAM占用。

RTOS API函数提供了返回堆使用信息的功能,允许优化堆大小。


若configSUPPORT_DYNAMIC_ALLOCATION设置为1,那么下列API函数,可以使用动态内存分配创建:

1xTaskCreate()
2xQueueCreate()
3xTimerCreate()
4xEventGroupCreate()
5xSemaphoreCreateBinary()
6xSemaphoreCreateCounting()
7xSemaphoreCreateMutex()
8xSemaphoreCreateRecursiveMutex()


静态内存分配的创建


静态内存分配的好处是,可以更好的对应用程序的内存的利用,具有更好的控制代码的编写:


RTOS 对象可以放置在特定的内存位置。


最大 RAM 占用空间可以在链路时确定,而不是 运行时。


应用程序编写者不需要关心如何 处理内存分配失败的问题。


它允许在不允许任何动态内存分配的应用程序中使用RTOS(尽管FreeRTOS包括可以克服大多数异议的分配方案)。

如果configSUPPORT_STATIC_ALLOCATION设置为1,则下列API可用:

1xTaskCreateStatic()
2xQueueCreateStatic()
3xTimerCreateStatic()
4xEventGroupCreateStatic()
5xSemaphoreCreateBinaryStatic()
6xSemaphoreCreateCountingStatic()
7xSemaphoreCreateMutexStatic()
8xSemaphoreCreateRecursiveMutexStatic()

以上这些函数后面都会讲解。

下面是官方提供的有关上面这些函数的静态应用,自己可以看一下,我看了一下,基本上没有理解难度:

1/*
   2 * FreeRTOS V202011.00
   3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
   6 * this software and associated documentation files (the "Software"), to deal in
   7 * the Software without restriction, including without limitation the rights to
   8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   9 * the Software, and to permit persons to whom the Software is furnished to do so,
  10 * subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice shall be included in all
  13 * copies or substantial portions of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * http://www.FreeRTOS.org
  23 * http://aws.amazon.com/freertos
  24 *
  25 * 1 tab == 4 spaces!
  26 */
  27
  28
  29/*
  30 * Demonstrates how to create FreeRTOS objects using pre-allocated memory,
  31 * rather than the normal dynamically allocated memory, and tests objects being
  32 * created and deleted with both statically allocated memory and dynamically
  33 * allocated memory.
  34 *
  35 * See http://www.FreeRTOS.org/Static_Vs_Dynamic_Memory_Allocation.html
  36 */
  37
  38/* Scheduler include files. */
  39#include "FreeRTOS.h"
  40#include "task.h"
  41#include "queue.h"
  42#include "semphr.h"
  43#include "event_groups.h"
  44#include "timers.h"
  45
  46/* Demo program include files. */
  47#include "StaticAllocation.h"
  48
  49/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
  50#if( configSUPPORT_STATIC_ALLOCATION == 1 )
  51
  52/* The priority at which the task that performs the tests is created. */
  53#define staticTASK_PRIORITY                    ( tskIDLE_PRIORITY + 2 )
  54
  55/* The length of the queue, in items, not bytes, used in the queue static
  56allocation tests. */
  57#define staticQUEUE_LENGTH_IN_ITEMS            ( 5 )
  58
  59/* A block time of 0 simply means "don't block". */
  60#define staticDONT_BLOCK                    ( ( TickType_t ) 0 )
  61
  62/* Binary semaphores have a maximum count of 1. */
  63#define staticBINARY_SEMAPHORE_MAX_COUNT    ( 1 )
  64
  65/* The size of the stack used by the task that runs the tests. */
  66#define staticCREATOR_TASK_STACK_SIZE        ( configMINIMAL_STACK_SIZE * 2 )
  67
  68/* The number of times the software timer will execute before stopping itself. */
  69#define staticMAX_TIMER_CALLBACK_EXECUTIONS    ( 5 )
  70
  71
  72/*-----------------------------------------------------------*/
  73
  74/*
  75 * The task that repeatedly creates and deletes statically allocated tasks, and
  76 * other RTOS objects.
  77 */
  78static void prvStaticallyAllocatedCreator( void *pvParameters );
  79
  80/*
  81 * The callback function used by the software timer that is repeatedly created
  82 * and deleted using both static and dynamically allocated memory.
  83 */
  84static void prvTimerCallback( TimerHandle_t xExpiredTimer );
  85
  86/*
  87 * A task that is created and deleted multiple times, using both statically and
  88 * dynamically allocated stack and TCB.
  89 */
  90static void prvStaticallyAllocatedTask( void *pvParameters );
  91
  92/*
  93 * A function that demonstrates and tests the API functions that create and
  94 * delete tasks using both statically and dynamically allocated TCBs and stacks.
  95 */
  96static void prvCreateAndDeleteStaticallyAllocatedTasks( void );
  97
  98/*
  99 * A function that demonstrates and tests the API functions that create and
 100 * delete event groups using both statically and dynamically allocated RAM.
 101 */
 102static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void );
 103
 104/*
 105 * A function that demonstrates and tests the API functions that create and
 106 * delete queues using both statically and dynamically allocated RAM.
 107 */
 108static void prvCreateAndDeleteStaticallyAllocatedQueues( void );
 109
 110/*
 111 * A function that demonstrates and tests the API functions that create and
 112 * delete binary semaphores using both statically and dynamically allocated RAM.
 113 */
 114static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void );
 115
 116/*
 117 * A function that demonstrates and tests the API functions that create and
 118 * delete software timers using both statically and dynamically allocated RAM.
 119 */
 120static void prvCreateAndDeleteStaticallyAllocatedTimers( void );
 121
 122/*
 123 * A function that demonstrates and tests the API functions that create and
 124 * delete mutexes using both statically and dynamically allocated RAM.
 125 */
 126static void prvCreateAndDeleteStaticallyAllocatedMutexes( void );
 127
 128/*
 129 * A function that demonstrates and tests the API functions that create and
 130 * delete counting semaphores using both statically and dynamically allocated
 131 * RAM.
 132 */
 133static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void );
 134
 135/*
 136 * A function that demonstrates and tests the API functions that create and
 137 * delete recursive mutexes using both statically and dynamically allocated RAM.
 138 */
 139static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void );
 140
 141/*
 142 * Utility function to create pseudo random numbers.
 143 */
 144static UBaseType_t prvRand( void );
 145
 146/*
 147 * The task that creates and deletes other tasks has to delay occasionally to
 148 * ensure lower priority tasks are not starved of processing time.  A pseudo
 149 * random delay time is used just to add a little bit of randomisation into the
 150 * execution pattern.  prvGetNextDelayTime() generates the pseudo random delay.
 151 */
 152static TickType_t prvGetNextDelayTime( void );
 153
 154/*
 155 * Checks the basic operation of a queue after it has been created.
 156 */
 157static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue );
 158
 159/*
 160 * Checks the basic operation of a recursive mutex after it has been created.
 161 */
 162static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore );
 163
 164/*
 165 * Checks the basic operation of a binary semaphore after it has been created.
 166 */
 167static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount );
 168
 169/*
 170 * Checks the basic operation of an event group after it has been created.
 171 */
 172static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup );
 173
 174/*-----------------------------------------------------------*/
 175
 176/* StaticTask_t is a publicly accessible structure that has the same size and
 177alignment requirements as the real TCB structure.  It is provided as a mechanism
 178for applications to know the size of the TCB (which is dependent on the
 179architecture and configuration file settings) without breaking the strict data
 180hiding policy by exposing the real TCB.  This StaticTask_t variable is passed
 181into the xTaskCreateStatic() function that creates the
 182prvStaticallyAllocatedCreator() task, and will hold the TCB of the created
 183tasks. */
 184static StaticTask_t xCreatorTaskTCBBuffer;
 185
 186/* This is the stack that will be used by the prvStaticallyAllocatedCreator()
 187task, which is itself created using statically allocated buffers (so without any
 188dynamic memory allocation). */
 189static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ];
 190
 191/* Used by the pseudo random number generating function. */
 192static uint32_t ulNextRand = 0;
 193
 194/* Used so a check task can ensure this test is still executing, and not
 195stalled. */
 196static volatile UBaseType_t uxCycleCounter = 0;
 197
 198/* A variable that gets set to pdTRUE if an error is detected. */
 199static volatile BaseType_t xErrorOccurred = pdFALSE;
 200
 201/*-----------------------------------------------------------*/
 202
 203void vStartStaticallyAllocatedTasks( void  )
 204{
 205    /* Create a single task, which then repeatedly creates and deletes the other
 206    RTOS objects using both statically and dynamically allocated RAM. */
 207    xTaskCreateStatic( prvStaticallyAllocatedCreator,       /* The function that implements the task being created. */
 208                       "StatCreate",                        /* Text name for the task - not used by the RTOS, its just to assist debugging. */
 209                       staticCREATOR_TASK_STACK_SIZE,       /* Size of the buffer passed in as the stack - in words, not bytes! */
 210                       NULL,                                /* Parameter passed into the task - not used in this case. */
 211                       staticTASK_PRIORITY,                 /* Priority of the task. */
 212                       &( uxCreatorTaskStackBuffer[ 0 ] ),  /* The buffer to use as the task's stack. */
 213                       &xCreatorTaskTCBBuffer );            /* The variable that will hold the task's TCB. */
 214}
 215/*-----------------------------------------------------------*/
 216
 217static void prvStaticallyAllocatedCreator( void *pvParameters )
 218{
 219    /* Avoid compiler warnings. */
 220    ( void ) pvParameters;
 221
 222    for( ;; )
 223    {
 224        /* Loop, running functions that create and delete the various RTOS
 225        objects that can be optionally created using either static or dynamic
 226        memory allocation. */
 227        prvCreateAndDeleteStaticallyAllocatedTasks();
 228        prvCreateAndDeleteStaticallyAllocatedQueues();
 229
 230        /* Delay to ensure lower priority tasks get CPU time, and increment the
 231        cycle counter so a 'check' task can determine that this task is still
 232        executing. */
 233        vTaskDelay( prvGetNextDelayTime() );
 234        uxCycleCounter++;
 235
 236        prvCreateAndDeleteStaticallyAllocatedBinarySemaphores();
 237        prvCreateAndDeleteStaticallyAllocatedCountingSemaphores();
 238
 239        vTaskDelay( prvGetNextDelayTime() );
 240        uxCycleCounter++;
 241
 242        prvCreateAndDeleteStaticallyAllocatedMutexes();
 243        prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes();
 244
 245        vTaskDelay( prvGetNextDelayTime() );
 246        uxCycleCounter++;
 247
 248        prvCreateAndDeleteStaticallyAllocatedEventGroups();
 249        prvCreateAndDeleteStaticallyAllocatedTimers();
 250    }
 251}
 252/*-----------------------------------------------------------*/
 253
 254static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void )
 255{
 256SemaphoreHandle_t xSemaphore;
 257const UBaseType_t uxMaxCount = ( UBaseType_t ) 10;
 258
 259/* StaticSemaphore_t is a publicly accessible structure that has the same size
 260and alignment requirements as the real semaphore structure.  It is provided as a
 261mechanism for applications to know the size of the semaphore (which is dependent
 262on the architecture and configuration file settings) without breaking the strict
 263data hiding policy by exposing the real semaphore internals.  This
 264StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic()
 265function calls within this function.  NOTE: In most usage scenarios now it is
 266faster and more memory efficient to use a direct to task notification instead of
 267a counting semaphore.  http://www.freertos.org/RTOS-task-notifications.html */
 268StaticSemaphore_t xSemaphoreBuffer;
 269
 270    /* Create the semaphore.  xSemaphoreCreateCountingStatic() has one more
 271    parameter than the usual xSemaphoreCreateCounting() function.  The parameter
 272    is a pointer to the pre-allocated StaticSemaphore_t structure, which will
 273    hold information on the semaphore in an anonymous way.  If the pointer is
 274    passed as NULL then the structure will be allocated dynamically, just as
 275    when xSemaphoreCreateCounting() is called. */
 276    xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer );
 277
 278    /* The semaphore handle should equal the static semaphore structure passed
 279    into the xSemaphoreCreateBinaryStatic() function. */
 280    configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
 281
 282    /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
 283    prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
 284
 285    /* Delete the semaphore again so the buffers can be reused. */
 286    vSemaphoreDelete( xSemaphore );
 287
 288    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 289    {
 290        /* Now do the same but using dynamically allocated buffers to ensure the
 291        delete functions are working correctly in both the static and dynamic
 292        allocation cases. */
 293        xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 );
 294        configASSERT( xSemaphore != NULL );
 295        prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
 296        vSemaphoreDelete( xSemaphore );
 297    }
 298    #endif
 299}
 300/*-----------------------------------------------------------*/
 301
 302static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void )
 303{
 304SemaphoreHandle_t xSemaphore;
 305
 306/* StaticSemaphore_t is a publicly accessible structure that has the same size
 307and alignment requirements as the real semaphore structure.  It is provided as a
 308mechanism for applications to know the size of the semaphore (which is dependent
 309on the architecture and configuration file settings) without breaking the strict
 310data hiding policy by exposing the real semaphore internals.  This
 311StaticSemaphore_t variable is passed into the
 312xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */
 313StaticSemaphore_t xSemaphoreBuffer;
 314
 315    /* Create the semaphore.  xSemaphoreCreateRecursiveMutexStatic() has one
 316    more parameter than the usual xSemaphoreCreateRecursiveMutex() function.
 317    The parameter is a pointer to the pre-allocated StaticSemaphore_t structure,
 318    which will hold information on the semaphore in an anonymous way.  If the
 319    pointer is passed as NULL then the structure will be allocated dynamically,
 320    just as when xSemaphoreCreateRecursiveMutex() is called. */
 321    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer );
 322
 323    /* The semaphore handle should equal the static semaphore structure passed
 324    into the xSemaphoreCreateBinaryStatic() function. */
 325    configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
 326
 327    /* Ensure the semaphore passes a few sanity checks as a valid
 328    recursive semaphore. */
 329    prvSanityCheckCreatedRecursiveMutex( xSemaphore );
 330
 331    /* Delete the semaphore again so the buffers can be reused. */
 332    vSemaphoreDelete( xSemaphore );
 333
 334    /* Now do the same using dynamically allocated buffers to ensure the delete
 335    functions are working correctly in both the static and dynamic memory
 336    allocation cases. */
 337    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 338    {
 339        xSemaphore = xSemaphoreCreateRecursiveMutex();
 340        configASSERT( xSemaphore != NULL );
 341        prvSanityCheckCreatedRecursiveMutex( xSemaphore );
 342        vSemaphoreDelete( xSemaphore );
 343    }
 344    #endif
 345}
 346/*-----------------------------------------------------------*/
 347
 348static void prvCreateAndDeleteStaticallyAllocatedQueues( void )
 349{
 350QueueHandle_t xQueue;
 351
 352/* StaticQueue_t is a publicly accessible structure that has the same size and
 353alignment requirements as the real queue structure.  It is provided as a
 354mechanism for applications to know the size of the queue (which is dependent on
 355the architecture and configuration file settings) without breaking the strict
 356data hiding policy by exposing the real queue internals.  This StaticQueue_t
 357variable is passed into the xQueueCreateStatic() function calls within this
 358function. */
 359static StaticQueue_t xStaticQueue;
 360
 361/* The queue storage area must be large enough to hold the maximum number of
 362items it is possible for the queue to hold at any one time, which equals the
 363queue length (in items, not bytes) multiplied by the size of each item.  In this
 364case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items.  See
 365http://www.freertos.org/Embedded-RTOS-Queues.html */
 366static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];
 367
 368    /* Create the queue.  xQueueCreateStatic() has two more parameters than the
 369    usual xQueueCreate() function.  The first new parameter is a pointer to the
 370    pre-allocated queue storage area.  The second new parameter is a pointer to
 371    the StaticQueue_t structure that will hold the queue state information in
 372    an anonymous way.  If the two pointers are passed as NULL then the data
 373    will be allocated dynamically as if xQueueCreate() had been called. */
 374    xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
 375                                 sizeof( uint64_t ), /* The size of each item. */
 376                                 ucQueueStorageArea, /* The buffer used to hold items within the queue. */
 377                                 &xStaticQueue );    /* The static queue structure that will hold the state of the queue. */
 378
 379    /* The queue handle should equal the static queue structure passed into the
 380    xQueueCreateStatic() function. */
 381    configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
 382
 383    /* Ensure the queue passes a few sanity checks as a valid queue. */
 384    prvSanityCheckCreatedQueue( xQueue );
 385
 386    /* Delete the queue again so the buffers can be reused. */
 387    vQueueDelete( xQueue );
 388
 389    /* Now do the same using a dynamically allocated queue to ensure the delete
 390    function is working correctly in both the static and dynamic memory
 391    allocation cases. */
 392    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 393    {
 394        xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
 395                               sizeof( uint64_t ) );        /* The size of each item. */
 396
 397        /* The queue handle should equal the static queue structure passed into the
 398        xQueueCreateStatic() function. */
 399        configASSERT( xQueue != NULL );
 400
 401        /* Ensure the queue passes a few sanity checks as a valid queue. */
 402        prvSanityCheckCreatedQueue( xQueue );
 403
 404        /* Delete the queue again so the buffers can be reused. */
 405        vQueueDelete( xQueue );
 406    }
 407    #endif
 408}
 409/*-----------------------------------------------------------*/
 410
 411static void prvCreateAndDeleteStaticallyAllocatedMutexes( void )
 412{
 413SemaphoreHandle_t xSemaphore;
 414BaseType_t xReturned;
 415
 416/* StaticSemaphore_t is a publicly accessible structure that has the same size
 417and alignment requirements as the real semaphore structure.  It is provided as a
 418mechanism for applications to know the size of the semaphore (which is dependent
 419on the architecture and configuration file settings) without breaking the strict
 420data hiding policy by exposing the real semaphore internals.  This
 421StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic()
 422function calls within this function. */
 423StaticSemaphore_t xSemaphoreBuffer;
 424
 425    /* Create the semaphore.  xSemaphoreCreateMutexStatic() has one more
 426    parameter than the usual xSemaphoreCreateMutex() function.  The parameter
 427    is a pointer to the pre-allocated StaticSemaphore_t structure, which will
 428    hold information on the semaphore in an anonymous way.  If the pointer is
 429    passed as NULL then the structure will be allocated dynamically, just as
 430    when xSemaphoreCreateMutex() is called. */
 431    xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer );
 432
 433    /* The semaphore handle should equal the static semaphore structure passed
 434    into the xSemaphoreCreateMutexStatic() function. */
 435    configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
 436
 437    /* Take the mutex so the mutex is in the state expected by the
 438    prvSanityCheckCreatedSemaphore() function. */
 439    xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
 440
 441    if( xReturned != pdPASS )
 442    {
 443        xErrorOccurred = pdTRUE;
 444    }
 445
 446    /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
 447    prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
 448
 449    /* Delete the semaphore again so the buffers can be reused. */
 450    vSemaphoreDelete( xSemaphore );
 451
 452    /* Now do the same using a dynamically allocated mutex to ensure the delete
 453    function is working correctly in both the static and dynamic allocation
 454    cases. */
 455    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 456    {
 457        xSemaphore = xSemaphoreCreateMutex();
 458
 459        /* The semaphore handle should equal the static semaphore structure
 460        passed into the xSemaphoreCreateMutexStatic() function. */
 461        configASSERT( xSemaphore != NULL );
 462
 463        /* Take the mutex so the mutex is in the state expected by the
 464        prvSanityCheckCreatedSemaphore() function. */
 465        xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
 466
 467        if( xReturned != pdPASS )
 468        {
 469            xErrorOccurred = pdTRUE;
 470        }
 471
 472        /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
 473        prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
 474
 475        /* Delete the semaphore again so the buffers can be reused. */
 476        vSemaphoreDelete( xSemaphore );
 477    }
 478    #endif
 479}
 480/*-----------------------------------------------------------*/
 481
 482static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )
 483{
 484SemaphoreHandle_t xSemaphore;
 485
 486/* StaticSemaphore_t is a publicly accessible structure that has the same size
 487and alignment requirements as the real semaphore structure.  It is provided as a
 488mechanism for applications to know the size of the semaphore (which is dependent
 489on the architecture and configuration file settings) without breaking the strict
 490data hiding policy by exposing the real semaphore internals.  This
 491StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic()
 492function calls within this function.  NOTE: In most usage scenarios now it is
 493faster and more memory efficient to use a direct to task notification instead of
 494a binary semaphore.  http://www.freertos.org/RTOS-task-notifications.html */
 495StaticSemaphore_t xSemaphoreBuffer;
 496
 497    /* Create the semaphore.  xSemaphoreCreateBinaryStatic() has one more
 498    parameter than the usual xSemaphoreCreateBinary() function.  The parameter
 499    is a pointer to the pre-allocated StaticSemaphore_t structure, which will
 500    hold information on the semaphore in an anonymous way.  If the pointer is
 501    passed as NULL then the structure will be allocated dynamically, just as
 502    when xSemaphoreCreateBinary() is called. */
 503    xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
 504
 505    /* The semaphore handle should equal the static semaphore structure passed
 506    into the xSemaphoreCreateBinaryStatic() function. */
 507    configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
 508
 509    /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
 510    prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
 511
 512    /* Delete the semaphore again so the buffers can be reused. */
 513    vSemaphoreDelete( xSemaphore );
 514
 515    /* Now do the same using a dynamically allocated semaphore to check the
 516    delete function is working correctly in both the static and dynamic
 517    allocation cases. */
 518    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 519    {
 520        xSemaphore = xSemaphoreCreateBinary();
 521        configASSERT( xSemaphore != NULL );
 522        prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
 523        vSemaphoreDelete( xSemaphore );
 524    }
 525    #endif
 526
 527    /* There isn't a static version of the old and deprecated
 528    vSemaphoreCreateBinary() macro (because its deprecated!), but check it is
 529    still functioning correctly. */
 530    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 531    {
 532        vSemaphoreCreateBinary( xSemaphore );
 533
 534        /* The macro starts with the binary semaphore available, but the test
 535        function expects it to be unavailable. */
 536        if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )
 537        {
 538            xErrorOccurred = pdTRUE;
 539        }
 540
 541        prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
 542        vSemaphoreDelete( xSemaphore );
 543    }
 544    #endif
 545}
 546/*-----------------------------------------------------------*/
 547
 548static void prvTimerCallback( TimerHandle_t xExpiredTimer )
 549{
 550UBaseType_t *puxVariableToIncrement;
 551BaseType_t xReturned;
 552
 553    /* The timer callback just demonstrates it is executing by incrementing a
 554    variable - the address of which is passed into the timer as its ID.  Obtain
 555    the address of the variable to increment. */
 556    puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );
 557
 558    /* Increment the variable to show the timer callback has executed. */
 559    ( *puxVariableToIncrement )++;
 560
 561    /* If this callback has executed the required number of times, stop the
 562    timer. */
 563    if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS )
 564    {
 565        /* This is called from a timer callback so must not block.  See
 566        http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */
 567        xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK );
 568
 569        if( xReturned != pdPASS )
 570        {
 571            xErrorOccurred = pdTRUE;
 572        }
 573    }
 574}
 575/*-----------------------------------------------------------*/
 576
 577static void prvCreateAndDeleteStaticallyAllocatedTimers( void )
 578{
 579TimerHandle_t xTimer;
 580UBaseType_t uxVariableToIncrement;
 581const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 );
 582BaseType_t xReturned;
 583
 584/* StaticTimer_t is a publicly accessible structure that has the same size
 585and alignment requirements as the real timer structure.  It is provided as a
 586mechanism for applications to know the size of the timer structure (which is
 587dependent on the architecture and configuration file settings) without breaking
 588the strict data hiding policy by exposing the real timer internals.  This
 589StaticTimer_t variable is passed into the xTimerCreateStatic() function calls
 590within this function. */
 591StaticTimer_t xTimerBuffer;
 592
 593    /* Create the software time.  xTimerCreateStatic() has an extra parameter
 594    than the normal xTimerCreate() API function.  The parameter is a pointer to
 595    the StaticTimer_t structure that will hold the software timer structure.  If
 596    the parameter is passed as NULL then the structure will be allocated
 597    dynamically, just as if xTimerCreate() had been called. */
 598    xTimer = xTimerCreateStatic( "T1",                  /* Text name for the task.  Helps debugging only.  Not used by FreeRTOS. */
 599                                 xTimerPeriod,          /* The period of the timer in ticks. */
 600                                 pdTRUE,                /* This is an auto-reload timer. */
 601                                 ( void * ) &uxVariableToIncrement, /* The variable incremented by the test is passed into the timer callback using the timer ID. */
 602                                 prvTimerCallback,      /* The function to execute when the timer expires. */
 603                                 &xTimerBuffer );       /* The buffer that will hold the software timer structure. */
 604
 605    /* The timer handle should equal the static timer structure passed into the
 606    xTimerCreateStatic() function. */
 607    configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer );
 608
 609    /* Set the variable to 0, wait for a few timer periods to expire, then check
 610    the timer callback has incremented the variable to the expected value. */
 611    uxVariableToIncrement = 0;
 612
 613    /* This is a low priority so a block time should not be needed. */
 614    xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
 615
 616    if( xReturned != pdPASS )
 617    {
 618        xErrorOccurred = pdTRUE;
 619    }
 620
 621    vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
 622
 623    /* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS
 624    times, and then stopped itself. */
 625    if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
 626    {
 627        xErrorOccurred = pdTRUE;
 628    }
 629
 630    /* Finished with the timer, delete it. */
 631    xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
 632
 633    /* Again, as this is a low priority task it is expected that the timer
 634    command will have been sent even without a block time being used. */
 635    if( xReturned != pdPASS )
 636    {
 637        xErrorOccurred = pdTRUE;
 638    }
 639
 640    /* Just to show the check task that this task is still executing. */
 641    uxCycleCounter++;
 642
 643    /* Now do the same using a dynamically allocated software timer to ensure
 644    the delete function is working correctly in both the static and dynamic
 645    allocation cases. */
 646    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 647    {
 648        xTimer = xTimerCreate( "T1",                                /* Text name for the task.  Helps debugging only.  Not used by FreeRTOS. */
 649                                xTimerPeriod,                       /* The period of the timer in ticks. */
 650                                pdTRUE,                             /* This is an auto-reload timer. */
 651                                ( void * ) &uxVariableToIncrement,  /* The variable incremented by the test is passed into the timer callback using the timer ID. */
 652                                prvTimerCallback );                 /* The function to execute when the timer expires. */
 653
 654        configASSERT( xTimer != NULL );
 655
 656        uxVariableToIncrement = 0;
 657        xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
 658
 659        if( xReturned != pdPASS )
 660        {
 661            xErrorOccurred = pdTRUE;
 662        }
 663
 664        vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
 665
 666        if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
 667        {
 668            xErrorOccurred = pdTRUE;
 669        }
 670
 671        xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
 672
 673        if( xReturned != pdPASS )
 674        {
 675            xErrorOccurred = pdTRUE;
 676        }
 677    }
 678    #endif
 679}
 680/*-----------------------------------------------------------*/
 681
 682static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void )
 683{
 684EventGroupHandle_t xEventGroup;
 685
 686/* StaticEventGroup_t is a publicly accessible structure that has the same size
 687and alignment requirements as the real event group structure.  It is provided as
 688a mechanism for applications to know the size of the event group (which is
 689dependent on the architecture and configuration file settings) without breaking
 690the strict data hiding policy by exposing the real event group internals.  This
 691StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic()
 692function calls within this function. */
 693StaticEventGroup_t xEventGroupBuffer;
 694
 695    /* Create the event group.  xEventGroupCreateStatic() has an extra parameter
 696    than the normal xEventGroupCreate() API function.  The parameter is a
 697    pointer to the StaticEventGroup_t structure that will hold the event group
 698    structure. */
 699    xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
 700
 701    /* The event group handle should equal the static event group structure
 702    passed into the xEventGroupCreateStatic() function. */
 703    configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer );
 704
 705    /* Ensure the event group passes a few sanity checks as a valid event
 706    group. */
 707    prvSanityCheckCreatedEventGroup( xEventGroup );
 708
 709    /* Delete the event group again so the buffers can be reused. */
 710    vEventGroupDelete( xEventGroup );
 711
 712    /* Now do the same using a dynamically allocated event group to ensure the
 713    delete function is working correctly in both the static and dynamic
 714    allocation cases. */
 715    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 716    {
 717        xEventGroup = xEventGroupCreate();
 718        configASSERT( xEventGroup != NULL );
 719        prvSanityCheckCreatedEventGroup( xEventGroup );
 720        vEventGroupDelete( xEventGroup );
 721    }
 722    #endif
 723}
 724/*-----------------------------------------------------------*/
 725
 726static void prvCreateAndDeleteStaticallyAllocatedTasks( void )
 727{
 728TaskHandle_t xCreatedTask;
 729
 730/* The variable that will hold the TCB of tasks created by this function.  See
 731the comments above the declaration of the xCreatorTaskTCBBuffer variable for
 732more information.  NOTE:  This is not static so relies on the tasks that use it
 733being deleted before this function returns and deallocates its stack.  That will
 734only be the case if configUSE_PREEMPTION is set to 1. */
 735StaticTask_t xTCBBuffer;
 736
 737/* This buffer that will be used as the stack of tasks created by this function.
 738See the comments above the declaration of the uxCreatorTaskStackBuffer[] array
 739above for more information. */
 740static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
 741
 742    /* Create the task.  xTaskCreateStatic() has two more parameters than
 743    the usual xTaskCreate() function.  The first new parameter is a pointer to
 744    the pre-allocated stack.  The second new parameter is a pointer to the
 745    StaticTask_t structure that will hold the task's TCB.  If both pointers are
 746    passed as NULL then the respective object will be allocated dynamically as
 747    if xTaskCreate() had been called. */
 748    xCreatedTask = xTaskCreateStatic(
 749                        prvStaticallyAllocatedTask,     /* Function that implements the task. */
 750                        "Static",                       /* Human readable name for the task. */
 751                        configMINIMAL_STACK_SIZE,       /* Task's stack size, in words (not bytes!). */
 752                        NULL,                           /* Parameter to pass into the task. */
 753                        uxTaskPriorityGet( NULL ) + 1,  /* The priority of the task. */
 754                        &( uxStackBuffer[ 0 ] ),        /* The buffer to use as the task's stack. */
 755                        &xTCBBuffer );                  /* The variable that will hold that task's TCB. */
 756
 757    /* Check the task was created correctly, then delete the task. */
 758    if( xCreatedTask == NULL )
 759    {
 760        xErrorOccurred = pdTRUE;
 761    }
 762    else if( eTaskGetState( xCreatedTask ) != eSuspended )
 763    {
 764        /* The created task had a higher priority so should have executed and
 765        suspended itself by now. */
 766        xErrorOccurred = pdTRUE;
 767    }
 768    else
 769    {
 770        vTaskDelete( xCreatedTask );
 771    }
 772
 773    /* Now do the same using a dynamically allocated task to ensure the delete
 774    function is working correctly in both the static and dynamic allocation
 775    cases. */
 776    #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 777    {
 778    BaseType_t xReturned;
 779
 780        xReturned = xTaskCreate(
 781                                    prvStaticallyAllocatedTask,     /* Function that implements the task - the same function is used but is actually dynamically allocated this time. */
 782                                    "Static",                       /* Human readable name for the task. */
 783                                    configMINIMAL_STACK_SIZE,       /* Task's stack size, in words (not bytes!). */
 784                                    NULL,                           /* Parameter to pass into the task. */
 785                                    uxTaskPriorityGet( NULL ) + 1,  /* The priority of the task. */
 786                                    &xCreatedTask );                /* Handle of the task being created. */
 787
 788        if( eTaskGetState( xCreatedTask ) != eSuspended )
 789        {
 790            xErrorOccurred = pdTRUE;
 791        }
 792
 793        configASSERT( xReturned == pdPASS );
 794        if( xReturned != pdPASS )
 795        {
 796            xErrorOccurred = pdTRUE;
 797        }
 798        vTaskDelete( xCreatedTask );
 799    }
 800    #endif
 801}
 802/*-----------------------------------------------------------*/
 803
 804static void prvStaticallyAllocatedTask( void *pvParameters )
 805{
 806    ( void ) pvParameters;
 807
 808    /* The created task just suspends itself to wait to get deleted.  The task
 809    that creates this task checks this task is in the expected Suspended state
 810    before deleting it. */
 811    vTaskSuspend( NULL );
 812}
 813/*-----------------------------------------------------------*/
 814
 815static UBaseType_t prvRand( void )
 816{
 817const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
 818
 819    /* Utility function to generate a pseudo random number. */
 820    ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
 821    return( ( ulNextRand >> 16UL ) & 0x7fffUL );
 822}
 823/*-----------------------------------------------------------*/
 824
 825static TickType_t prvGetNextDelayTime( void )
 826{
 827TickType_t xNextDelay;
 828const TickType_t xMaxDelay = pdMS_TO_TICKS( ( TickType_t ) 150 );
 829const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 );
 830const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 );
 831
 832    /* Generate the next delay time.  This is kept within a narrow band so as
 833    not to disturb the timing of other tests - but does add in some pseudo
 834    randomisation into the tests. */
 835    do
 836    {
 837        xNextDelay = prvRand() % xMaxDelay;
 838
 839        /* Just in case this loop is executed lots of times. */
 840        vTaskDelay( xTinyDelay );
 841
 842    } while ( xNextDelay < xMinDelay );
 843
 844    return xNextDelay;
 845}
 846/*-----------------------------------------------------------*/
 847
 848static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup )
 849{
 850EventBits_t xEventBits;
 851const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55;
 852
 853    /* The event group should not have any bits set yet. */
 854    xEventBits = xEventGroupGetBits( xEventGroup );
 855
 856    if( xEventBits != ( EventBits_t ) 0 )
 857    {
 858        xErrorOccurred = pdTRUE;
 859    }
 860
 861    /* Some some bits, then read them back to check they are as expected. */
 862    xEventGroupSetBits( xEventGroup, xFirstTestBits );
 863
 864    xEventBits = xEventGroupGetBits( xEventGroup );
 865
 866    if( xEventBits != xFirstTestBits )
 867    {
 868        xErrorOccurred = pdTRUE;
 869    }
 870
 871    xEventGroupSetBits( xEventGroup, xSecondTestBits );
 872
 873    xEventBits = xEventGroupGetBits( xEventGroup );
 874
 875    if( xEventBits != ( xFirstTestBits | xSecondTestBits ) )
 876    {
 877        xErrorOccurred = pdTRUE;
 878    }
 879
 880    /* Finally try clearing some bits too and check that operation proceeds as
 881    expected. */
 882    xEventGroupClearBits( xEventGroup, xFirstTestBits );
 883
 884    xEventBits = xEventGroupGetBits( xEventGroup );
 885
 886    if( xEventBits != xSecondTestBits )
 887    {
 888        xErrorOccurred = pdTRUE;
 889    }
 890}
 891/*-----------------------------------------------------------*/
 892
 893static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount )
 894{
 895BaseType_t xReturned;
 896UBaseType_t x;
 897const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );
 898TickType_t xTickCount;
 899
 900    /* The binary semaphore should start 'empty', so a call to xSemaphoreTake()
 901    should fail. */
 902    xTickCount = xTaskGetTickCount();
 903    xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
 904
 905    if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
 906    {
 907        /* Did not block on the semaphore as long as expected. */
 908        xErrorOccurred = pdTRUE;
 909    }
 910
 911    if( xReturned != pdFAIL )
 912    {
 913        xErrorOccurred = pdTRUE;
 914    }
 915
 916    /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount
 917    times. */
 918    for( x = 0; x < uxMaxCount; x++ )
 919    {
 920        xReturned = xSemaphoreGive( xSemaphore );
 921
 922        if( xReturned == pdFAIL )
 923        {
 924            xErrorOccurred = pdTRUE;
 925        }
 926    }
 927
 928    /* Giving the semaphore again should fail, as it is 'full'. */
 929    xReturned = xSemaphoreGive( xSemaphore );
 930
 931    if( xReturned != pdFAIL )
 932    {
 933        xErrorOccurred = pdTRUE;
 934    }
 935
 936    configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );
 937
 938    /* Should now be possible to 'take' the semaphore up to a maximum of
 939    uxMaxCount times without blocking. */
 940    for( x = 0; x < uxMaxCount; x++ )
 941    {
 942        xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
 943
 944        if( xReturned == pdFAIL )
 945        {
 946            xErrorOccurred = pdTRUE;
 947        }
 948    }
 949
 950    /* Back to the starting condition, where the semaphore should not be
 951    available. */
 952    xTickCount = xTaskGetTickCount();
 953    xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
 954
 955    if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
 956    {
 957        /* Did not block on the semaphore as long as expected. */
 958        xErrorOccurred = pdTRUE;
 959    }
 960
 961    if( xReturned != pdFAIL )
 962    {
 963        xErrorOccurred = pdTRUE;
 964    }
 965
 966    configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
 967}
 968/*-----------------------------------------------------------*/
 969
 970static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue )
 971{
 972uint64_t ull, ullRead;
 973BaseType_t xReturned, xLoop;
 974
 975    /* This test is done twice to ensure the queue storage area wraps. */
 976    for( xLoop = 0; xLoop < 2; xLoop++ )
 977    {
 978        /* A very basic test that the queue can be written to and read from as
 979        expected.  First the queue should be empty. */
 980        xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
 981        if( xReturned != errQUEUE_EMPTY )
 982        {
 983            xErrorOccurred = pdTRUE;
 984        }
 985
 986        /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS
 987        times. */
 988        for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
 989        {
 990            xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
 991            if( xReturned != pdPASS )
 992            {
 993                xErrorOccurred = pdTRUE;
 994            }
 995        }
 996
 997        /* Should not now be possible to write to the queue again. */
 998        xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
 999        if( xReturned != errQUEUE_FULL )
1000        {
1001            xErrorOccurred = pdTRUE;
1002        }
1003
1004        /* Now read back from the queue to ensure the data read back matches that
1005        written. */
1006        for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
1007        {
1008            xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );
1009
1010            if( xReturned != pdPASS )
1011            {
1012                xErrorOccurred = pdTRUE;
1013            }
1014
1015            if( ullRead != ull )
1016            {
1017                xErrorOccurred = pdTRUE;
1018            }
1019        }
1020
1021        /* The queue should be empty again. */
1022        xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
1023        if( xReturned != errQUEUE_EMPTY )
1024        {
1025            xErrorOccurred = pdTRUE;
1026        }
1027    }
1028}
1029/*-----------------------------------------------------------*/
1030
1031static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore )
1032{
1033const BaseType_t xLoops = 5;
1034BaseType_t x, xReturned;
1035
1036    /* A very basic test that the recursive semaphore behaved like a recursive
1037    semaphore. First the semaphore should not be able to be given, as it has not
1038    yet been taken. */
1039    xReturned = xSemaphoreGiveRecursive( xSemaphore );
1040
1041    if( xReturned != pdFAIL )
1042    {
1043        xErrorOccurred = pdTRUE;
1044    }
1045
1046    /* Now it should be possible to take the mutex a number of times. */
1047    for( x = 0; x < xLoops; x++ )
1048    {
1049        xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK );
1050
1051        if( xReturned != pdPASS )
1052        {
1053            xErrorOccurred = pdTRUE;
1054        }
1055    }
1056
1057    /* Should be possible to give the semaphore the same number of times as it
1058    was given in the loop above. */
1059    for( x = 0; x < xLoops; x++ )
1060    {
1061        xReturned = xSemaphoreGiveRecursive( xSemaphore );
1062
1063        if( xReturned != pdPASS )
1064        {
1065            xErrorOccurred = pdTRUE;
1066        }
1067    }
1068
1069    /* No more gives should be possible though. */
1070    xReturned = xSemaphoreGiveRecursive( xSemaphore );
1071
1072    if( xReturned != pdFAIL )
1073    {
1074        xErrorOccurred = pdTRUE;
1075    }
1076}
1077/*-----------------------------------------------------------*/
1078
1079BaseType_t xAreStaticAllocationTasksStillRunning( void )
1080{
1081static UBaseType_t uxLastCycleCounter = 0;
1082BaseType_t xReturn;
1083
1084    if( uxCycleCounter == uxLastCycleCounter )
1085    {
1086        xErrorOccurred = pdTRUE;
1087    }
1088    else
1089    {
1090        uxLastCycleCounter = uxCycleCounter;
1091    }
1092
1093    if( xErrorOccurred != pdFALSE )
1094    {
1095        xReturn = pdFAIL;
1096    }
1097    else
1098    {
1099        xReturn = pdPASS;
1100    }
1101
1102    return xReturn;
1103}
1104/*-----------------------------------------------------------*/
1105
1106/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
1107#endif /* configSUPPORT_STATIC_ALLOCATION == 1 */
相关文章
|
存储 编译器 C++
【C/C++】 静态内存分配与动态内存分配
C/C++ 中静态内存分配与动态内存分配相关内容,区别与比较
337 0
|
存储 算法 编译器
12-FreeRTOS内存管理
12-FreeRTOS内存管理
|
程序员 C++
【C/C++动态内存 or 柔性数组】——对动态内存分配以及柔性数组的概念进行详细解读(张三 or 李四)
【C/C++动态内存 or 柔性数组】——对动态内存分配以及柔性数组的概念进行详细解读(张三 or 李四)
113 0
|
4月前
|
存储 分布式计算 Hadoop
HadoopCPU、内存、存储限制
【7月更文挑战第13天】
283 14
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
376 0
|
24天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
50 1
|
28天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
1月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
1月前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
41 4
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
53 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配