Browse Source

updated .gitignore

added source
wrote README
master
Hendrik Schutter 3 years ago
parent
commit
d2e9b4a0b7
  1. 3
      .gitignore
  2. 127
      Makefile
  3. 70
      Project/FreeRTOSConfig.h
  4. 171
      Project/demo.c
  5. 54
      Project/demo.h
  6. 92
      Project/nodes.c
  7. 33
      README.md
  8. 395
      Source/croutine.c
  9. 752
      Source/event_groups.c
  10. 1063
      Source/include/FreeRTOS.h
  11. 171
      Source/include/StackMacros.h
  12. 762
      Source/include/croutine.h
  13. 321
      Source/include/deprecated_definitions.h
  14. 797
      Source/include/event_groups.h
  15. 453
      Source/include/list.h
  16. 177
      Source/include/mpu_prototypes.h
  17. 201
      Source/include/mpu_wrappers.h
  18. 207
      Source/include/portable.h
  19. 161
      Source/include/projdefs.h
  20. 1798
      Source/include/queue.h
  21. 1171
      Source/include/semphr.h
  22. 27
      Source/include/stdint.readme
  23. 2267
      Source/include/task.h
  24. 1314
      Source/include/timers.h
  25. 240
      Source/list.c
  26. 787
      Source/portable/GCC/POSIX/port.c
  27. 128
      Source/portable/GCC/POSIX/portmacro.h
  28. 174
      Source/portable/MemMang/heap_1.c
  29. 303
      Source/portable/MemMang/heap_2.c
  30. 135
      Source/portable/MemMang/heap_3.c
  31. 474
      Source/portable/MemMang/heap_4.c
  32. 523
      Source/portable/MemMang/heap_5.c
  33. 2566
      Source/queue.c
  34. 17
      Source/readme.txt
  35. 4811
      Source/tasks.c
  36. 1092
      Source/timers.c

3
.gitignore vendored

@ -125,3 +125,6 @@ Module.symvers
Mkfile.old
dkms.conf
obj/
FreeRTOS-Demo

127
Makefile

@ -0,0 +1,127 @@
# ######## Build options ########
verbose = 0
######## Build setup ########
# SRCROOT should always be the current directory
SRCROOT = $(CURDIR)
# .o directory
ODIR = obj
# Source VPATHS
VPATH += $(SRCROOT)/Source
VPATH += $(SRCROOT)/Source/portable/MemMang
VPATH += $(SRCROOT)/Source/portable/GCC/POSIX
VPATH += $(SRCROOT)/Project/FileIO
VPATH += $(SRCROOT)/Project
# FreeRTOS Objects
C_FILES += croutine.c
C_FILES += event_groups.c
C_FILES += list.c
C_FILES += queue.c
C_FILES += tasks.c
C_FILES += timers.c
# portable Objects
C_FILES += heap_3.c
C_FILES += port.c
# Main Object
C_FILES += demo.c
C_FILES += nodes.c
# Include Paths
INCLUDES += -I$(SRCROOT)/Source/include
INCLUDES += -I$(SRCROOT)/Source/portable/GCC/POSIX/
INCLUDES += -I$(SRCROOT)/Project
# Generate OBJS names
OBJS = $(patsubst %.c,%.o,$(C_FILES))
######## C Flags ########
# Warnings
CWARNS += -W
CWARNS += -Wall
CWARNS += -Werror
CWARNS += -Wextra
CWARNS += -Wformat
CWARNS += -Wmissing-braces
CWARNS += -Wno-cast-align
CWARNS += -Wparentheses
CWARNS += -Wshadow
CWARNS += -Wno-sign-compare
CWARNS += -Wswitch
CWARNS += -Wuninitialized
CWARNS += -Wunknown-pragmas
CWARNS += -Wunused-function
CWARNS += -Wunused-label
CWARNS += -Wunused-parameter
CWARNS += -Wunused-value
CWARNS += -Wunused-variable
#CWARNS += -Wmissing-prototypes
#CWARNS += -Wno-unused-function
CFLAGS += -m32
CFLAGS += -DDEBUG=1
#CFLAGS += -g -DUSE_STDIO=1 -D__GCC_POSIX__=1
CFLAGS += -g -UUSE_STDIO -D__GCC_POSIX__=1
ifneq ($(shell uname), Darwin)
CFLAGS += -pthread
endif
# MAX_NUMBER_OF_TASKS = max pthreads used in the POSIX port.
# Default value is 64 (_POSIX_THREAD_THREADS_MAX), the minimum number required by POSIX.
CFLAGS += -DMAX_NUMBER_OF_TASKS=300
CFLAGS += $(INCLUDES) $(CWARNS) -O2
######## Makefile targets ########
# Rules
.PHONY : all
all: setup FreeRTOS-Demo
.PHONY : setup
setup:
# Make obj directory
@mkdir -p $(ODIR)
# Fix to place .o files in ODIR
_OBJS = $(patsubst %,$(ODIR)/%,$(OBJS))
$(ODIR)/%.o: %.c
# If verbose, print gcc execution, else hide
ifeq ($(verbose),1)
@echo ">> Compiling $<"
$(CC) $(CFLAGS) -c -o $@ $<
else
@echo ">> Compiling $(notdir $<)"
@$(CC) $(CFLAGS) -c -o $@ $<
endif
FreeRTOS-Demo: $(_OBJS)
@echo ">> Linking $@..."
ifeq ($(verbose),1)
$(CC) $(CFLAGS) $^ $(LINKFLAGS) $(LIBS) -o $@
else
@$(CC) $(CFLAGS) $^ $(LINKFLAGS) $(LIBS) -o $@
endif
@echo "-------------------------"
@echo "BUILD COMPLETE: $@"
@echo "-------------------------"
.PHONY : clean
clean:
@-rm -rf $(ODIR) FreeRTOS-Demo
@echo "--------------"
@echo "CLEAN COMPLETE"
@echo "--------------"

70
Project/FreeRTOSConfig.h

@ -0,0 +1,70 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 1
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 64 ) /* 64words x 4byte = 256byte */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024) ) /* 65536words x 4byte = 256Kbyte */
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configCHECK_FOR_STACK_OVERFLOW 0 /* Do not use this option on the PC port. */
#define configUSE_RECURSIVE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 20
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0
//#define configMAX_SYSCALL_INTERRUPT_PRIORITY 1
#define configUSE_QUEUE_SETS 1
#define configUSE_TASK_NOTIFICATIONS 1
/* Software timer related configuration options. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 20
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
#define configMAX_PRIORITIES ( 10 )
#define configGENERATE_RUN_TIME_STATS 1
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. In most cases the linker will remove unused
functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0 /* Do not use this option on the PC port. */
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#endif /* FREERTOS_CONFIG_H */

171
Project/demo.c

@ -0,0 +1,171 @@
/*
* This file is part of the distribution https://git.mosad.xyz/localhorst/ParallelTrafficRouter_FreeRTOS
* Copyright (c) 2019 Hendrik Schutter.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "demo.h"
#define SIMULATE_COST
SemaphoreHandle_t xMutexData;
void vApplicationMallocFailedHook( void );
void vApplicationIdleHook( void );
void vApplicationTickHook( void );
void search(void* arguments);
void show(void* arguments);
int main()
{
printf("starting routing ...\n");
xMutexData = xSemaphoreCreateMutex();
THREAD_DATA_t* data;
data = (THREAD_DATA_t*) pvPortMalloc(sizeof(THREAD_DATA_t));
data->node = getStartNode();
data->cost = 0;
data->depth = 0;
data->predecessors[0] = data->node->id;
data->bestpath = (BESTPATH_t*) pvPortMalloc(sizeof(BESTPATH_t));
data->bestpath->lowestCost = -1;
data->bestpath->depth = 0;
xTaskCreate(search, "startTask", configMINIMAL_STACK_SIZE, (void*) data, 1, 0);
xTaskCreate(show, "showTask", configMINIMAL_STACK_SIZE, (void*) data, 0, 0);
vTaskStartScheduler();
return 0;
}
void search(void* arguments)
{
THREAD_DATA_t *data = (THREAD_DATA_t*) arguments;
printf("Node: %i reached\n", data->node->id);
#ifdef SIMULATE_COST
vTaskDelay(((data->cost)*20)/ portTICK_PERIOD_MS); //receive data for route
#endif
if(data->node->id == 8) //end node reached
{
printf("Route found! Cost: %i\n", data->cost);
xSemaphoreTake( xMutexData, ( TickType_t ) 1 );
if((data->bestpath->lowestCost == -1) || (data->bestpath->lowestCost > data->cost))
//first route found or better route found
{
data->bestpath->lowestCost = data->cost;
data->bestpath->depth = data->depth;
for(int j = 0; j < data->depth; j++)
{
data->bestpath->predecessorsBestPath[j] = data->predecessors[j];
}
data->bestpath->predecessorsBestPath[(data->bestpath->depth)] = data->node->id;
}
xSemaphoreGive( xMutexData );
}
else
{
//create new tasks
for(int i = 0; i < data->node->nodescount; i++)
{
THREAD_DATA_t* nextdata;
nextdata = (THREAD_DATA_t*) pvPortMalloc(sizeof(THREAD_DATA_t));
//nextdata = (THREAD_DATA_t*) pvPortMalloc(1000000000);
nextdata->node = (data->node->nodesnext[i]);
nextdata->bestpath = data->bestpath;
nextdata->cost = data->node->nodescost[i] + data->cost; //sum up cost
nextdata->depth = data->depth + 1;
for(int j = 0; j < data->depth; j++) {
nextdata->predecessors[j] = data->predecessors[j];
}
nextdata->predecessors[((nextdata->depth) - 1)] = data->node->id;
xTaskCreate(search, "searchTask", configMINIMAL_STACK_SIZE, (void*) nextdata, 2, 0);
}
}
printf("Node: %i exit\n", data->node->id);
vTaskDelete( NULL );
}
void show(void* arguments)
{
THREAD_DATA_t *data = (THREAD_DATA_t*) arguments;
for(;;)
{
xSemaphoreTake( xMutexData, ( TickType_t ) 1 );
if(data->bestpath->lowestCost > -1)
{
printf("\nBest route: %i", data->bestpath->predecessorsBestPath[0]);
for(int i = 1; i <= data->bestpath->depth; i++) {
printf(" --> %i", data->bestpath->predecessorsBestPath[i]);
}
printf("\nWith cost of: %i\n", data->bestpath->lowestCost);
}
xSemaphoreGive( xMutexData );
vTaskDelay(1000 / portTICK_PERIOD_MS); //wait 1sec
}
vTaskDelete( NULL );
}
void vApplicationMallocFailedHook( void )
{
printf("Malloc failed\n");
}
void vApplicationIdleHook( void )
{
//printf("No tasks to do\n");
}
void vApplicationTickHook( void )
{
//printf("TickHook\n");
}

54
Project/demo.h

@ -0,0 +1,54 @@
/*
* This file is part of the distribution https://git.mosad.xyz/localhorst/ParallelTrafficRouter_FreeRTOS
* Copyright (c) 2019 Hendrik Schutter.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEMO_H
#define DEMO_H
#define MAX_CHILDREN 3
#define MAX_DEPTH 4
typedef struct node NODE_t;
typedef struct threadData THREAD_DATA_t;
typedef struct bestPath BESTPATH_t;
extern NODE_t* getStartNode();
struct node {
int id; //identifier for this node
int nodescount; //how many children nodes
NODE_t* nodesnext[MAX_CHILDREN]; //array of children nodes
int nodescost[MAX_CHILDREN]; //array of cost per children node
};
struct threadData {
int depth; //depth of the next node, e.g. start --> 0
NODE_t* node; //next node to go
int cost; //cost for the next node
int predecessors[MAX_DEPTH]; // array with all predecessor
BESTPATH_t* bestpath;
};
struct bestPath {
int lowestCost;
int predecessorsBestPath[MAX_DEPTH]; // array with all predecessor of the best path
int depth; //depth of the best path, aka. how many nodes
};
#endif /* DEMO_H */

92
Project/nodes.c

@ -0,0 +1,92 @@
/*
* This file is part of the distribution https://git.mosad.xyz/localhorst/ParallelTrafficRouter_FreeRTOS
* Copyright (c) 2019 Hendrik Schutter.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "demo.h"
#include "FreeRTOS.h"
NODE_t* getStartNode();
NODE_t* getStartNode() {
static NODE_t* start;
static NODE_t* g;
static NODE_t* f;
static NODE_t* e;
static NODE_t* d;
static NODE_t* c;
static NODE_t* b;
static NODE_t* a;
static NODE_t* end;
start = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
a = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
b = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
c = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
d = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
e = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
f = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
g = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
end = (NODE_t*) pvPortMalloc(sizeof(NODE_t));
end->id = 8;
end->nodescount = 0;
g->id = 7;
g->nodescount = 0;
f->id = 6;
f->nodescount = 1;
f->nodesnext[0] = end;
f->nodescost[0] = 7;
e->id = 5;
e->nodescount = 0;
d->id = 4;
d->nodescount = 0;
c->id = 3;
c->nodescount = 1;
c->nodesnext[0] = end;
c->nodescost[0] = 3;
b->id = 2;
b->nodescount = 3;
b->nodesnext[0] = e;
b->nodescost[0] = 11;
b->nodesnext[1] = f;
b->nodescost[1] = 42;
b->nodesnext[2] = g;
b->nodescost[2] = 8;
a->id = 1;
a->nodescount = 2;
a->nodesnext[0] = c;
a->nodescost[0] = 15;
a->nodesnext[1] = d;
a->nodescost[1] = 27;
start->id = 0;
start->nodescount = 2;
start->nodesnext[0] = a;
start->nodescost[0] = 72;
start->nodesnext[1] = b;
start->nodescost[1] = 32;
return start;
}

33
README.md

@ -1,3 +1,34 @@
# ParallelTrafficRouter_FreeRTOS
Example of a parallel algorithm in a FreeRTOS simulation
Example of a parallel algorithm in a FreeRTOS simulation
##Build requirements
###openSuse Tumbleweed
zypper install git make gcc-32bit
###Ubuntu 18.04
apt-get install git make gcc gcc-multilib g++-multilib
###Microsoft Windows
[FreeRTOS site for the Windows port](https://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html)
##Build
* git clone https://git.mosad.xyz/localhorst/ParallelTrafficRouter_FreeRTOS.git
* cd ParallelTrafficRouter_FreeRTOS
* make
##Execute
* ./FreeRTOS-Demo
### Using freeRTOS simulator fork from [https://github.com/Muriukidavid/FreeRTOS-Sim](https://github.com/Muriukidavid/FreeRTOS-Sim)

395
Source/croutine.c

@ -0,0 +1,395 @@
/*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
/* Remove the whole file is co-routines are not being used. */
#if( configUSE_CO_ROUTINES != 0 )
/*
* Some kernel aware debuggers require data to be viewed to be global, rather
* than file scope.
*/
#ifdef portREMOVE_STATIC_QUALIFIER
#define static
#endif
/* Lists for ready and blocked co-routines. --------------------*/
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
/* Other file private variables. --------------------------------*/
CRCB_t * pxCurrentCoRoutine = NULL;
static UBaseType_t uxTopCoRoutineReadyPriority = 0;
static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
/* The initial state of the co-routine when it is created. */
#define corINITIAL_STATE ( 0 )
/*
* Place the co-routine represented by pxCRCB into the appropriate ready queue
* for the priority. It is inserted at the end of the list.
*
* This macro accesses the co-routine ready lists and therefore must not be
* used from within an ISR.
*/
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
{ \
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
{ \
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
} \
vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
}
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first co-routine.
*/
static void prvInitialiseCoRoutineLists( void );
/*
* Co-routines that are readied by an interrupt cannot be placed directly into
* the ready lists (there is no mutual exclusion). Instead they are placed in
* in the pending ready list in order that they can later be moved to the ready
* list by the co-routine scheduler.
*/
static void prvCheckPendingReadyList( void );
/*
* Macro that looks at the list of co-routines that are currently delayed to
* see if any require waking.
*
* Co-routines are stored in the queue in the order of their wake time -
* meaning once one co-routine has been found whose timer has not expired
* we need not look any further down the list.
*/
static void prvCheckDelayedList( void );
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex )
{
BaseType_t xReturn;
CRCB_t *pxCoRoutine;
/* Allocate the memory that will store the co-routine control block. */
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
if( pxCoRoutine )
{
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
be created and the co-routine data structures need initialising. */
if( pxCurrentCoRoutine == NULL )
{
pxCurrentCoRoutine = pxCoRoutine;
prvInitialiseCoRoutineLists();
}
/* Check the priority is within limits. */
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
{
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
}
/* Fill out the co-routine control block from the function parameters. */
pxCoRoutine->uxState = corINITIAL_STATE;
pxCoRoutine->uxPriority = uxPriority;
pxCoRoutine->uxIndex = uxIndex;
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
/* Initialise all the other co-routine control block parameters. */
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
/* Set the co-routine control block as a link back from the ListItem_t.
This is so we can get back to the containing CRCB from a generic item
in a list. */
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
/* Now the co-routine has been initialised it can be added to the ready
list at the correct priority. */
prvAddCoRoutineToReadyQueue( pxCoRoutine );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList )
{
TickType_t xTimeToWake;
/* Calculate the time to wake - this may overflow but this is
not a problem. */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists. */
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
if( xTimeToWake < xCoRoutineTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list. */
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
current block list. */
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
if( pxEventList )
{
/* Also add the co-routine to an event list. If this is done then the
function must be called with interrupts disabled. */
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
}
}
/*-----------------------------------------------------------*/
static void prvCheckPendingReadyList( void )
{
/* Are there any co-routines waiting to get moved to the ready list? These
are co-routines that have been readied by an ISR. The ISR cannot access
the ready lists itself. */
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
{
CRCB_t *pxUnblockedCRCB;
/* The pending ready list can be accessed by an ISR. */
portDISABLE_INTERRUPTS();
{
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
}
portENABLE_INTERRUPTS();
( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
}
}
/*-----------------------------------------------------------*/
static void prvCheckDelayedList( void )
{
CRCB_t *pxCRCB;
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
while( xPassedTicks )
{
xCoRoutineTickCount++;
xPassedTicks--;
/* If the tick count has overflowed we need to swap the ready lists. */
if( xCoRoutineTickCount == 0 )
{
List_t * pxTemp;
/* Tick count has overflowed so we need to swap the delay lists. If there are
any items in pxDelayedCoRoutineList here then there is an error! */
pxTemp = pxDelayedCoRoutineList;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
pxOverflowDelayedCoRoutineList = pxTemp;
}
/* See if this tick has made a timeout expire. */
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
{
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
{
/* Timeout not yet expired. */
break;
}
portDISABLE_INTERRUPTS();
{
/* The event could have occurred just before this critical
section. If this is the case then the generic list item will
have been moved to the pending ready list and the following
line is still valid. Also the pvContainer parameter will have
been set to NULL so the following lines are also valid. */
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
/* Is the co-routine waiting on an event also? */
if( pxCRCB->xEventListItem.pvContainer )
{
( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
}
}
portENABLE_INTERRUPTS();
prvAddCoRoutineToReadyQueue( pxCRCB );
}
}
xLastTickCount = xCoRoutineTickCount;
}
/*-----------------------------------------------------------*/
void vCoRoutineSchedule( void )
{
/* See if any co-routines readied by events need moving to the ready lists. */
prvCheckPendingReadyList();
/* See if any delayed co-routines have timed out. */
prvCheckDelayedList();
/* Find the highest priority queue that contains ready co-routines. */
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
{
if( uxTopCoRoutineReadyPriority == 0 )
{
/* No more co-routines to check. */
return;
}
--uxTopCoRoutineReadyPriority;
}
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
of the same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
/* Call the co-routine. */
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
return;
}
/*-----------------------------------------------------------*/
static void prvInitialiseCoRoutineLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
{
vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
}
vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
/* Start with pxDelayedCoRoutineList using list1 and the
pxOverflowDelayedCoRoutineList using list2. */
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
}
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList )
{
CRCB_t *pxUnblockedCRCB;
BaseType_t xReturn;
/* This function is called from within an interrupt. It can only access
event lists and the pending ready list. This function assumes that a
check has already been made to ensure pxEventList is not empty. */
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
#endif /* configUSE_CO_ROUTINES == 0 */

752
Source/event_groups.c

@ -0,0 +1,752 @@
/*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
/* Standard includes. */
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "event_groups.h"
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
header files above, but not in this file, in order to generate the correct
privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
/* The following bit fields convey control information in a task's event list
item value. It is important they don't clash with the
taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
#if configUSE_16_BIT_TICKS == 1
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
#define eventWAIT_FOR_ALL_BITS 0x0400U
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
#else
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
#endif
typedef struct xEventGroupDefinition
{
EventBits_t uxEventBits;
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
#endif
} EventGroup_t;
/*-----------------------------------------------------------*/
/*
* Test the bits set in uxCurrentEventBits to see if the wait condition is met.
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is
* pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
* are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the
* wait condition is met if any of the bits set in uxBitsToWait for are also set
* in uxCurrentEventBits.
*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
{
EventGroup_t *pxEventBits;
/* A StaticEventGroup_t object must be provided. */
configASSERT( pxEventGroupBuffer );
/* The user has provided a statically allocated event group - use it. */
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note that
this event group was created statically in case the event group
is later deleted. */
pxEventBits->ucStaticallyAllocated = pdTRUE;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return ( EventGroupHandle_t ) pxEventBits;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t *pxEventBits;
/* Allocate the event group. */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note this
event group was allocated statically in case the event group is
later deleted. */
pxEventBits->ucStaticallyAllocated = pdFALSE;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return ( EventGroupHandle_t ) pxEventBits;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
{
EventBits_t uxOriginalBitValue, uxReturn;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
uxOriginalBitValue = pxEventBits->uxEventBits;
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
/* All the rendezvous bits are now set - no need to block. */
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
/* Rendezvous always clear the bits. They will have been cleared
already unless this is the only task in the rendezvous. */
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
xTicksToWait = 0;
}
else
{
if( xTicksToWait != ( TickType_t ) 0 )
{
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
/* Store the bits that the calling task is waiting for in the
task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
/* This assignment is obsolete as uxReturn will get set after
the task unblocks, but some compilers mistakenly generate a
warning about uxReturn being returned without being set if the
assignment is omitted. */
uxReturn = 0;
}
else
{
/* The rendezvous bits were not set, but no block time was
specified - just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
}
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
point either the required bits were set or the block time expired. If
the required bits were set they will have been stored in the task's
event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
/* The task timed out, just return the current event bit value. */
taskENTER_CRITICAL();
{
uxReturn = pxEventBits->uxEventBits;
/* Although the task got here because it timed out before the
bits it was waiting for were set, it is possible that since it
unblocked another task has set the bits. If this is the case
then it needs to clear the bits before exiting. */
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
xTimeoutOccurred = pdTRUE;
}
else
{
/* The task unblocked because the bits were set. */
}
/* Control bits might be set as the task had blocked should not be
returned. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
return uxReturn;
}
/*-----------------------------------------------------------*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
/* Check the user is not attempting to wait on the bits used by the kernel
itself, and that at least one bit is being requested. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
/* Check to see if the wait condition is already met or not. */
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
if( xWaitConditionMet != pdFALSE )
{
/* The wait condition has already been met so there is no need to
block. */
uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0;
/* Clear the wait bits if requested to do so. */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xTicksToWait == ( TickType_t ) 0 )
{
/* The wait condition has not been met, but no block time was
specified, so just return the current value. */
uxReturn = uxCurrentEventBits;
}
else
{
/* The task is going to block to wait for its required bits to be
set. uxControlBits are used to remember the specified behaviour of
this call to xEventGroupWaitBits() - for use when the event bits
unblock the task. */
if( xClearOnExit != pdFALSE )
{
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xWaitForAllBits != pdFALSE )
{
uxControlBits |= eventWAIT_FOR_ALL_BITS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Store the bits that the calling task is waiting for in the
task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
/* This is obsolete as it will get set after the task unblocks, but
some compilers mistakenly generate a warning about the variable
being returned without being set if it is not done. */
uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
point either the required bits were set or the block time expired. If
the required bits were set they will have been stored in the task's
event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
taskENTER_CRITICAL();
{
/* The task timed out, just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
/* It is possible that the event bits were updated between this
task leaving the Blocked state and running again. */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();