Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,156 @@
#
# !!!! Do NOT edit this makefile with an editor which replace tabs by spaces !!!!
#
##############################################################################################
#
# On command line:
#
# make all = Create project
#
# make clean = Clean project files.
#
# To rebuild project do "make clean" and "make all".
#
##############################################################################################
# Start of default section
#
TRGT = mingw32-
CC = $(TRGT)gcc
AS = $(TRGT)gcc -x assembler-with-cpp
COV = gcov
# List all default C defines here, like -D_DEBUG=1
DDEFS = -DSIMULATOR
# List all default ASM defines here, like -D_DEBUG=1
DADEFS =
# List all default directories to look for include files here
DINCDIR =
# List the default directory to look for the libraries here
DLIBDIR =
# List all default libraries here
DLIBS = -lws2_32
# Must be a directory in ${CHIBIOS}/os/hal/platforms
HOST_TYPE = Win32
#
# End of default section
##############################################################################################
##############################################################################################
# Start of user section
#
# Define project name here
PROJECT = ch
# Define linker script file here
LDSCRIPT=
# List all user C define here, like -D_DEBUG=1
UDEFS =
# Define ASM defines here
UADEFS =
# Imported source files
CHIBIOS = ../..
include $(CHIBIOS)/boards/simulator/board.mk
include ${CHIBIOS}/os/hal/hal.mk
include ${CHIBIOS}/os/hal/platforms/$(HOST_TYPE)/platform.mk
include ${CHIBIOS}/os/ports/GCC/SIMIA32/port.mk
include ${CHIBIOS}/os/kernel/kernel.mk
include ${CHIBIOS}/test/test.mk
# List C source files here
SRC = ${PORTSRC} \
${KERNSRC} \
${TESTSRC} \
${HALSRC} \
${PLATFORMSRC} \
$(BOARDSRC) \
${CHIBIOS}/os/hal/platforms/$(HOST_TYPE)/console.c \
main.c
# List ASM source files here
ASRC =
# List all user directories here
UINCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
$(HALINC) $(PLATFORMINC) $(BOARDINC) \
$(CHIBIOS)/os/various
# List the user directory to look for the libraries here
ULIBDIR =
# List all user libraries here
ULIBS =
# Define optimisation level here
OPT = -ggdb -O0 -fomit-frame-pointer -fprofile-arcs -ftest-coverage
#
# End of user defines
##############################################################################################
INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR))
LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR))
DEFS = $(DDEFS) $(UDEFS)
ADEFS = $(DADEFS) $(UADEFS)
OBJS = $(ASRC:.s=.o) $(SRC:.c=.o)
LIBS = $(DLIBS) $(ULIBS)
LDFLAGS = -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch -lgcov $(LIBDIR)
ASFLAGS = -Wa,-amhls=$(<:.s=.lst) $(ADEFS)
CPFLAGS = $(OPT) -Wall -Wextra -Wstrict-prototypes -fverbose-asm -Wa,-alms=$(<:.c=.lst) $(DEFS)
# Generate dependency information
CPFLAGS += -MD -MP -MF .dep/$(@F).d
#
# makefile rules
#
all: $(OBJS) $(PROJECT).exe
%o : %c
$(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@
%o : %s
$(AS) -c $(ASFLAGS) $< -o $@
%exe: $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@
.PHONY: gcov
gcov:
-mkdir gcov
$(COV) -u $(subst /,\,$(KERNSRC))
-mv -f *.gcov ./gcov
.PHONY: clean
clean:
-rm -f $(OBJS)
-rm -f $(PROJECT).exe
-rm -f $(PROJECT).map
-rm -f $(SRC:.c=.c.bak)
-rm -f $(SRC:.c=.lst)
-rm -f $(SRC:.c=.gcno)
-rm -f $(SRC:.c=.gcda)
-rm -f $(ASRC:.s=.s.bak)
-rm -f $(ASRC:.s=.lst)
-rm -fR .dep
#
# Include the dependency files, should be the last of the makefile
#
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# *** EOF ***

View File

@ -0,0 +1,532 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file templates/chconf.h
* @brief Configuration file template.
* @details A copy of this file must be placed in each project directory, it
* contains the application specific kernel settings.
*
* @addtogroup config
* @details Kernel related settings and hooks.
* @{
*/
#ifndef _CHCONF_H_
#define _CHCONF_H_
/*===========================================================================*/
/**
* @name Kernel parameters and options
* @{
*/
/*===========================================================================*/
/**
* @brief System tick frequency.
* @details Frequency of the system timer that drives the system ticks. This
* setting also defines the system tick time unit.
*/
#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
#define CH_FREQUENCY 1000
#endif
/**
* @brief Round robin interval.
* @details This constant is the number of system ticks allowed for the
* threads before preemption occurs. Setting this value to zero
* disables the preemption for threads with equal priority and the
* round robin becomes cooperative. Note that higher priority
* threads can still preempt, the kernel is always preemptive.
*
* @note Disabling the round robin preemption makes the kernel more compact
* and generally faster.
*/
#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
#define CH_TIME_QUANTUM 20
#endif
/**
* @brief Managed RAM size.
* @details Size of the RAM area to be managed by the OS. If set to zero
* then the whole available RAM is used. The core memory is made
* available to the heap allocator and/or can be used directly through
* the simplified core memory allocator.
*
* @note In order to let the OS manage the whole RAM the linker script must
* provide the @p __heap_base__ and @p __heap_end__ symbols.
* @note Requires @p CH_USE_MEMCORE.
*/
#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
#define CH_MEMCORE_SIZE 0x20000
#endif
/**
* @brief Idle thread automatic spawn suppression.
* @details When this option is activated the function @p chSysInit()
* does not spawn the idle thread automatically. The application has
* then the responsibility to do one of the following:
* - Spawn a custom idle thread at priority @p IDLEPRIO.
* - Change the main() thread priority to @p IDLEPRIO then enter
* an endless loop. In this scenario the @p main() thread acts as
* the idle thread.
* .
* @note Unless an idle thread is spawned the @p main() thread must not
* enter a sleep state.
*/
#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
#define CH_NO_IDLE_THREAD FALSE
#endif
/** @} */
/*===========================================================================*/
/**
* @name Performance options
* @{
*/
/*===========================================================================*/
/**
* @brief OS optimization.
* @details If enabled then time efficient rather than space efficient code
* is used when two possible implementations exist.
*
* @note This is not related to the compiler optimization options.
* @note The default is @p TRUE.
*/
#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
#define CH_OPTIMIZE_SPEED FALSE
#endif
/** @} */
/*===========================================================================*/
/**
* @name Subsystem options
* @{
*/
/*===========================================================================*/
/**
* @brief Threads registry APIs.
* @details If enabled then the registry APIs are included in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
#define CH_USE_REGISTRY TRUE
#endif
/**
* @brief Threads synchronization APIs.
* @details If enabled then the @p chThdWait() function is included in
* the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
#define CH_USE_WAITEXIT TRUE
#endif
/**
* @brief Semaphores APIs.
* @details If enabled then the Semaphores APIs are included in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
#define CH_USE_SEMAPHORES TRUE
#endif
/**
* @brief Semaphores queuing mode.
* @details If enabled then the threads are enqueued on semaphores by
* priority rather than in FIFO order.
*
* @note The default is @p FALSE. Enable this if you have special requirements.
* @note Requires @p CH_USE_SEMAPHORES.
*/
#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
#define CH_USE_SEMAPHORES_PRIORITY FALSE
#endif
/**
* @brief Atomic semaphore API.
* @details If enabled then the semaphores the @p chSemSignalWait() API
* is included in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_SEMAPHORES.
*/
#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
#define CH_USE_SEMSW TRUE
#endif
/**
* @brief Mutexes APIs.
* @details If enabled then the mutexes APIs are included in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
#define CH_USE_MUTEXES TRUE
#endif
/**
* @brief Conditional Variables APIs.
* @details If enabled then the conditional variables APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_MUTEXES.
*/
#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
#define CH_USE_CONDVARS TRUE
#endif
/**
* @brief Conditional Variables APIs with timeout.
* @details If enabled then the conditional variables APIs with timeout
* specification are included in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_CONDVARS.
*/
#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
#define CH_USE_CONDVARS_TIMEOUT TRUE
#endif
/**
* @brief Events Flags APIs.
* @details If enabled then the event flags APIs are included in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
#define CH_USE_EVENTS TRUE
#endif
/**
* @brief Events Flags APIs with timeout.
* @details If enabled then the events APIs with timeout specification
* are included in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_EVENTS.
*/
#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
#define CH_USE_EVENTS_TIMEOUT TRUE
#endif
/**
* @brief Synchronous Messages APIs.
* @details If enabled then the synchronous messages APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
#define CH_USE_MESSAGES TRUE
#endif
/**
* @brief Synchronous Messages queuing mode.
* @details If enabled then messages are served by priority rather than in
* FIFO order.
*
* @note The default is @p FALSE. Enable this if you have special requirements.
* @note Requires @p CH_USE_MESSAGES.
*/
#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
#define CH_USE_MESSAGES_PRIORITY FALSE
#endif
/**
* @brief Mailboxes APIs.
* @details If enabled then the asynchronous messages (mailboxes) APIs are
* included in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_SEMAPHORES.
*/
#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
#define CH_USE_MAILBOXES TRUE
#endif
/**
* @brief I/O Queues APIs.
* @details If enabled then the I/O queues APIs are included in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
#define CH_USE_QUEUES TRUE
#endif
/**
* @brief Core Memory Manager APIs.
* @details If enabled then the core memory manager APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__)
#define CH_USE_MEMCORE TRUE
#endif
/**
* @brief Heap Allocator APIs.
* @details If enabled then the memory heap allocator APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
* @p CH_USE_SEMAPHORES.
* @note Mutexes are recommended.
*/
#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
#define CH_USE_HEAP TRUE
#endif
/**
* @brief C-runtime allocator.
* @details If enabled the the heap allocator APIs just wrap the C-runtime
* @p malloc() and @p free() functions.
*
* @note The default is @p FALSE.
* @note Requires @p CH_USE_HEAP.
* @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the
* appropriate documentation.
*/
#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
#define CH_USE_MALLOC_HEAP FALSE
#endif
/**
* @brief Memory Pools Allocator APIs.
* @details If enabled then the memory pools allocator APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
*/
#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
#define CH_USE_MEMPOOLS TRUE
#endif
/**
* @brief Dynamic Threads APIs.
* @details If enabled then the dynamic threads creation APIs are included
* in the kernel.
*
* @note The default is @p TRUE.
* @note Requires @p CH_USE_WAITEXIT.
* @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
*/
#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
#define CH_USE_DYNAMIC TRUE
#endif
/** @} */
/*===========================================================================*/
/**
* @name Debug options
* @{
*/
/*===========================================================================*/
/**
* @brief Debug option, system state check.
* @details If enabled the correct call protocol for system APIs is checked
* at runtime.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
#define CH_DBG_SYSTEM_STATE_CHECK FALSE
#endif
/**
* @brief Debug option, parameters checks.
* @details If enabled then the checks on the API functions input
* parameters are activated.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_CHECKS FALSE
#endif
/**
* @brief Debug option, consistency checks.
* @details If enabled then all the assertions in the kernel code are
* activated. This includes consistency checks inside the kernel,
* runtime anomalies and port-defined checks.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_ASSERTS FALSE
#endif
/**
* @brief Debug option, trace buffer.
* @details If enabled then the context switch circular trace buffer is
* activated.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_TRACE TRUE
#endif
/**
* @brief Debug option, stack checks.
* @details If enabled then a runtime stack check is performed.
*
* @note The default is @p FALSE.
* @note The stack check is performed in a architecture/port dependent way.
* It may not be implemented or some ports.
* @note The default failure mode is to halt the system with the global
* @p panic_msg variable set to @p NULL.
*/
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
#define CH_DBG_ENABLE_STACK_CHECK FALSE
#endif
/**
* @brief Debug option, stacks initialization.
* @details If enabled then the threads working area is filled with a byte
* value when a thread is created. This can be useful for the
* runtime measurement of the used stack.
*
* @note The default is @p FALSE.
*/
#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
#define CH_DBG_FILL_THREADS TRUE
#endif
/**
* @brief Debug option, threads profiling.
* @details If enabled then a field is added to the @p Thread structure that
* counts the system ticks occurred while executing the thread.
*
* @note The default is @p TRUE.
* @note This debug option is defaulted to TRUE because it is required by
* some test cases into the test suite.
*/
#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
#define CH_DBG_THREADS_PROFILING TRUE
#endif
/** @} */
/*===========================================================================*/
/**
* @name Kernel hooks
* @{
*/
/*===========================================================================*/
/**
* @brief Threads descriptor structure extension.
* @details User fields added to the end of the @p Thread structure.
*/
#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
#define THREAD_EXT_FIELDS \
/* Add threads custom fields here.*/
#endif
/**
* @brief Threads initialization hook.
* @details User initialization code added to the @p chThdInit() API.
*
* @note It is invoked from within @p chThdInit() and implicitly from all
* the threads creation APIs.
*/
#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
#define THREAD_EXT_INIT_HOOK(tp) { \
/* Add threads initialization code here.*/ \
}
#endif
/**
* @brief Threads finalization hook.
* @details User finalization code added to the @p chThdExit() API.
*
* @note It is inserted into lock zone.
* @note It is also invoked when the threads simply return in order to
* terminate.
*/
#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
#define THREAD_EXT_EXIT_HOOK(tp) { \
/* Add threads finalization code here.*/ \
}
#endif
/**
* @brief Context switch hook.
* @details This hook is invoked just before switching between threads.
*/
#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \
/* Context switch code here.*/ \
}
#endif
/**
* @brief Idle Loop hook.
* @details This hook is continuously invoked by the idle thread loop.
*/
#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
#define IDLE_LOOP_HOOK() { \
/* Idle loop code here.*/ \
}
#endif
/**
* @brief System tick event hook.
* @details This hook is invoked in the system tick handler immediately
* after processing the virtual timers queue.
*/
#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
#define SYSTEM_TICK_EVENT_HOOK() { \
/* System tick event code here.*/ \
}
#endif
/**
* @brief System halt hook.
* @details This hook is invoked in case to a system halting error before
* the system is halted.
*/
#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
#define SYSTEM_HALT_HOOK() { \
/* System halt code here.*/ \
}
#endif
/** @} */
/*===========================================================================*/
/* Port-specific settings (override port settings defaulted in chcore.h). */
/*===========================================================================*/
#endif /* _CHCONF_H_ */
/** @} */

View File

@ -0,0 +1,312 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file templates/halconf.h
* @brief HAL configuration header.
* @details HAL configuration file, this file allows to enable or disable the
* various device drivers from your application. You may also use
* this file in order to override the device drivers default settings.
*
* @addtogroup HAL_CONF
* @{
*/
#ifndef _HALCONF_H_
#define _HALCONF_H_
/*#include "mcuconf.h"*/
/**
* @brief Enables the TM subsystem.
*/
#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
#define HAL_USE_TM FALSE
#endif
/**
* @brief Enables the PAL subsystem.
*/
#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
#define HAL_USE_PAL FALSE
#endif
/**
* @brief Enables the ADC subsystem.
*/
#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
#define HAL_USE_ADC FALSE
#endif
/**
* @brief Enables the CAN subsystem.
*/
#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
#define HAL_USE_CAN FALSE
#endif
/**
* @brief Enables the EXT subsystem.
*/
#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
#define HAL_USE_EXT FALSE
#endif
/**
* @brief Enables the GPT subsystem.
*/
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
#define HAL_USE_GPT FALSE
#endif
/**
* @brief Enables the I2C subsystem.
*/
#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
#define HAL_USE_I2C FALSE
#endif
/**
* @brief Enables the ICU subsystem.
*/
#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
#define HAL_USE_ICU FALSE
#endif
/**
* @brief Enables the MAC subsystem.
*/
#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
#define HAL_USE_MAC FALSE
#endif
/**
* @brief Enables the MMC_SPI subsystem.
*/
#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
#define HAL_USE_MMC_SPI FALSE
#endif
/**
* @brief Enables the PWM subsystem.
*/
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
#define HAL_USE_PWM FALSE
#endif
/**
* @brief Enables the RTC subsystem.
*/
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
#define HAL_USE_RTC FALSE
#endif
/**
* @brief Enables the SDC subsystem.
*/
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
#define HAL_USE_SDC FALSE
#endif
/**
* @brief Enables the SERIAL subsystem.
*/
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL FALSE
#endif
/**
* @brief Enables the SERIAL over USB subsystem.
*/
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL_USB FALSE
#endif
/**
* @brief Enables the SPI subsystem.
*/
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
#define HAL_USE_SPI FALSE
#endif
/**
* @brief Enables the UART subsystem.
*/
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
#define HAL_USE_UART FALSE
#endif
/**
* @brief Enables the USB subsystem.
*/
#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
#define HAL_USE_USB FALSE
#endif
/*===========================================================================*/
/* ADC driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
#define ADC_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define ADC_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* CAN driver related settings. */
/*===========================================================================*/
/**
* @brief Sleep mode related APIs inclusion switch.
*/
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
#define CAN_USE_SLEEP_MODE TRUE
#endif
/*===========================================================================*/
/* I2C driver related settings. */
/*===========================================================================*/
/**
* @brief Enables the mutual exclusion APIs on the I2C bus.
*/
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define I2C_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* MAC driver related settings. */
/*===========================================================================*/
/**
* @brief Enables an event sources for incoming packets.
*/
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
#define MAC_USE_ZERO_COPY FALSE
#endif
/**
* @brief Enables an event sources for incoming packets.
*/
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
#define MAC_USE_EVENTS TRUE
#endif
/*===========================================================================*/
/* MMC_SPI driver related settings. */
/*===========================================================================*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING TRUE
#endif
/*===========================================================================*/
/* SDC driver related settings. */
/*===========================================================================*/
/**
* @brief Number of initialization attempts before rejecting the card.
* @note Attempts are performed at 10mS intervals.
*/
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
#define SDC_INIT_RETRY 100
#endif
/**
* @brief Include support for MMC cards.
* @note MMC support is not yet implemented so this option must be kept
* at @p FALSE.
*/
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
#define SDC_MMC_SUPPORT FALSE
#endif
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
*/
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
#define SDC_NICE_WAITING TRUE
#endif
/*===========================================================================*/
/* SERIAL driver related settings. */
/*===========================================================================*/
/**
* @brief Default bit rate.
* @details Configuration parameter, this is the baud rate selected for the
* default configuration.
*/
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
#define SERIAL_DEFAULT_BITRATE 38400
#endif
/**
* @brief Serial buffers size.
* @details Configuration parameter, you can change the depth of the queue
* buffers depending on the requirements of your application.
* @note The default is 64 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_BUFFERS_SIZE 16
#endif
/*===========================================================================*/
/* SPI driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION TRUE
#endif
#endif /* _HALCONF_H_ */
/** @} */

View File

@ -0,0 +1,51 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ch.h"
#include "hal.h"
#include "test.h"
#include "console.h"
/*
* Simulator main.
*/
int main(int argc, char *argv[]) {
msg_t result;
(void)argc;
(void)argv;
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
conInit();
chSysInit();
result = TestThread(&CD1);
if (result)
exit(1);
else
exit(0);
}

View File

@ -0,0 +1,6 @@
In order to compute the code coverage:
- Build the test application: make
- Run the test suite: ch
- Compute the code coverage: make gcov
- Clear everything: make clean

View File

@ -0,0 +1,390 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file test.c
* @brief Tests support code.
*
* @addtogroup test
* @{
*/
#include "ch.h"
#include "hal.h"
#include "test.h"
#include "testthd.h"
#include "testsem.h"
#include "testmtx.h"
#include "testmsg.h"
#include "testmbox.h"
#include "testevt.h"
#include "testheap.h"
#include "testpools.h"
#include "testdyn.h"
#include "testqueues.h"
#include "testbmk.h"
/*
* Array of all the test patterns.
*/
static ROMCONST struct testcase * ROMCONST *patterns[] = {
patternthd,
patternsem,
patternmtx,
patternmsg,
patternmbox,
patternevt,
patternheap,
patternpools,
patterndyn,
patternqueues,
patternbmk,
NULL
};
static bool_t local_fail, global_fail;
static unsigned failpoint;
static char tokens_buffer[MAX_TOKENS];
static char *tokp;
/*
* Static working areas, the following areas can be used for threads or
* used as temporary buffers.
*/
union test_buffers test;
/*
* Pointers to the spawned threads.
*/
Thread *threads[MAX_THREADS];
/*
* Pointers to the working areas.
*/
void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2,
test.wa.T3, test.wa.T4};
/*
* Console output.
*/
static BaseSequentialStream *chp;
/**
* @brief Prints a decimal unsigned number.
*
* @param[in] n the number to be printed
*/
void test_printn(uint32_t n) {
char buf[16], *p;
if (!n)
chSequentialStreamPut(chp, '0');
else {
p = buf;
while (n)
*p++ = (n % 10) + '0', n /= 10;
while (p > buf)
chSequentialStreamPut(chp, *--p);
}
}
/**
* @brief Prints a line without final end-of-line.
*
* @param[in] msgp the message
*/
void test_print(const char *msgp) {
while (*msgp)
chSequentialStreamPut(chp, *msgp++);
}
/**
* @brief Prints a line.
*
* @param[in] msgp the message
*/
void test_println(const char *msgp) {
test_print(msgp);
chSequentialStreamWrite(chp, (const uint8_t *)"\r\n", 2);
}
/*
* Tokens.
*/
static void clear_tokens(void) {
tokp = tokens_buffer;
}
static void print_tokens(void) {
char *cp = tokens_buffer;
while (cp < tokp)
chSequentialStreamPut(chp, *cp++);
}
/**
* @brief Emits a token into the tokens buffer.
*
* @param[in] token the token as a char
*/
void test_emit_token(char token) {
chSysLock();
*tokp++ = token;
chSysUnlock();
}
/*
* Assertions.
*/
bool_t _test_fail(unsigned point) {
local_fail = TRUE;
global_fail = TRUE;
failpoint = point;
return TRUE;
}
bool_t _test_assert(unsigned point, bool_t condition) {
if (!condition)
return _test_fail(point);
return FALSE;
}
bool_t _test_assert_sequence(unsigned point, char *expected) {
char *cp = tokens_buffer;
while (cp < tokp) {
if (*cp++ != *expected++)
return _test_fail(point);
}
if (*expected)
return _test_fail(point);
clear_tokens();
return FALSE;
}
bool_t _test_assert_time_window(unsigned point, systime_t start, systime_t end) {
return _test_assert(point, chTimeIsWithin(start, end));
}
/*
* Threads utils.
*/
/**
* @brief Sets a termination request in all the test-spawned threads.
*/
void test_terminate_threads(void) {
int i;
for (i = 0; i < MAX_THREADS; i++)
if (threads[i])
chThdTerminate(threads[i]);
}
/**
* @brief Waits for the completion of all the test-spawned threads.
*/
void test_wait_threads(void) {
int i;
for (i = 0; i < MAX_THREADS; i++)
if (threads[i] != NULL) {
chThdWait(threads[i]);
threads[i] = NULL;
}
}
#if CH_DBG_THREADS_PROFILING
/**
* @brief CPU pulse.
* @note The current implementation is not totally reliable.
*
* @param[in] duration CPU pulse duration in milliseconds
*/
void test_cpu_pulse(unsigned duration) {
systime_t start, end, now;
start = chThdSelf()->p_time;
end = start + MS2ST(duration);
do {
now = chThdSelf()->p_time;
#if defined(SIMULATOR)
ChkIntSources();
#endif
}
while (end > start ? (now >= start) && (now < end) :
(now >= start) || (now < end));
}
#endif
/**
* @brief Delays execution until next system time tick.
*
* @return The system time.
*/
systime_t test_wait_tick(void) {
chThdSleep(1);
return chTimeNow();
}
/*
* Timer utils.
*/
/**
* @brief Set to @p TRUE when the test timer reaches its deadline.
*/
bool_t test_timer_done;
static VirtualTimer vt;
static void tmr(void *p) {
(void)p;
test_timer_done = TRUE;
}
/**
* @brief Starts the test timer.
*
* @param[in] ms time in milliseconds
*/
void test_start_timer(unsigned ms) {
systime_t duration = MS2ST(ms);
test_timer_done = FALSE;
chVTSet(&vt, duration, tmr, NULL);
}
/*
* Test suite execution.
*/
static void execute_test(const struct testcase *tcp) {
int i;
/* Initialization */
clear_tokens();
local_fail = FALSE;
for (i = 0; i < MAX_THREADS; i++)
threads[i] = NULL;
if (tcp->setup != NULL)
tcp->setup();
tcp->execute();
if (tcp->teardown != NULL)
tcp->teardown();
test_wait_threads();
}
static void print_line(void) {
unsigned i;
for (i = 0; i < 76; i++)
chSequentialStreamPut(chp, '-');
chSequentialStreamWrite(chp, (const uint8_t *)"\r\n", 2);
}
/**
* @brief Test execution thread function.
*
* @param[in] p pointer to a @p BaseChannel object for test output
* @return A failure boolean value.
*/
msg_t TestThread(void *p) {
int i, j;
chp = p;
test_println("");
test_println("*** ChibiOS/RT test suite");
test_println("***");
test_print("*** Kernel: ");
test_println(CH_KERNEL_VERSION);
test_print("*** Compiled: ");
test_println(__DATE__ " - " __TIME__);
#ifdef CH_COMPILER_NAME
test_print("*** Compiler: ");
test_println(CH_COMPILER_NAME);
#endif
test_print("*** Architecture: ");
test_println(CH_ARCHITECTURE_NAME);
#ifdef CH_CORE_VARIANT_NAME
test_print("*** Core Variant: ");
test_println(CH_CORE_VARIANT_NAME);
#endif
#ifdef CH_PORT_INFO
test_print("*** Port Info: ");
test_println(CH_PORT_INFO);
#endif
#ifdef PLATFORM_NAME
test_print("*** Platform: ");
test_println(PLATFORM_NAME);
#endif
#ifdef BOARD_NAME
test_print("*** Test Board: ");
test_println(BOARD_NAME);
#endif
test_println("");
global_fail = FALSE;
i = 0;
while (patterns[i]) {
j = 0;
while (patterns[i][j]) {
print_line();
test_print("--- Test Case ");
test_printn(i + 1);
test_print(".");
test_printn(j + 1);
test_print(" (");
test_print(patterns[i][j]->name);
test_println(")");
#if DELAY_BETWEEN_TESTS > 0
chThdSleepMilliseconds(DELAY_BETWEEN_TESTS);
#endif
execute_test(patterns[i][j]);
if (local_fail) {
test_print("--- Result: FAILURE (#");
test_printn(failpoint);
test_print(" [");
print_tokens();
test_println("])");
}
else
test_println("--- Result: SUCCESS");
j++;
}
i++;
}
print_line();
test_println("");
test_print("Final result: ");
if (global_fail)
test_println("FAILURE");
else
test_println("SUCCESS");
return (msg_t)global_fail;
}
/** @} */

View File

@ -0,0 +1,20 @@
# List of all the ChibiOS/RT test files.
set(TESTSRC
${CHIBIOS}/test/test.c
${CHIBIOS}/test/testthd.c
${CHIBIOS}/test/testsem.c
${CHIBIOS}/test/testmtx.c
${CHIBIOS}/test/testmsg.c
${CHIBIOS}/test/testmbox.c
${CHIBIOS}/test/testevt.c
${CHIBIOS}/test/testheap.c
${CHIBIOS}/test/testpools.c
${CHIBIOS}/test/testdyn.c
${CHIBIOS}/test/testqueues.c
${CHIBIOS}/test/testbmk.c
)
# Required include directories
set(TESTINC
${CHIBIOS}/test
)

View File

@ -0,0 +1,82 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @defgroup test Test Runtime
* @details Runtime code for the test suite execution, this code is not part
* of the OS and should not be included in user applications.
*/
/**
* @page testsuite Testing Strategy
* <h2>Description</h2>
* Most of the ChibiOS/RT demos link a set of software modules (test suite) in
* order to verify the proper working of the kernel, the port and the demo
* itself.
*
* <h2>Strategy by Component</h2>
* The OS components are tested in various modes depending on their importance:
* - <b>Kernel</b>. The kernel code is subject to rigorous testing. The test
* suite aims to test <b>all</b> the kernel code and reach a code coverage
* as close to 100% as possible. In addition to the code coverage, the kernel
* code is tested for <b>functionality</b> and benchmarked for <b>speed</b>
* and <b>size</b> before each stable release. In addition to the code
* coverage and functional testing a <b>batch compilation test</b> is
* performed before each release, the kernel is compiled by alternatively
* enabling and disabling all the various configuration options, the
* kernel code is expected to compile without errors nor warnings and
* execute the test suite without failures (a specific simulator is used
* for this execution test, it is done automatically by a script because
* the entire sequence can take hours).<br>
* All the tests results are included as reports in the OS distribution
* under <tt>./docs/reports</tt>.
* - <b>Ports</b>. The port code is tested by executing the kernel test
* suite on the target hardware. A port is validated only if it passes all
* the tests. Speed and size benchmarks for all the supported architectures
* are performed, both size and speed regressions are <b>monitored</b>.
* - <b>HAL</b>. The HAL high level code and device drivers implementations
* are tested through specific test applications under <tt>./testhal</tt>.
* - <b>Various</b>. The miscellaneous code is tested by use in the various
* demos.
* - <b>External Code</b>. Not tested, external libraries or components are
* used as-is or with minor patching where required, problems are usually
* reported upstream.
* .
* <h2>Kernel Test Suite</h2>
* The kernel test suite is divided in modules or test sequences. Each Test
* Module performs a series of tests on a specified kernel subsystem or
* subsystems and can report a failure/success status and/or a performance
* index as the test suite output.<br>
* The test suite is usually activated in the demo applications by pressing a
* button on the target board, see the readme file into the various demos
* directories. The test suite output is usually sent through a serial port
* and can be examined by using a terminal emulator program.
*
* <h2>Kernel Test Modules</h2>
*
* - @subpage test_threads
* - @subpage test_dynamic
* - @subpage test_msg
* - @subpage test_sem
* - @subpage test_mtx
* - @subpage test_events
* - @subpage test_mbox
* - @subpage test_queues
* - @subpage test_heap
* - @subpage test_pools
* - @subpage test_benchmarks
* .
*/

View File

@ -0,0 +1,173 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file test.h
* @brief Tests support header.
*
* @addtogroup test
* @{
*/
#ifndef _TEST_H_
#define _TEST_H_
/**
* @brief Delay inserted between test cases.
*/
#if !defined(DELAY_BETWEEN_TESTS) || defined(__DOXYGEN__)
#define DELAY_BETWEEN_TESTS 200
#endif
/**
* @brief If @p TRUE then benchmarks are not included.
*/
#if !defined(TEST_NO_BENCHMARKS) || defined(__DOXYGEN__)
#define TEST_NO_BENCHMARKS FALSE
#endif
#define MAX_THREADS 5
#define MAX_TOKENS 16
#if defined(CH_ARCHITECTURE_AVR) || defined(CH_ARCHITECTURE_MSP430)
#define THREADS_STACK_SIZE 48
#elif defined(CH_ARCHITECTURE_STM8)
#define THREADS_STACK_SIZE 64
#elif defined(CH_ARCHITECTURE_SIMIA32)
#define THREADS_STACK_SIZE 512
#else
#define THREADS_STACK_SIZE 128
#endif
#define WA_SIZE THD_WA_SIZE(THREADS_STACK_SIZE)
/**
* @brief Structure representing a test case.
*/
struct testcase {
const char *name; /**< @brief Test case name. */
void (*setup)(void); /**< @brief Test case preparation function. */
void (*teardown)(void); /**< @brief Test case clean up function. */
void (*execute)(void); /**< @brief Test case execution function. */
};
#ifndef __DOXYGEN__
union test_buffers {
struct {
WORKING_AREA(T0, THREADS_STACK_SIZE);
WORKING_AREA(T1, THREADS_STACK_SIZE);
WORKING_AREA(T2, THREADS_STACK_SIZE);
WORKING_AREA(T3, THREADS_STACK_SIZE);
WORKING_AREA(T4, THREADS_STACK_SIZE);
} wa;
uint8_t buffer[WA_SIZE * 5];
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
msg_t TestThread(void *p);
void test_printn(uint32_t n);
void test_print(const char *msgp);
void test_println(const char *msgp);
void test_emit_token(char token);
bool_t _test_fail(unsigned point);
bool_t _test_assert(unsigned point, bool_t condition);
bool_t _test_assert_sequence(unsigned point, char *expected);
bool_t _test_assert_time_window(unsigned point, systime_t start, systime_t end);
void test_terminate_threads(void);
void test_wait_threads(void);
systime_t test_wait_tick(void);
void test_start_timer(unsigned ms);
#if CH_DBG_THREADS_PROFILING
void test_cpu_pulse(unsigned duration);
#endif
#if defined(WIN32)
void ChkIntSources(void);
#endif
#ifdef __cplusplus
}
#endif
/**
* @brief Test failure enforcement.
*/
#define test_fail(point) { \
_test_fail(point); \
return; \
}
/**
* @brief Test assertion.
*
* @param[in] point numeric assertion identifier
* @param[in] condition a boolean expression that must be verified to be true
* @param[in] msg failure message
*/
#define test_assert(point, condition, msg) { \
if (_test_assert(point, condition)) \
return; \
}
/**
* @brief Test assertion with lock.
*
* @param[in] point numeric assertion identifier
* @param[in] condition a boolean expression that must be verified to be true
* @param[in] msg failure message
*/
#define test_assert_lock(point, condition, msg) { \
chSysLock(); \
if (_test_assert(point, condition)) { \
chSysUnlock(); \
return; \
} \
chSysUnlock(); \
}
/**
* @brief Test sequence assertion.
*
* @param[in] point numeric assertion identifier
* @param[in] expected string to be matched with the tokens buffer
*/
#define test_assert_sequence(point, expected) { \
if (_test_assert_sequence(point, expected)) \
return; \
}
/**
* @brief Test time window assertion.
*
* @param[in] point numeric assertion identifier
* @param[in] start initial time in the window (included)
* @param[in] end final time in the window (not included)
*/
#define test_assert_time_window(point, start, end) { \
if (_test_assert_time_window(point, start, end)) \
return; \
}
#if !defined(__DOXYGEN__)
extern Thread *threads[MAX_THREADS];
extern union test_buffers test;
extern void * ROMCONST wa[];
extern bool_t test_timer_done;
#endif
#endif /* _TEST_H_ */
/** @} */

View File

@ -0,0 +1,16 @@
# List of all the ChibiOS/RT test files.
TESTSRC = ${CHIBIOS}/test/test.c \
${CHIBIOS}/test/testthd.c \
${CHIBIOS}/test/testsem.c \
${CHIBIOS}/test/testmtx.c \
${CHIBIOS}/test/testmsg.c \
${CHIBIOS}/test/testmbox.c \
${CHIBIOS}/test/testevt.c \
${CHIBIOS}/test/testheap.c \
${CHIBIOS}/test/testpools.c \
${CHIBIOS}/test/testdyn.c \
${CHIBIOS}/test/testqueues.c \
${CHIBIOS}/test/testbmk.c
# Required include directories
TESTINC = ${CHIBIOS}/test

View File

@ -0,0 +1,720 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_benchmarks Kernel Benchmarks
*
* File: @ref testbmk.c
*
* <h2>Description</h2>
* This module implements a series of system benchmarks. The benchmarks are
* useful as a stress test and as a reference when comparing ChibiOS/RT
* with similar systems.
*
* <h2>Objective</h2>
* Objective of the test module is to provide a performance index for the
* most critical system subsystems. The performance numbers allow to
* discover performance regressions between successive ChibiOS/RT releases.
*
* <h2>Preconditions</h2>
* None.
*
* <h2>Test Cases</h2>
* - @subpage test_benchmarks_001
* - @subpage test_benchmarks_002
* - @subpage test_benchmarks_003
* - @subpage test_benchmarks_004
* - @subpage test_benchmarks_005
* - @subpage test_benchmarks_006
* - @subpage test_benchmarks_007
* - @subpage test_benchmarks_008
* - @subpage test_benchmarks_009
* - @subpage test_benchmarks_010
* - @subpage test_benchmarks_011
* - @subpage test_benchmarks_012
* - @subpage test_benchmarks_013
* .
* @file testbmk.c Kernel Benchmarks
* @brief Kernel Benchmarks source file
* @file testbmk.h
* @brief Kernel Benchmarks header file
*/
static Semaphore sem1;
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
static Mutex mtx1;
#endif
static msg_t thread1(void *p) {
Thread *tp;
msg_t msg;
(void)p;
do {
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
} while (msg);
return 0;
}
#ifdef __GNUC__
__attribute__((noinline))
#endif
static unsigned int msg_loop_test(Thread *tp) {
uint32_t n = 0;
test_wait_tick();
test_start_timer(1000);
do {
(void)chMsgSend(tp, 1);
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
(void)chMsgSend(tp, 0);
return n;
}
/**
* @page test_benchmarks_001 Messages performance #1
*
* <h2>Description</h2>
* A message server thread is created with a lower priority than the client
* thread, the messages throughput per second is measured and the result
* printed in the output log.
*/
static void bmk1_execute(void) {
uint32_t n;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread1, NULL);
n = msg_loop_test(threads[0]);
test_wait_threads();
test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk1 = {
"Benchmark, messages #1",
NULL,
NULL,
bmk1_execute
};
/**
* @page test_benchmarks_002 Messages performance #2
*
* <h2>Description</h2>
* A message server thread is created with an higher priority than the client
* thread, the messages throughput per second is measured and the result
* printed in the output log.
*/
static void bmk2_execute(void) {
uint32_t n;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL);
n = msg_loop_test(threads[0]);
test_wait_threads();
test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk2 = {
"Benchmark, messages #2",
NULL,
NULL,
bmk2_execute
};
static msg_t thread2(void *p) {
return (msg_t)p;
}
/**
* @page test_benchmarks_003 Messages performance #3
*
* <h2>Description</h2>
* A message server thread is created with an higher priority than the client
* thread, four lower priority threads crowd the ready list, the messages
* throughput per second is measured while the ready list and the result
* printed in the output log.
*/
static void bmk3_execute(void) {
uint32_t n;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-2, thread2, NULL);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-3, thread2, NULL);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-4, thread2, NULL);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-5, thread2, NULL);
n = msg_loop_test(threads[0]);
test_wait_threads();
test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk3 = {
"Benchmark, messages #3",
NULL,
NULL,
bmk3_execute
};
/**
* @page test_benchmarks_004 Context Switch performance
*
* <h2>Description</h2>
* A thread is created that just performs a @p chSchGoSleepS() into a loop,
* the thread is awakened as fast is possible by the tester thread.<br>
* The Context Switch performance is calculated by measuring the number of
* iterations after a second of continuous operations.
*/
msg_t thread4(void *p) {
msg_t msg;
Thread *self = chThdSelf();
(void)p;
chSysLock();
do {
chSchGoSleepS(THD_STATE_SUSPENDED);
msg = self->p_u.rdymsg;
} while (msg == RDY_OK);
chSysUnlock();
return 0;
}
static void bmk4_execute(void) {
Thread *tp;
uint32_t n;
tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread4, NULL);
n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chSysLock();
chSchWakeupS(tp, RDY_OK);
chSchWakeupS(tp, RDY_OK);
chSchWakeupS(tp, RDY_OK);
chSchWakeupS(tp, RDY_OK);
chSysUnlock();
n += 4;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
chSysLock();
chSchWakeupS(tp, RDY_TIMEOUT);
chSysUnlock();
test_wait_threads();
test_print("--- Score : ");
test_printn(n * 2);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk4 = {
"Benchmark, context switch",
NULL,
NULL,
bmk4_execute
};
/**
* @page test_benchmarks_005 Threads performance, full cycle
*
* <h2>Description</h2>
* Threads are continuously created and terminated into a loop. A full
* @p chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is performed
* in each iteration.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void bmk5_execute(void) {
uint32_t n = 0;
void *wap = wa[0];
tprio_t prio = chThdGetPriority() - 1;
test_wait_tick();
test_start_timer(1000);
do {
chThdWait(chThdCreateStatic(wap, WA_SIZE, prio, thread2, NULL));
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");
}
ROMCONST struct testcase testbmk5 = {
"Benchmark, threads, full cycle",
NULL,
NULL,
bmk5_execute
};
/**
* @page test_benchmarks_006 Threads performance, create/exit only
*
* <h2>Description</h2>
* Threads are continuously created and terminated into a loop. A partial
* @p chThdCreateStatic() / @p chThdExit() cycle is performed in each
* iteration, the @p chThdWait() is not necessary because the thread is
* created at an higher priority so there is no need to wait for it to
* terminate.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void bmk6_execute(void) {
uint32_t n = 0;
void *wap = wa[0];
tprio_t prio = chThdGetPriority() + 1;
test_wait_tick();
test_start_timer(1000);
do {
chThdCreateStatic(wap, WA_SIZE, prio, thread2, NULL);
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");
}
ROMCONST struct testcase testbmk6 = {
"Benchmark, threads, create only",
NULL,
NULL,
bmk6_execute
};
/**
* @page test_benchmarks_007 Mass reschedule performance
*
* <h2>Description</h2>
* Five threads are created and atomically rescheduled by resetting the
* semaphore where they are waiting on. The operation is performed into a
* continuous loop.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static msg_t thread3(void *p) {
(void)p;
while (!chThdShouldTerminate())
chSemWait(&sem1);
return 0;
}
static void bmk7_setup(void) {
chSemInit(&sem1, 0);
}
static void bmk7_execute(void) {
uint32_t n;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+5, thread3, NULL);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()+4, thread3, NULL);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()+3, thread3, NULL);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()+2, thread3, NULL);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()+1, thread3, NULL);
n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chSemReset(&sem1, 0);
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_terminate_threads();
chSemReset(&sem1, 0);
test_wait_threads();
test_print("--- Score : ");
test_printn(n);
test_print(" reschedules/S, ");
test_printn(n * 6);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk7 = {
"Benchmark, mass reschedule, 5 threads",
bmk7_setup,
NULL,
bmk7_execute
};
/**
* @page test_benchmarks_008 I/O Round-Robin voluntary reschedule.
*
* <h2>Description</h2>
* Five threads are created at equal priority, each thread just increases a
* variable and yields.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static msg_t thread8(void *p) {
do {
chThdYield();
chThdYield();
chThdYield();
chThdYield();
(*(uint32_t *)p) += 4;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while(!chThdShouldTerminate());
return 0;
}
static void bmk8_execute(void) {
uint32_t n;
n = 0;
test_wait_tick();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
chThdSleepSeconds(1);
test_terminate_threads();
test_wait_threads();
test_print("--- Score : ");
test_printn(n);
test_println(" ctxswc/S");
}
ROMCONST struct testcase testbmk8 = {
"Benchmark, round robin context switching",
NULL,
NULL,
bmk8_execute
};
#if CH_USE_QUEUES || defined(__DOXYGEN__)
/**
* @page test_benchmarks_009 I/O Queues throughput
*
* <h2>Description</h2>
* Four bytes are written and then read from an @p InputQueue into a continuous
* loop.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void bmk9_execute(void) {
uint32_t n;
static uint8_t ib[16];
static InputQueue iq;
chIQInit(&iq, ib, sizeof(ib), NULL, NULL);
n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chSysLock();
chIQPutI(&iq, 0);
chIQPutI(&iq, 1);
chIQPutI(&iq, 2);
chIQPutI(&iq, 3);
chSysUnlock();
(void)chIQGet(&iq);
(void)chIQGet(&iq);
(void)chIQGet(&iq);
(void)chIQGet(&iq);
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n * 4);
test_println(" bytes/S");
}
ROMCONST struct testcase testbmk9 = {
"Benchmark, I/O Queues throughput",
NULL,
NULL,
bmk9_execute
};
#endif /* CH_USE_QUEUES */
/**
* @page test_benchmarks_010 Virtual Timers set/reset performance
*
* <h2>Description</h2>
* A virtual timer is set and immediately reset into a continuous loop.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void tmo(void *param) {(void)param;}
static void bmk10_execute(void) {
static VirtualTimer vt1, vt2;
uint32_t n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chSysLock();
chVTSetI(&vt1, 1, tmo, NULL);
chVTSetI(&vt2, 10000, tmo, NULL);
chVTResetI(&vt1);
chVTResetI(&vt2);
chSysUnlock();
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n * 2);
test_println(" timers/S");
}
ROMCONST struct testcase testbmk10 = {
"Benchmark, virtual timers set/reset",
NULL,
NULL,
bmk10_execute
};
#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
/**
* @page test_benchmarks_011 Semaphores wait/signal performance
*
* <h2>Description</h2>
* A counting semaphore is taken/released into a continuous loop, no Context
* Switch happens because the counter is always non negative.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void bmk11_setup(void) {
chSemInit(&sem1, 1);
}
static void bmk11_execute(void) {
uint32_t n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n * 4);
test_println(" wait+signal/S");
}
ROMCONST struct testcase testbmk11 = {
"Benchmark, semaphores wait/signal",
bmk11_setup,
NULL,
bmk11_execute
};
#endif /* CH_USE_SEMAPHORES */
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @page test_benchmarks_012 Mutexes lock/unlock performance
*
* <h2>Description</h2>
* A mutex is locked/unlocked into a continuous loop, no Context Switch happens
* because there are no other threads asking for the mutex.<br>
* The performance is calculated by measuring the number of iterations after
* a second of continuous operations.
*/
static void bmk12_setup(void) {
chMtxInit(&mtx1);
}
static void bmk12_execute(void) {
uint32_t n = 0;
test_wait_tick();
test_start_timer(1000);
do {
chMtxLock(&mtx1);
chMtxUnlock();
chMtxLock(&mtx1);
chMtxUnlock();
chMtxLock(&mtx1);
chMtxUnlock();
chMtxLock(&mtx1);
chMtxUnlock();
n++;
#if defined(SIMULATOR)
ChkIntSources();
#endif
} while (!test_timer_done);
test_print("--- Score : ");
test_printn(n * 4);
test_println(" lock+unlock/S");
}
ROMCONST struct testcase testbmk12 = {
"Benchmark, mutexes lock/unlock",
bmk12_setup,
NULL,
bmk12_execute
};
#endif
/**
* @page test_benchmarks_013 RAM Footprint
*
* <h2>Description</h2>
* The memory size of the various kernel objects is printed.
*/
static void bmk13_execute(void) {
test_print("--- System: ");
test_printn(sizeof(ReadyList) + sizeof(VTList) +
PORT_IDLE_THREAD_STACK_SIZE +
(sizeof(Thread) + sizeof(struct intctx) +
sizeof(struct extctx) +
PORT_INT_REQUIRED_STACK) * 2);
test_println(" bytes");
test_print("--- Thread: ");
test_printn(sizeof(Thread));
test_println(" bytes");
test_print("--- Timer : ");
test_printn(sizeof(VirtualTimer));
test_println(" bytes");
#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
test_print("--- Semaph: ");
test_printn(sizeof(Semaphore));
test_println(" bytes");
#endif
#if CH_USE_EVENTS || defined(__DOXYGEN__)
test_print("--- EventS: ");
test_printn(sizeof(EventSource));
test_println(" bytes");
test_print("--- EventL: ");
test_printn(sizeof(EventListener));
test_println(" bytes");
#endif
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
test_print("--- Mutex : ");
test_printn(sizeof(Mutex));
test_println(" bytes");
#endif
#if CH_USE_CONDVARS || defined(__DOXYGEN__)
test_print("--- CondV.: ");
test_printn(sizeof(CondVar));
test_println(" bytes");
#endif
#if CH_USE_QUEUES || defined(__DOXYGEN__)
test_print("--- Queue : ");
test_printn(sizeof(GenericQueue));
test_println(" bytes");
#endif
#if CH_USE_MAILBOXES || defined(__DOXYGEN__)
test_print("--- MailB.: ");
test_printn(sizeof(Mailbox));
test_println(" bytes");
#endif
}
ROMCONST struct testcase testbmk13 = {
"Benchmark, RAM footprint",
NULL,
NULL,
bmk13_execute
};
/**
* @brief Test sequence for benchmarks.
*/
ROMCONST struct testcase * ROMCONST patternbmk[] = {
#if !TEST_NO_BENCHMARKS
&testbmk1,
&testbmk2,
&testbmk3,
&testbmk4,
&testbmk5,
&testbmk6,
&testbmk7,
&testbmk8,
#if CH_USE_QUEUES || defined(__DOXYGEN__)
&testbmk9,
#endif
&testbmk10,
#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
&testbmk11,
#endif
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
&testbmk12,
#endif
&testbmk13,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTBMK_H_
#define _TESTBMK_H_
extern ROMCONST struct testcase * ROMCONST patternbmk[];
#endif /* _TESTBMK_H_ */

View File

@ -0,0 +1,264 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_dynamic Dynamic APIs test
*
* File: @ref testdyn.c
*
* <h2>Description</h2>
* This module implements the test sequence for the dynamic thread creation
* APIs.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the dynamic APIs code.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_DYNAMIC
* - @p CH_USE_HEAP
* - @p CH_USE_MEMPOOLS
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_dynamic_001
* - @subpage test_dynamic_002
* - @subpage test_dynamic_003
* .
* @file testdyn.c
* @brief Dynamic thread APIs test source file
* @file testdyn.h
* @brief Dynamic thread APIs test header file
*/
#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
static MemoryHeap heap1;
#endif
#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
static MemoryPool mp1;
#endif
/**
* @page test_dynamic_001 Threads creation from Memory Heap
*
* <h2>Description</h2>
* Two threads are started by allocating the memory from the Memory Heap then
* the remaining heap space is arbitrarily allocated and a third tread startup
* is attempted.<br>
* The test expects the first two threads to successfully start and the last
* one to fail.
*/
static msg_t thread(void *p) {
test_emit_token(*(char *)p);
return 0;
}
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
static void dyn1_setup(void) {
chHeapInit(&heap1, test.buffer, sizeof(union test_buffers));
}
static void dyn1_execute(void) {
size_t n, sz;
void *p1;
tprio_t prio = chThdGetPriority();
(void)chHeapStatus(&heap1, &sz);
/* Starting threads from the heap. */
threads[0] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE),
prio-1, thread, "A");
threads[1] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE),
prio-2, thread, "B");
/* Allocating the whole heap in order to make the thread creation fail.*/
(void)chHeapStatus(&heap1, &n);
p1 = chHeapAlloc(&heap1, n);
threads[2] = chThdCreateFromHeap(&heap1, THD_WA_SIZE(THREADS_STACK_SIZE),
prio-3, thread, "C");
chHeapFree(p1);
test_assert(1, (threads[0] != NULL) &&
(threads[1] != NULL) &&
(threads[2] == NULL) &&
(threads[3] == NULL) &&
(threads[4] == NULL),
"thread creation failed");
/* Claiming the memory from terminated threads. */
test_wait_threads();
test_assert_sequence(2, "AB");
/* Heap status checked again.*/
test_assert(3, chHeapStatus(&heap1, &n) == 1, "heap fragmented");
test_assert(4, n == sz, "heap size changed");
}
ROMCONST struct testcase testdyn1 = {
"Dynamic APIs, threads creation from heap",
dyn1_setup,
NULL,
dyn1_execute
};
#endif /* (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) */
#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
/**
* @page test_dynamic_002 Threads creation from Memory Pool
*
* <h2>Description</h2>
* Five thread creation are attempted from a pool containing only four
* elements.<br>
* The test expects the first four threads to successfully start and the last
* one to fail.
*/
static void dyn2_setup(void) {
chPoolInit(&mp1, THD_WA_SIZE(THREADS_STACK_SIZE), NULL);
}
static void dyn2_execute(void) {
int i;
tprio_t prio = chThdGetPriority();
/* Adding the WAs to the pool. */
for (i = 0; i < 4; i++)
chPoolFree(&mp1, wa[i]);
/* Starting threads from the memory pool. */
threads[0] = chThdCreateFromMemoryPool(&mp1, prio-1, thread, "A");
threads[1] = chThdCreateFromMemoryPool(&mp1, prio-2, thread, "B");
threads[2] = chThdCreateFromMemoryPool(&mp1, prio-3, thread, "C");
threads[3] = chThdCreateFromMemoryPool(&mp1, prio-4, thread, "D");
threads[4] = chThdCreateFromMemoryPool(&mp1, prio-5, thread, "E");
test_assert(1, (threads[0] != NULL) &&
(threads[1] != NULL) &&
(threads[2] != NULL) &&
(threads[3] != NULL) &&
(threads[4] == NULL),
"thread creation failed");
/* Claiming the memory from terminated threads. */
test_wait_threads();
test_assert_sequence(2, "ABCD");
/* Now the pool must be full again. */
for (i = 0; i < 4; i++)
test_assert(3, chPoolAlloc(&mp1) != NULL, "pool list empty");
test_assert(4, chPoolAlloc(&mp1) == NULL, "pool list not empty");
}
ROMCONST struct testcase testdyn2 = {
"Dynamic APIs, threads creation from memory pool",
dyn2_setup,
NULL,
dyn2_execute
};
#endif /* CH_USE_MEMPOOLS */
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP && CH_USE_REGISTRY) || \
defined(__DOXYGEN__)
/**
* @page test_dynamic_003 Registry and References test
*
* <h2>Description</h2>
* Registry and Thread References APIs are tested for functionality and
* coverage.
*/
static bool_t regfind(Thread *tp) {
Thread *ftp;
bool_t found = FALSE;
ftp = chRegFirstThread();
do {
found |= ftp == tp;
ftp = chRegNextThread(ftp);
} while (ftp != NULL);
return found;
}
static void dyn3_setup(void) {
chHeapInit(&heap1, test.buffer, sizeof(union test_buffers));
}
static void dyn3_execute(void) {
Thread *tp;
tprio_t prio = chThdGetPriority();
/* Testing references increase/decrease and final detach.*/
tp = chThdCreateFromHeap(&heap1, WA_SIZE, prio-1, thread, "A");
test_assert(1, tp->p_refs == 1, "wrong initial reference counter");
chThdAddRef(tp);
test_assert(2, tp->p_refs == 2, "references increase failure");
chThdRelease(tp);
test_assert(3, tp->p_refs == 1, "references decrease failure");
/* Verify the new threads count.*/
test_assert(4, regfind(tp), "thread missing from registry");
test_assert(5, regfind(tp), "thread disappeared");
/* Detach and let the thread execute and terminate.*/
chThdRelease(tp);
test_assert(6, tp->p_refs == 0, "detach failure");
test_assert(7, tp->p_state == THD_STATE_READY, "invalid state");
test_assert(8, regfind(tp), "thread disappeared");
test_assert(9, regfind(tp), "thread disappeared");
chThdSleepMilliseconds(50); /* The thread just terminates. */
test_assert(10, tp->p_state == THD_STATE_FINAL, "invalid state");
/* Clearing the zombie by scanning the registry.*/
test_assert(11, regfind(tp), "thread disappeared");
test_assert(12, !regfind(tp), "thread still in registry");
}
ROMCONST struct testcase testdyn3 = {
"Dynamic APIs, registry and references",
dyn3_setup,
NULL,
dyn3_execute
};
#endif /* CH_USE_HEAP && CH_USE_REGISTRY */
#endif /* CH_USE_DYNAMIC */
/**
* @brief Test sequence for dynamic APIs.
*/
ROMCONST struct testcase * ROMCONST patterndyn[] = {
#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
&testdyn1,
#endif
#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
&testdyn2,
#endif
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP && CH_USE_REGISTRY) || \
defined(__DOXYGEN__)
&testdyn3,
#endif
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTDYN_H_
#define _TESTDYN_H_
extern ROMCONST struct testcase * ROMCONST patterndyn[];
#endif /* _TESTDYN_H_ */

View File

@ -0,0 +1,296 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_events Events test
*
* File: @ref testevt.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref events subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref events subsystem.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_EVENTS
* - @p CH_USE_EVENTS_TIMEOUT
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_events_001
* - @subpage test_events_002
* - @subpage test_events_003
* .
* @file testevt.c
* @brief Events test source file
* @file testevt.h
* @brief Events test header file
*/
#if CH_USE_EVENTS || defined(__DOXYGEN__)
#define ALLOWED_DELAY MS2ST(5)
/*
* Note, the static initializers are not really required because the
* variables are explicitly initialized in each test case. It is done in order
* to test the macros.
*/
static EVENTSOURCE_DECL(es1);
static EVENTSOURCE_DECL(es2);
/**
* @page test_events_001 Events registration and dispatch
*
* <h2>Description</h2>
* Two event listeners are registered on an event source and then unregistered
* in the same order.<br>
* The test expects that the even source has listeners after the registrations
* and after the first unregistration, then, after the second unegistration,
* the test expects no more listeners.<br>
* In the second part the test dispatches three event flags and verifies that
* the associated event handlers are invoked in LSb-first order.
*/
static void evt1_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
static void evt1_execute(void) {
EventListener el1, el2;
/*
* Testing chEvtRegisterMask() and chEvtUnregister().
*/
chEvtInit(&es1);
chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es1, &el2, 2);
test_assert(1, chEvtIsListeningI(&es1), "no listener");
chEvtUnregister(&es1, &el1);
test_assert(2, chEvtIsListeningI(&es1), "no listener");
chEvtUnregister(&es1, &el2);
test_assert(3, !chEvtIsListeningI(&es1), "stuck listener");
/*
* Testing chEvtDispatch().
*/
chEvtDispatch(evhndl, 7);
test_assert_sequence(4, "ABC");
}
ROMCONST struct testcase testevt1 = {
"Events, registration and dispatch",
evt1_setup,
NULL,
evt1_execute
};
/**
* @page test_events_002 Events wait and broadcast
*
* <h2>Description</h2>
* In this test the following APIs are indipently tested by starting threads
* that signal/broadcast events after fixed delays:
* - @p chEvtWaitOne()
* - @p chEvtWaitAny()
* - @p chEvtWaitAll()
* .
* After each test phase the test verifies that the events have been served at
* the expected time and that there are no stuck event flags.
*/
static void evt2_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static msg_t thread1(void *p) {
chThdSleepMilliseconds(50);
chEvtSignal((Thread *)p, 1);
return 0;
}
static msg_t thread2(void *p) {
(void)p;
chEvtBroadcast(&es1);
chThdSleepMilliseconds(50);
chEvtBroadcast(&es2);
return 0;
}
static void evt2_execute(void) {
eventmask_t m;
EventListener el1, el2;
systime_t target_time;
/*
* Test on chEvtWaitOne() without wait.
*/
chEvtAddEvents(7);
m = chEvtWaitOne(ALL_EVENTS);
test_assert(1, m == 1, "single event error");
m = chEvtWaitOne(ALL_EVENTS);
test_assert(2, m == 2, "single event error");
m = chEvtWaitOne(ALL_EVENTS);
test_assert(3, m == 4, "single event error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(4, m == 0, "stuck event");
/*
* Test on chEvtWaitOne() with wait.
*/
test_wait_tick();
target_time = chTimeNow() + MS2ST(50);
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
thread1, chThdSelf());
m = chEvtWaitOne(ALL_EVENTS);
test_assert_time_window(5, target_time, target_time + ALLOWED_DELAY);
test_assert(6, m == 1, "single event error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(7, m == 0, "stuck event");
test_wait_threads();
/*
* Test on chEvtWaitAny() without wait.
*/
chEvtAddEvents(5);
m = chEvtWaitAny(ALL_EVENTS);
test_assert(8, m == 5, "unexpected pending bit");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(9, m == 0, "stuck event");
/*
* Test on chEvtWaitAny() with wait.
*/
test_wait_tick();
target_time = chTimeNow() + MS2ST(50);
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
thread1, chThdSelf());
m = chEvtWaitAny(ALL_EVENTS);
test_assert_time_window(10, target_time, target_time + ALLOWED_DELAY);
test_assert(11, m == 1, "single event error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(12, m == 0, "stuck event");
test_wait_threads();
/*
* Test on chEvtWaitAll().
*/
chEvtInit(&es1);
chEvtInit(&es2);
chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es2, &el2, 4);
test_wait_tick();
target_time = chTimeNow() + MS2ST(50);
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
thread2, "A");
m = chEvtWaitAll(5);
test_assert_time_window(13, target_time, target_time + ALLOWED_DELAY);
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(14, m == 0, "stuck event");
test_wait_threads();
chEvtUnregister(&es1, &el1);
chEvtUnregister(&es2, &el2);
test_assert(15, !chEvtIsListeningI(&es1), "stuck listener");
test_assert(16, !chEvtIsListeningI(&es2), "stuck listener");
}
ROMCONST struct testcase testevt2 = {
"Events, wait and broadcast",
evt2_setup,
NULL,
evt2_execute
};
#if CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
/**
* @page test_events_003 Events timeout
*
* <h2>Description</h2>
* In this test the following APIs are let to timeout twice: immediatly and
* after 10ms:
* In this test the following APIs are indipently tested by starting threads
* that broadcast events after fixed delays:
* - @p chEvtWaitOneTimeout()
* - @p chEvtWaitAnyTimeout()
* - @p chEvtWaitAllTimeout()
* .
* After each test phase the test verifies that there are no stuck event flags.
*/
static void evt3_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void evt3_execute(void) {
eventmask_t m;
/*
* Tests various timeout situations.
*/
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(1, m == 0, "spurious event");
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(2, m == 0, "spurious event");
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(3, m == 0, "spurious event");
m = chEvtWaitOneTimeout(ALL_EVENTS, 10);
test_assert(4, m == 0, "spurious event");
m = chEvtWaitAnyTimeout(ALL_EVENTS, 10);
test_assert(5, m == 0, "spurious event");
m = chEvtWaitAllTimeout(ALL_EVENTS, 10);
test_assert(6, m == 0, "spurious event");
}
ROMCONST struct testcase testevt3 = {
"Events, timeouts",
evt3_setup,
NULL,
evt3_execute
};
#endif /* CH_USE_EVENTS_TIMEOUT */
/**
* @brief Test sequence for events.
*/
ROMCONST struct testcase * ROMCONST patternevt[] = {
#if CH_USE_EVENTS || defined(__DOXYGEN__)
&testevt1,
&testevt2,
#if CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
&testevt3,
#endif
#endif
NULL
};
#endif /* CH_USE_EVENTS */

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTEVT_H_
#define _TESTEVT_H_
extern ROMCONST struct testcase * ROMCONST patternevt[];
#endif /* _TESTEVT_H_ */

View File

@ -0,0 +1,159 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_heap Memory Heap test
*
* File: @ref testheap.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref heaps subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref heaps subsystem.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_HEAP
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_heap_001
* .
* @file testheap.c
* @brief Heap test source file
* @file testheap.h
* @brief Heap header file
*/
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
#define SIZE 16
static MemoryHeap test_heap;
/**
* @page test_heap_001 Allocation and fragmentation test
*
* <h2>Description</h2>
* Series of allocations/deallocations are performed in carefully designed
* sequences in order to stimulate all the possible code paths inside the
* allocator.<br>
* The test expects to find the heap back to the initial status after each
* sequence.
*/
static void heap1_setup(void) {
chHeapInit(&test_heap, test.buffer, sizeof(union test_buffers));
}
static void heap1_execute(void) {
void *p1, *p2, *p3;
size_t n, sz;
/* Unrelated, for coverage only.*/
(void)chCoreStatus();
/*
* Test on the default heap in order to cover the core allocator at
* least one time.
*/
(void)chHeapStatus(NULL, &sz);
p1 = chHeapAlloc(NULL, SIZE);
test_assert(1, p1 != NULL, "allocation failed");
chHeapFree(p1);
p1 = chHeapAlloc(NULL, (size_t)-256);
test_assert(2, p1 == NULL, "allocation not failed");
/* Initial local heap state.*/
(void)chHeapStatus(&test_heap, &sz);
/* Same order.*/
p1 = chHeapAlloc(&test_heap, SIZE);
p2 = chHeapAlloc(&test_heap, SIZE);
p3 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p1); /* Does not merge.*/
chHeapFree(p2); /* Merges backward.*/
chHeapFree(p3); /* Merges both sides.*/
test_assert(3, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
/* Reverse order.*/
p1 = chHeapAlloc(&test_heap, SIZE);
p2 = chHeapAlloc(&test_heap, SIZE);
p3 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p3); /* Merges forward.*/
chHeapFree(p2); /* Merges forward.*/
chHeapFree(p1); /* Merges forward.*/
test_assert(4, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
/* Small fragments handling.*/
p1 = chHeapAlloc(&test_heap, SIZE + 1);
p2 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p1);
test_assert(5, chHeapStatus(&test_heap, &n) == 2, "invalid state");
p1 = chHeapAlloc(&test_heap, SIZE);
/* Note, the first situation happens when the alignment size is smaller
than the header size, the second in the other cases.*/
test_assert(6, (chHeapStatus(&test_heap, &n) == 1) ||
(chHeapStatus(&test_heap, &n) == 2), "heap fragmented");
chHeapFree(p2);
chHeapFree(p1);
test_assert(7, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
/* Skip fragment handling.*/
p1 = chHeapAlloc(&test_heap, SIZE);
p2 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p1);
test_assert(8, chHeapStatus(&test_heap, &n) == 2, "invalid state");
p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment.*/
chHeapFree(p1);
chHeapFree(p2);
test_assert(9, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
/* Allocate all handling.*/
(void)chHeapStatus(&test_heap, &n);
p1 = chHeapAlloc(&test_heap, n);
test_assert(10, chHeapStatus(&test_heap, &n) == 0, "not empty");
chHeapFree(p1);
test_assert(11, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
test_assert(12, n == sz, "size changed");
}
ROMCONST struct testcase testheap1 = {
"Heap, allocation and fragmentation test",
heap1_setup,
NULL,
heap1_execute
};
#endif /* CH_USE_HEAP.*/
/**
* @brief Test sequence for heap.
*/
ROMCONST struct testcase * ROMCONST patternheap[] = {
#if (CH_USE_HEAP && !CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
&testheap1,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTHEAP_H_
#define _TESTHEAP_H_
extern ROMCONST struct testcase * ROMCONST patternheap[];
#endif /* _TESTHEAP_H_ */

View File

@ -0,0 +1,239 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_mbox Mailboxes test
*
* File: @ref testmbox.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref mailboxes subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref mailboxes
* subsystem code.<br>
* Note that the @ref mailboxes subsystem depends on the @ref semaphores
* subsystem that has to met its testing objectives as well.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_MAILBOXES
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_mbox_001
* .
* @file testmbox.c
* @brief Mailboxes test source file
* @file testmbox.h
* @brief Mailboxes header file
*/
#if CH_USE_MAILBOXES || defined(__DOXYGEN__)
#define ALLOWED_DELAY MS2ST(5)
#define MB_SIZE 5
/*
* Note, the static initializers are not really required because the
* variables are explicitly initialized in each test case. It is done in order
* to test the macros.
*/
static MAILBOX_DECL(mb1, test.wa.T0, MB_SIZE);
/**
* @page test_mbox_001 Queuing and timeouts
*
* <h2>Description</h2>
* Messages are posted/fetched from a mailbox in carefully designed sequences
* in order to stimulate all the possible code paths inside the mailbox.<br>
* The test expects to find a consistent mailbox status after each operation.
*/
static void mbox1_setup(void) {
chMBInit(&mb1, (msg_t *)test.wa.T0, MB_SIZE);
}
static void mbox1_execute(void) {
msg_t msg1, msg2;
unsigned i;
/*
* Testing initial space.
*/
test_assert(1, chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
/*
* Testing enqueuing and backward circularity.
*/
for (i = 0; i < MB_SIZE - 1; i++) {
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
test_assert(2, msg1 == RDY_OK, "wrong wake-up message");
}
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
test_assert(3, msg1 == RDY_OK, "wrong wake-up message");
/*
* Testing post timeout.
*/
msg1 = chMBPost(&mb1, 'X', 1);
test_assert(4, msg1 == RDY_TIMEOUT, "wrong wake-up message");
chSysLock();
msg1 = chMBPostI(&mb1, 'X');
chSysUnlock();
test_assert(5, msg1 == RDY_TIMEOUT, "wrong wake-up message");
msg1 = chMBPostAhead(&mb1, 'X', 1);
test_assert(6, msg1 == RDY_TIMEOUT, "wrong wake-up message");
chSysLock();
msg1 = chMBPostAheadI(&mb1, 'X');
chSysUnlock();
test_assert(7, msg1 == RDY_TIMEOUT, "wrong wake-up message");
/*
* Testing final conditions.
*/
test_assert_lock(8, chMBGetFreeCountI(&mb1) == 0, "still empty");
test_assert_lock(9, chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
test_assert_lock(10, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
/*
* Testing dequeuing.
*/
for (i = 0; i < MB_SIZE; i++) {
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
test_assert(11, msg1 == RDY_OK, "wrong wake-up message");
test_emit_token(msg2);
}
test_assert_sequence(12, "ABCDE");
/*
* Testing buffer circularity.
*/
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
test_assert(13, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
test_assert(14, msg1 == RDY_OK, "wrong wake-up message");
test_assert(15, mb1.mb_buffer == mb1.mb_wrptr, "write pointer not aligned to base");
test_assert(16, mb1.mb_buffer == mb1.mb_rdptr, "read pointer not aligned to base");
/*
* Testing fetch timeout.
*/
msg1 = chMBFetch(&mb1, &msg2, 1);
test_assert(17, msg1 == RDY_TIMEOUT, "wrong wake-up message");
chSysLock();
msg1 = chMBFetchI(&mb1, &msg2);
chSysUnlock();
test_assert(18, msg1 == RDY_TIMEOUT, "wrong wake-up message");
/*
* Testing final conditions.
*/
test_assert_lock(19, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
test_assert_lock(20, chMBGetUsedCountI(&mb1) == 0, "still full");
test_assert_lock(21, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
/*
* Testing I-Class.
*/
chSysLock();
msg1 = chMBPostI(&mb1, 'A');
test_assert(22, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostI(&mb1, 'B');
test_assert(23, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostI(&mb1, 'C');
test_assert(24, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostI(&mb1, 'D');
test_assert(25, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostI(&mb1, 'E');
chSysUnlock();
test_assert(26, msg1 == RDY_OK, "wrong wake-up message");
test_assert(27, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
for (i = 0; i < MB_SIZE; i++) {
chSysLock();
msg1 = chMBFetchI(&mb1, &msg2);
chSysUnlock();
test_assert(28, msg1 == RDY_OK, "wrong wake-up message");
test_emit_token(msg2);
}
test_assert_sequence(29, "ABCDE");
test_assert_lock(30, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
test_assert_lock(31, chMBGetUsedCountI(&mb1) == 0, "still full");
test_assert(32, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
chSysLock();
msg1 = chMBPostAheadI(&mb1, 'E');
test_assert(33, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostAheadI(&mb1, 'D');
test_assert(34, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostAheadI(&mb1, 'C');
test_assert(35, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostAheadI(&mb1, 'B');
test_assert(36, msg1 == RDY_OK, "wrong wake-up message");
msg1 = chMBPostAheadI(&mb1, 'A');
chSysUnlock();
test_assert(37, msg1 == RDY_OK, "wrong wake-up message");
test_assert(38, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
for (i = 0; i < MB_SIZE; i++) {
chSysLock();
msg1 = chMBFetchI(&mb1, &msg2);
chSysUnlock();
test_assert(39, msg1 == RDY_OK, "wrong wake-up message");
test_emit_token(msg2);
}
test_assert_sequence(40, "ABCDE");
test_assert_lock(41, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
test_assert_lock(42, chMBGetUsedCountI(&mb1) == 0, "still full");
test_assert(43, mb1.mb_rdptr == mb1.mb_wrptr, "pointers not aligned");
/*
* Testing reset.
*/
chMBReset(&mb1);
/*
* Re-testing final conditions.
*/
test_assert_lock(44, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
test_assert_lock(45, chMBGetUsedCountI(&mb1) == 0, "still full");
test_assert_lock(46, mb1.mb_buffer == mb1.mb_wrptr, "write pointer not aligned to base");
test_assert_lock(47, mb1.mb_buffer == mb1.mb_rdptr, "read pointer not aligned to base");
}
ROMCONST struct testcase testmbox1 = {
"Mailboxes, queuing and timeouts",
mbox1_setup,
NULL,
mbox1_execute
};
#endif /* CH_USE_MAILBOXES */
/**
* @brief Test sequence for mailboxes.
*/
ROMCONST struct testcase * ROMCONST patternmbox[] = {
#if CH_USE_MAILBOXES || defined(__DOXYGEN__)
&testmbox1,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTMBOX_H_
#define _TESTMBOX_H_
extern ROMCONST struct testcase * ROMCONST patternmbox[];
#endif /* _TESTMBOX_H_ */

View File

@ -0,0 +1,108 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_msg Messages test
*
* File: @ref testmsg.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref messages subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref messages
* subsystem code.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_MESSAGES
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_msg_001
* .
* @file testmsg.c
* @brief Messages test source file
* @file testmsg.h
* @brief Messages header file
*/
#if CH_USE_MESSAGES || defined(__DOXYGEN__)
/**
* @page test_msg_001 Messages Server loop
*
* <h2>Description</h2>
* A thread is spawned that sends four messages back to the tester thread.<br>
* The test expect to receive the messages in the correct sequence and to
* not find a fifth message waiting.
*/
static msg_t thread(void *p) {
chMsgSend(p, 'A');
chMsgSend(p, 'B');
chMsgSend(p, 'C');
return 0;
}
static void msg1_execute(void) {
Thread *tp;
msg_t msg;
/*
* Testing the whole messages loop.
*/
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() + 1,
thread, chThdSelf());
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
test_emit_token(msg);
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
test_emit_token(msg);
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
test_emit_token(msg);
test_assert_sequence(1, "ABC");
}
ROMCONST struct testcase testmsg1 = {
"Messages, loop",
NULL,
NULL,
msg1_execute
};
#endif /* CH_USE_MESSAGES */
/**
* @brief Test sequence for messages.
*/
ROMCONST struct testcase * ROMCONST patternmsg[] = {
#if CH_USE_MESSAGES || defined(__DOXYGEN__)
&testmsg1,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTMSG_H_
#define _TESTMSG_H_
extern ROMCONST struct testcase * ROMCONST patternmsg[];
#endif /* _TESTMSG_H_ */

View File

@ -0,0 +1,636 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_mtx Mutexes test
*
* File: @ref testmtx.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref mutexes and
* @ref condvars subsystems.<br>
* Tests on those subsystems are particularly critical because the system-wide
* implications of the Priority Inheritance mechanism.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the subsystems code.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_MUTEXES
* - @p CH_USE_CONDVARS
* - @p CH_DBG_THREADS_PROFILING
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_mtx_001
* - @subpage test_mtx_002
* - @subpage test_mtx_003
* - @subpage test_mtx_004
* - @subpage test_mtx_005
* - @subpage test_mtx_006
* - @subpage test_mtx_007
* - @subpage test_mtx_008
* .
* @file testmtx.c
* @brief Mutexes and CondVars test source file
* @file testmtx.h
* @brief Mutexes and CondVars test header file
*/
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
#define ALLOWED_DELAY 5
/*
* Note, the static initializers are not really required because the
* variables are explicitly initialized in each test case. It is done in order
* to test the macros.
*/
static MUTEX_DECL(m1);
static MUTEX_DECL(m2);
#if CH_USE_CONDVARS || defined(__DOXYGEN__)
static CONDVAR_DECL(c1);
#endif
/**
* @page test_mtx_001 Priority enqueuing test
*
* <h2>Description</h2>
* Five threads, with increasing priority, are enqueued on a locked mutex then
* the mutex is unlocked.<br>
* The test expects the threads to perform their operations in increasing
* priority order regardless of the initial order.
*/
static void mtx1_setup(void) {
chMtxInit(&m1);
}
static msg_t thread1(void *p) {
chMtxLock(&m1);
test_emit_token(*(char *)p);
chMtxUnlock();
return 0;
}
static void mtx1_execute(void) {
tprio_t prio = chThdGetPriority(); /* Because priority inheritance.*/
chMtxLock(&m1);
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A");
chMtxUnlock();
test_wait_threads();
test_assert(1, prio == chThdGetPriority(), "wrong priority level");
test_assert_sequence(2, "ABCDE");
}
ROMCONST struct testcase testmtx1 = {
"Mutexes, priority enqueuing test",
mtx1_setup,
NULL,
mtx1_execute
};
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
/**
* @page test_mtx_002 Priority inheritance, simple case
*
* <h2>Description</h2>
* Three threads are involved in the classic priority inversion scenario, a
* medium priority thread tries to starve an high priority thread by
* blocking a low priority thread into a mutex lock zone.<br>
* The test expects the threads to reach their goal in increasing priority
* order by rearranging their priorities in order to avoid the priority
* inversion trap.
*
* <h2>Scenario</h2>
* This weird looking diagram should explain what happens in the test case:
* @code
* Time ----> 0 10 20 30 40 50 60 70 80 90 100
* 0 ......AL++++++++++............2+++++++++++AU0---------------++++++G...
* 1 ..................++++++++++++------------------++++++++++++G.........
* 2 .............................AL..........++++++AUG...................
* ^ ^
* Legend:
* 0..2 - Priority levels
* +++ - Running
* --- - Ready
* ... - Waiting or Terminated
* xL - Lock operation on mutex 'x'
* xUn - Unlock operation on mutex 'x' with priority returning to level 'n'
* G - Goal
* ^ - Priority transition (boost or return).
* @endcode
*/
static void mtx2_setup(void) {
chMtxInit(&m1);
}
/* Low priority thread */
static msg_t thread2L(void *p) {
(void)p;
chMtxLock(&m1);
test_cpu_pulse(40);
chMtxUnlock();
test_cpu_pulse(10);
test_emit_token('C');
return 0;
}
/* Medium priority thread */
static msg_t thread2M(void *p) {
(void)p;
chThdSleepMilliseconds(20);
test_cpu_pulse(40);
test_emit_token('B');
return 0;
}
/* High priority thread */
static msg_t thread2H(void *p) {
(void)p;
chThdSleepMilliseconds(40);
chMtxLock(&m1);
test_cpu_pulse(10);
chMtxUnlock();
test_emit_token('A');
return 0;
}
static void mtx2_execute(void) {
systime_t time;
test_wait_tick();
time = chTimeNow();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread2H, 0);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-2, thread2M, 0);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-3, thread2L, 0);
test_wait_threads();
test_assert_sequence(1, "ABC");
test_assert_time_window(2, time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY);
}
ROMCONST struct testcase testmtx2 = {
"Mutexes, priority inheritance, simple case",
mtx2_setup,
NULL,
mtx2_execute
};
/**
* @page test_mtx_003 Priority inheritance, complex case
*
* <h2>Description</h2>
* Five threads are involved in the complex priority inversion scenario,
* please refer to the diagram below for the complete scenario.<br>
* The test expects the threads to perform their operations in increasing
* priority order by rearranging their priorities in order to avoid the
* priority inversion trap.
*
* <h2>Scenario</h2>
* This weird looking diagram should explain what happens in the test case:
* @code
* Time ----> 0 10 20 30 40 50 60 70 80 90 100 110
* 0 ......BL++++------------2+++++------4+++++BU0---------------------------G.....
* 1 ............AL++++2+++++BL----------4-----++++++BU4+++AU1---------------G.....
* 2 ..................AL----------------------------------------------++++++AUG...
* 3 ..............................+++++++-----------------------++++++G...........
* 4 ....................................AL................++++++AUG...............
* ^ ^ ^ ^ ^ ^
* Legend:
* 0..4 - Priority levels
* +++ - Running
* --- - Ready
* ... - Waiting or Terminated
* xL - Lock operation on mutex 'x'
* xUn - Unlock operation on mutex 'x' with priority returning to level 'n'
* ^ - Priority transition (boost or return).
* @endcode
*/
static void mtx3_setup(void) {
chMtxInit(&m1); /* Mutex B.*/
chMtxInit(&m2); /* Mutex A.*/
}
/* Lowest priority thread */
static msg_t thread3LL(void *p) {
(void)p;
chMtxLock(&m1);
test_cpu_pulse(30);
chMtxUnlock();
test_emit_token('E');
return 0;
}
/* Low priority thread */
static msg_t thread3L(void *p) {
(void)p;
chThdSleepMilliseconds(10);
chMtxLock(&m2);
test_cpu_pulse(20);
chMtxLock(&m1);
test_cpu_pulse(10);
chMtxUnlock();
test_cpu_pulse(10);
chMtxUnlock();
test_emit_token('D');
return 0;
}
/* Medium priority thread */
static msg_t thread3M(void *p) {
(void)p;
chThdSleepMilliseconds(20);
chMtxLock(&m2);
test_cpu_pulse(10);
chMtxUnlock();
test_emit_token('C');
return 0;
}
/* High priority thread */
static msg_t thread3H(void *p) {
(void)p;
chThdSleepMilliseconds(40);
test_cpu_pulse(20);
test_emit_token('B');
return 0;
}
/* Highest priority thread */
static msg_t thread3HH(void *p) {
(void)p;
chThdSleepMilliseconds(50);
chMtxLock(&m2);
test_cpu_pulse(10);
chMtxUnlock();
test_emit_token('A');
return 0;
}
static void mtx3_execute(void) {
systime_t time;
test_wait_tick();
time = chTimeNow();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-5, thread3LL, 0);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-4, thread3L, 0);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-3, thread3M, 0);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-2, thread3H, 0);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-1, thread3HH, 0);
test_wait_threads();
test_assert_sequence(1, "ABCDE");
test_assert_time_window(2, time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY);
}
ROMCONST struct testcase testmtx3 = {
"Mutexes, priority inheritance, complex case",
mtx3_setup,
NULL,
mtx3_execute
};
#endif /* CH_DBG_THREADS_PROFILING */
/**
* @page test_mtx_004 Priority return verification
*
* <h2>Description</h2>
* Two threads are spawned that try to lock the mutexes locked by the tester
* thread with precise timing.<br>
* The test expects that the priority changes caused by the priority
* inheritance algorithm happen at the right moment and with the right values.
*/
static void mtx4_setup(void) {
chMtxInit(&m1);
chMtxInit(&m2);
}
static msg_t thread4a(void *p) {
(void)p;
chThdSleepMilliseconds(50);
chMtxLock(&m2);
chMtxUnlock();
return 0;
}
static msg_t thread4b(void *p) {
(void)p;
chThdSleepMilliseconds(150);
chMtxLock(&m1);
chMtxUnlock();
return 0;
}
static void mtx4_execute(void) {
tprio_t p, p1, p2;
p = chThdGetPriority();
p1 = p + 1;
p2 = p + 2;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, p1, thread4a, "B");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, p2, thread4b, "A");
chMtxLock(&m2);
test_assert(1, chThdGetPriority() == p, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(2, chThdGetPriority() == p1, "wrong priority level");
chMtxLock(&m1);
test_assert(3, chThdGetPriority() == p1, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(4, chThdGetPriority() == p2, "wrong priority level");
chMtxUnlock();
test_assert(5, chThdGetPriority() == p1, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(6, chThdGetPriority() == p1, "wrong priority level");
chMtxUnlockAll();
test_assert(7, chThdGetPriority() == p, "wrong priority level");
test_wait_threads();
/* Test repeated in order to cover chMtxUnlockS().*/
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, p1, thread4a, "D");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, p2, thread4b, "C");
chMtxLock(&m2);
test_assert(8, chThdGetPriority() == p, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(9, chThdGetPriority() == p1, "wrong priority level");
chMtxLock(&m1);
test_assert(10, chThdGetPriority() == p1, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(11, chThdGetPriority() == p2, "wrong priority level");
chSysLock();
chMtxUnlockS();
chSchRescheduleS();
chSysUnlock();
test_assert(12, chThdGetPriority() == p1, "wrong priority level");
chThdSleepMilliseconds(100);
test_assert(13, chThdGetPriority() == p1, "wrong priority level");
chMtxUnlockAll();
test_assert(14, chThdGetPriority() == p, "wrong priority level");
test_wait_threads();
}
ROMCONST struct testcase testmtx4 = {
"Mutexes, priority return",
mtx4_setup,
NULL,
mtx4_execute
};
/**
* @page test_mtx_005 Mutex status
*
* <h2>Description</h2>
* Various tests on the mutex structure status after performing some lock and
* unlock operations.<br>
* The test expects that the internal mutex status is consistent after each
* operation.
*/
static void mtx5_setup(void) {
chMtxInit(&m1);
}
static void mtx5_execute(void) {
bool_t b;
tprio_t prio;
prio = chThdGetPriority();
b = chMtxTryLock(&m1);
test_assert(1, b, "already locked");
b = chMtxTryLock(&m1);
test_assert(2, !b, "not locked");
chSysLock();
chMtxUnlockS();
chSysUnlock();
test_assert(3, isempty(&m1.m_queue), "queue not empty");
test_assert(4, m1.m_owner == NULL, "still owned");
test_assert(5, chThdGetPriority() == prio, "wrong priority level");
chMtxLock(&m1);
chMtxUnlockAll();
test_assert(6, isempty(&m1.m_queue), "queue not empty");
test_assert(7, m1.m_owner == NULL, "still owned");
}
ROMCONST struct testcase testmtx5 = {
"Mutexes, status",
mtx5_setup,
NULL,
mtx5_execute
};
#if CH_USE_CONDVARS || defined(__DOXYGEN__)
/**
* @page test_mtx_006 Condition Variable signal test
*
* <h2>Description</h2>
* Five threads take a mutex and then enter a conditional variable queue, the
* tester thread then proceeds to signal the conditional variable five times
* atomically.<br>
* The test expects the threads to reach their goal in increasing priority
* order regardless of the initial order.
*/
static void mtx6_setup(void) {
chCondInit(&c1);
chMtxInit(&m1);
}
static msg_t thread10(void *p) {
chMtxLock(&m1);
chCondWait(&c1);
test_emit_token(*(char *)p);
chMtxUnlock();
return 0;
}
static void mtx6_execute(void) {
tprio_t prio = chThdGetPriority();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread10, "E");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "D");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread10, "C");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread10, "B");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread10, "A");
chSysLock();
chCondSignalI(&c1);
chCondSignalI(&c1);
chCondSignalI(&c1);
chCondSignalI(&c1);
chCondSignalI(&c1);
chSchRescheduleS();
chSysUnlock();
test_wait_threads();
test_assert_sequence(1, "ABCDE");
}
ROMCONST struct testcase testmtx6 = {
"CondVar, signal test",
mtx6_setup,
NULL,
mtx6_execute
};
/**
* @page test_mtx_007 Condition Variable broadcast test
*
* <h2>Description</h2>
* Five threads take a mutex and then enter a conditional variable queue, the
* tester thread then proceeds to broadcast the conditional variable.<br>
* The test expects the threads to reach their goal in increasing priority
* order regardless of the initial order.
*/
static void mtx7_setup(void) {
chCondInit(&c1);
chMtxInit(&m1);
}
static void mtx7_execute(void) {
tprio_t prio = chThdGetPriority();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread10, "E");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "D");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread10, "C");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread10, "B");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread10, "A");
chCondBroadcast(&c1);
test_wait_threads();
test_assert_sequence(1, "ABCDE");
}
ROMCONST struct testcase testmtx7 = {
"CondVar, broadcast test",
mtx7_setup,
NULL,
mtx7_execute
};
/**
* @page test_mtx_008 Condition Variable priority boost test
*
* <h2>Description</h2>
* This test case verifies the priority boost of a thread waiting on a
* conditional variable queue. It tests this very specific situation in order
* to complete the code coverage.
*/
static void mtx8_setup(void) {
chCondInit(&c1);
chMtxInit(&m1);
chMtxInit(&m2);
}
static msg_t thread11(void *p) {
chMtxLock(&m2);
chMtxLock(&m1);
#if CH_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
chCondWaitTimeout(&c1, TIME_INFINITE);
#else
chCondWait(&c1);
#endif
test_emit_token(*(char *)p);
chMtxUnlock();
chMtxUnlock();
return 0;
}
static msg_t thread12(void *p) {
chMtxLock(&m2);
test_emit_token(*(char *)p);
chMtxUnlock();
return 0;
}
static void mtx8_execute(void) {
tprio_t prio = chThdGetPriority();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread11, "A");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "C");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread12, "B");
chCondSignal(&c1);
chCondSignal(&c1);
test_wait_threads();
test_assert_sequence(1, "ABC");
}
ROMCONST struct testcase testmtx8 = {
"CondVar, boost test",
mtx8_setup,
NULL,
mtx8_execute
};
#endif /* CH_USE_CONDVARS */
#endif /* CH_USE_MUTEXES */
/**
* @brief Test sequence for mutexes.
*/
ROMCONST struct testcase * ROMCONST patternmtx[] = {
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
&testmtx1,
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
&testmtx2,
&testmtx3,
#endif
&testmtx4,
&testmtx5,
#if CH_USE_CONDVARS || defined(__DOXYGEN__)
&testmtx6,
&testmtx7,
&testmtx8,
#endif
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTMTX_H_
#define _TESTMTX_H_
extern ROMCONST struct testcase * ROMCONST patternmtx[];
#endif /* _TESTMTX_H_ */

View File

@ -0,0 +1,117 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_pools Memory Pools test
*
* File: @ref testpools.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref pools subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref pools code.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_MEMPOOLS
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_pools_001
* .
* @file testpools.c
* @brief Memory Pools test source file
* @file testpools.h
* @brief Memory Pools test header file
*/
#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
static MEMORYPOOL_DECL(mp1, THD_WA_SIZE(THREADS_STACK_SIZE), NULL);
/**
* @page test_pools_001 Allocation and enqueuing test
*
* <h2>Description</h2>
* Five memory blocks are added to a memory pool then removed.<br>
* The test expects to find the pool queue in the proper status after each
* operation.
*/
static void *null_provider(size_t size) {
(void)size;
return NULL;
}
static void pools1_setup(void) {
chPoolInit(&mp1, THD_WA_SIZE(THREADS_STACK_SIZE), NULL);
}
static void pools1_execute(void) {
int i;
/* Adding the WAs to the pool.*/
chPoolLoadArray(&mp1, wa[0], MAX_THREADS);
/* Emptying the pool.*/
for (i = 0; i < MAX_THREADS; i++)
test_assert(1, chPoolAlloc(&mp1) != NULL, "list empty");
/* Now must be empty.*/
test_assert(2, chPoolAlloc(&mp1) == NULL, "list not empty");
/* Adding the WAs to the pool, one by one this time.*/
for (i = 0; i < MAX_THREADS; i++)
chPoolFree(&mp1, wa[i]);
/* Emptying the pool again.*/
for (i = 0; i < MAX_THREADS; i++)
test_assert(3, chPoolAlloc(&mp1) != NULL, "list empty");
/* Now must be empty again.*/
test_assert(4, chPoolAlloc(&mp1) == NULL, "list not empty");
/* Covering the case where a provider is unable to return more memory.*/
chPoolInit(&mp1, 16, null_provider);
test_assert(5, chPoolAlloc(&mp1) == NULL, "provider returned memory");
}
ROMCONST struct testcase testpools1 = {
"Memory Pools, queue/dequeue",
pools1_setup,
NULL,
pools1_execute
};
#endif /* CH_USE_MEMPOOLS */
/*
* @brief Test sequence for pools.
*/
ROMCONST struct testcase * ROMCONST patternpools[] = {
#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
&testpools1,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTPOOLS_H_
#define _TESTPOOLS_H_
extern ROMCONST struct testcase * ROMCONST patternpools[];
#endif /* _TESTPOOLS_H_ */

View File

@ -0,0 +1,244 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_queues I/O Queues test
*
* File: @ref testqueues.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref io_queues subsystem.
* The tests are performed by inserting and removing data from queues and by
* checking both the queues status and the correct sequence of the extracted
* data.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref io_queues code.<br>
* Note that the @ref io_queues subsystem depends on the @ref semaphores
* subsystem that has to met its testing objectives as well.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_QUEUES (and dependent options)
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_queues_001
* - @subpage test_queues_002
* .
* @file testqueues.c
* @brief I/O Queues test source file
* @file testqueues.h
* @brief I/O Queues test header file
*/
#if CH_USE_QUEUES || defined(__DOXYGEN__)
#define TEST_QUEUES_SIZE 4
static void notify(GenericQueue *qp) {
(void)qp;
}
/*
* Note, the static initializers are not really required because the
* variables are explicitly initialized in each test case. It is done in order
* to test the macros.
*/
static INPUTQUEUE_DECL(iq, test.wa.T0, TEST_QUEUES_SIZE, notify, NULL);
static OUTPUTQUEUE_DECL(oq, test.wa.T1, TEST_QUEUES_SIZE, notify, NULL);
/**
* @page test_queues_001 Input Queues functionality and APIs
*
* <h2>Description</h2>
* This test case tests sysnchronos and asynchronous operations on an
* @p InputQueue object including timeouts. The queue state must remain
* consistent through the whole test.
*/
static void queues1_setup(void) {
chIQInit(&iq, wa[0], TEST_QUEUES_SIZE, notify, NULL);
}
static msg_t thread1(void *p) {
(void)p;
chIQGetTimeout(&iq, MS2ST(200));
return 0;
}
static void queues1_execute(void) {
unsigned i;
size_t n;
/* Initial empty state */
test_assert_lock(1, chIQIsEmptyI(&iq), "not empty");
/* Queue filling */
chSysLock();
for (i = 0; i < TEST_QUEUES_SIZE; i++)
chIQPutI(&iq, 'A' + i);
chSysUnlock();
test_assert_lock(2, chIQIsFullI(&iq), "still has space");
test_assert_lock(3, chIQPutI(&iq, 0) == Q_FULL, "failed to report Q_FULL");
/* Queue emptying */
for (i = 0; i < TEST_QUEUES_SIZE; i++)
test_emit_token(chIQGet(&iq));
test_assert_lock(4, chIQIsEmptyI(&iq), "still full");
test_assert_sequence(5, "ABCD");
/* Queue filling again */
chSysLock();
for (i = 0; i < TEST_QUEUES_SIZE; i++)
chIQPutI(&iq, 'A' + i);
chSysUnlock();
/* Reading the whole thing */
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size");
test_assert_lock(7, chIQIsEmptyI(&iq), "still full");
/* Queue filling again */
chSysLock();
for (i = 0; i < TEST_QUEUES_SIZE; i++)
chIQPutI(&iq, 'A' + i);
chSysUnlock();
/* Partial reads */
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
test_assert(8, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
test_assert(9, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
test_assert_lock(10, chIQIsEmptyI(&iq), "still full");
/* Testing reset */
chSysLock();
chIQPutI(&iq, 0);
chIQResetI(&iq);
chSysUnlock();
test_assert_lock(11, chIQGetFullI(&iq) == 0, "still full");
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL);
test_assert_lock(12, chIQGetFullI(&iq) == 0, "not empty");
test_wait_threads();
/* Timeout */
test_assert(13, chIQGetTimeout(&iq, 10) == Q_TIMEOUT, "wrong timeout return");
}
ROMCONST struct testcase testqueues1 = {
"Queues, input queues",
queues1_setup,
NULL,
queues1_execute
};
/**
* @page test_queues_002 Output Queues functionality and APIs
*
* <h2>Description</h2>
* This test case tests sysnchronos and asynchronous operations on an
* @p OutputQueue object including timeouts. The queue state must remain
* consistent through the whole test.
*/
static void queues2_setup(void) {
chOQInit(&oq, wa[0], TEST_QUEUES_SIZE, notify, NULL);
}
static msg_t thread2(void *p) {
(void)p;
chOQPutTimeout(&oq, 0, MS2ST(200));
return 0;
}
static void queues2_execute(void) {
unsigned i;
size_t n;
/* Initial empty state */
test_assert_lock(1, chOQIsEmptyI(&oq), "not empty");
/* Queue filling */
for (i = 0; i < TEST_QUEUES_SIZE; i++)
chOQPut(&oq, 'A' + i);
test_assert_lock(2, chOQIsFullI(&oq), "still has space");
/* Queue emptying */
for (i = 0; i < TEST_QUEUES_SIZE; i++) {
char c;
chSysLock();
c = chOQGetI(&oq);
chSysUnlock();
test_emit_token(c);
}
test_assert_lock(3, chOQIsEmptyI(&oq), "still full");
test_assert_sequence(4, "ABCD");
test_assert_lock(5, chOQGetI(&oq) == Q_EMPTY, "failed to report Q_EMPTY");
/* Writing the whole thing */
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size");
test_assert_lock(7, chOQIsFullI(&oq), "not full");
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread2, NULL);
test_assert_lock(8, chOQGetFullI(&oq) == TEST_QUEUES_SIZE, "not empty");
test_wait_threads();
/* Testing reset */
chSysLock();
chOQResetI(&oq);
chSysUnlock();
test_assert_lock(9, chOQGetFullI(&oq) == 0, "still full");
/* Partial writes */
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
test_assert(10, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
test_assert(11, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
test_assert_lock(12, chOQIsFullI(&oq), "not full");
/* Timeout */
test_assert(13, chOQPutTimeout(&oq, 0, 10) == Q_TIMEOUT, "wrong timeout return");
}
ROMCONST struct testcase testqueues2 = {
"Queues, output queues",
queues2_setup,
NULL,
queues2_execute
};
#endif /* CH_USE_QUEUES */
/**
* @brief Test sequence for queues.
*/
ROMCONST struct testcase * ROMCONST patternqueues[] = {
#if CH_USE_QUEUES || defined(__DOXYGEN__)
&testqueues1,
&testqueues2,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTQUEUES_H_
#define _TESTQUEUES_H_
extern ROMCONST struct testcase * ROMCONST patternqueues[];
#endif /* _TESTQUEUES_H_ */

View File

@ -0,0 +1,303 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_sem Semaphores test
*
* File: @ref testsem.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref semaphores subsystem.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the @ref semaphores code.
*
* <h2>Preconditions</h2>
* The module requires the following kernel options:
* - @p CH_USE_SEMAPHORES
* .
* In case some of the required options are not enabled then some or all tests
* may be skipped.
*
* <h2>Test Cases</h2>
* - @subpage test_sem_001
* - @subpage test_sem_002
* - @subpage test_sem_003
* - @subpage test_sem_004
* .
* @file testsem.c
* @brief Semaphores test source file
* @file testsem.h
* @brief Semaphores test header file
*/
#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
#define ALLOWED_DELAY MS2ST(5)
/*
* Note, the static initializers are not really required because the
* variables are explicitly initialized in each test case. It is done in order
* to test the macros.
*/
static SEMAPHORE_DECL(sem1, 0);
/**
* @page test_sem_001 Enqueuing test
*
* <h2>Description</h2>
* Five threads with randomized priorities are enqueued to a semaphore then
* awakened one at time.<br>
* The test expects that the threads reach their goal in FIFO order or
* priority order depending on the CH_USE_SEMAPHORES_PRIORITY configuration
* setting.
*/
static void sem1_setup(void) {
chSemInit(&sem1, 0);
}
static msg_t thread1(void *p) {
chSemWait(&sem1);
test_emit_token(*(char *)p);
return 0;
}
static void sem1_execute(void) {
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+5, thread1, "A");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()+1, thread1, "B");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()+3, thread1, "C");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()+4, thread1, "D");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()+2, thread1, "E");
chSemSignal(&sem1);
chSemSignal(&sem1);
chSemSignal(&sem1);
chSemSignal(&sem1);
chSemSignal(&sem1);
test_wait_threads();
#if CH_USE_SEMAPHORES_PRIORITY
test_assert_sequence(1, "ADCEB");
#else
test_assert_sequence(1, "ABCDE");
#endif
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+5, thread1, "A");
chSysLock();
chSemAddCounterI(&sem1, 2);
chSchRescheduleS();
chSysUnlock();
test_wait_threads();
test_assert(2, chSemGetCounterI(&sem1) == 1, "invalid counter");
}
ROMCONST struct testcase testsem1 = {
"Semaphores, enqueuing",
sem1_setup,
NULL,
sem1_execute
};
/**
* @page test_sem_002 Timeout test
*
* <h2>Description</h2>
* The three possible semaphore waiting modes (do not wait, wait with timeout,
* wait without timeout) are explored.<br>
* The test expects that the semaphore wait function returns the correct value
* in each of the above scenario and that the semaphore structure status is
* correct after each operation.
*/
static void sem2_setup(void) {
chSemInit(&sem1, 0);
}
static msg_t thread2(void *p) {
(void)p;
chThdSleepMilliseconds(50);
chSysLock();
chSemSignalI(&sem1); /* For coverage reasons */
chSchRescheduleS();
chSysUnlock();
return 0;
}
static void sem2_execute(void) {
int i;
systime_t target_time;
msg_t msg;
/*
* Testing special case TIME_IMMEDIATE.
*/
msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
test_assert(1, msg == RDY_TIMEOUT, "wrong wake-up message");
test_assert(2, isempty(&sem1.s_queue), "queue not empty");
test_assert(3, sem1.s_cnt == 0, "counter not zero");
/*
* Testing not timeout condition.
*/
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
thread2, 0);
msg = chSemWaitTimeout(&sem1, MS2ST(500));
test_wait_threads();
test_assert(4, msg == RDY_OK, "wrong wake-up message");
test_assert(5, isempty(&sem1.s_queue), "queue not empty");
test_assert(6, sem1.s_cnt == 0, "counter not zero");
/*
* Testing timeout condition.
*/
test_wait_tick();
target_time = chTimeNow() + MS2ST(5 * 500);
for (i = 0; i < 5; i++) {
test_emit_token('A' + i);
msg = chSemWaitTimeout(&sem1, MS2ST(500));
test_assert(7, msg == RDY_TIMEOUT, "wrong wake-up message");
test_assert(8, isempty(&sem1.s_queue), "queue not empty");
test_assert(9, sem1.s_cnt == 0, "counter not zero");
}
test_assert_sequence(10, "ABCDE");
test_assert_time_window(11, target_time, target_time + ALLOWED_DELAY);
}
ROMCONST struct testcase testsem2 = {
"Semaphores, timeout",
sem2_setup,
NULL,
sem2_execute
};
#if CH_USE_SEMSW || defined(__DOXYGEN__)
/**
* @page test_sem_003 Atomic signal-wait test
*
* <h2>Description</h2>
* This test case explicitly addresses the @p chSemWaitSignal() function. A
* thread is created that performs a wait and a signal operations.
* The tester thread is awakened from an atomic wait/signal operation.<br>
* The test expects that the semaphore wait function returns the correct value
* in each of the above scenario and that the semaphore structure status is
* correct after each operation.
*/
static void sem3_setup(void) {
chSemInit(&sem1, 0);
}
static msg_t thread3(void *p) {
(void)p;
chSemWait(&sem1);
chSemSignal(&sem1);
return 0;
}
static void sem3_execute(void) {
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread3, 0);
chSemSignalWait(&sem1, &sem1);
test_assert(1, isempty(&sem1.s_queue), "queue not empty");
test_assert(2, sem1.s_cnt == 0, "counter not zero");
chSemSignalWait(&sem1, &sem1);
test_assert(3, isempty(&sem1.s_queue), "queue not empty");
test_assert(4, sem1.s_cnt == 0, "counter not zero");
}
ROMCONST struct testcase testsem3 = {
"Semaphores, atomic signal-wait",
sem3_setup,
NULL,
sem3_execute
};
#endif /* CH_USE_SEMSW */
/**
* @page test_sem_004 Binary Wait and Signal
*
* <h2>Description</h2>
* This test case tests the binary semaphores functionality. The test both
* checks the binary semaphore status and the expected status of the underlying
* counting semaphore.
*/
static msg_t thread4(void *p) {
chBSemSignal((BinarySemaphore *)p);
return 0;
}
static void sem4_execute(void) {
BinarySemaphore bsem;
/* Creates a taken binary semaphore.*/
chBSemInit(&bsem, TRUE);
chBSemReset(&bsem, TRUE);
test_assert(1, chBSemGetStateI(&bsem) == TRUE, "not taken");
/* Starts a signaler thread at a lower priority.*/
threads[0] = chThdCreateStatic(wa[0], WA_SIZE,
chThdGetPriority()-1, thread4, &bsem);
/* Waits to be signaled.*/
chBSemWait(&bsem);
/* The binary semaphore is expected to be taken.*/
test_assert(2, chBSemGetStateI(&bsem) == TRUE, "not taken");
/* Releasing it, check both the binary semaphore state and the underlying
counter semaphore state..*/
chBSemSignal(&bsem);
test_assert(3, chBSemGetStateI(&bsem) == FALSE, "still taken");
test_assert(4, chSemGetCounterI(&bsem.bs_sem) == 1, "unexpected counter");
/* Checking signaling overflow, the counter must not go beyond 1.*/
chBSemSignal(&bsem);
test_assert(3, chBSemGetStateI(&bsem) == FALSE, "taken");
test_assert(5, chSemGetCounterI(&bsem.bs_sem) == 1, "unexpected counter");
}
ROMCONST struct testcase testsem4 = {
"Binary Semaphores, functionality",
NULL,
NULL,
sem4_execute
};
#endif /* CH_USE_SEMAPHORES */
/**
* @brief Test sequence for semaphores.
*/
ROMCONST struct testcase * ROMCONST patternsem[] = {
#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
&testsem1,
&testsem2,
#if CH_USE_SEMSW || defined(__DOXYGEN__)
&testsem3,
#endif
&testsem4,
#endif
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTSEM_H_
#define _TESTSEM_H_
extern ROMCONST struct testcase * ROMCONST patternsem[];
#endif /* _TESTSEM_H_ */

View File

@ -0,0 +1,231 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "test.h"
/**
* @page test_threads Threads and Scheduler test
*
* File: @ref testthd.c
*
* <h2>Description</h2>
* This module implements the test sequence for the @ref scheduler,
* @ref threads and @ref time subsystems.<br>
* Note that the tests on those subsystems are formally required but most of
* their functionality is already demonstrated because the test suite itself
* depends on them, anyway double check is good.
*
* <h2>Objective</h2>
* Objective of the test module is to cover 100% of the subsystems code.
*
* <h2>Preconditions</h2>
* None.
*
* <h2>Test Cases</h2>
* - @subpage test_threads_001
* - @subpage test_threads_002
* - @subpage test_threads_003
* - @subpage test_threads_004
* .
* @file testthd.c
* @brief Threads and Scheduler test source file
* @file testthd.h
* @brief Threads and Scheduler test header file
*/
/**
* @page test_threads_001 Ready List functionality #1
*
* <h2>Description</h2>
* Five threads, with increasing priority, are enqueued in the ready list
* and atomically executed.<br>
* The test expects the threads to perform their operations in increasing
* priority order regardless of the initial order.
*/
static msg_t thread(void *p) {
test_emit_token(*(char *)p);
return 0;
}
static void thd1_execute(void) {
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-5, thread, "E");
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-4, thread, "D");
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-3, thread, "C");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-2, thread, "B");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-1, thread, "A");
test_wait_threads();
test_assert_sequence(1, "ABCDE");
}
ROMCONST struct testcase testthd1 = {
"Threads, enqueuing test #1",
NULL,
NULL,
thd1_execute
};
/**
* @page test_threads_002 Ready List functionality #2
*
* <h2>Description</h2>
* Five threads, with pseudo-random priority, are enqueued in the ready list
* and atomically executed.<br>
* The test expects the threads to perform their operations in increasing
* priority order regardless of the initial order.
*/
static void thd2_execute(void) {
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-4, thread, "D");
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-5, thread, "E");
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-1, thread, "A");
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-2, thread, "B");
/* Done this way for coverage of chThdCreateI() and chThdResume().*/
chSysLock();
threads[2] = chThdCreateI(wa[2], WA_SIZE, chThdGetPriority()-3, thread, "C");
chSysUnlock();
chThdResume(threads[2]);
test_wait_threads();
test_assert_sequence(1, "ABCDE");
}
ROMCONST struct testcase testthd2 = {
"Threads, enqueuing test #2",
NULL,
NULL,
thd2_execute
};
/**
* @page test_threads_003 Threads priority change test
*
* <h2>Description</h2>
* A series of priority changes are performed on the current thread in order
* to verify that the priority change happens as expected.<br>
* If the @p CH_USE_MUTEXES option is enabled then the priority changes are
* also tested under priority inheritance boosted priority state.
*/
static void thd3_execute(void) {
tprio_t prio, p1;
prio = chThdGetPriority();
p1 = chThdSetPriority(prio + 1);
test_assert(1, p1 == prio,
"unexpected returned priority level");
test_assert(2, chThdGetPriority() == prio + 1,
"unexpected priority level");
p1 = chThdSetPriority(p1);
test_assert(3, p1 == prio + 1,
"unexpected returned priority level");
test_assert(4, chThdGetPriority() == prio,
"unexpected priority level");
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/* Simulates a priority boost situation (p_prio > p_realprio).*/
chSysLock();
chThdSelf()->p_prio += 2;
chSysUnlock();
test_assert(5, chThdGetPriority() == prio + 2,
"unexpected priority level");
/* Tries to raise but below the boost level. */
p1 = chThdSetPriority(prio + 1);
test_assert(6, p1 == prio,
"unexpected returned priority level");
test_assert(7, chThdSelf()->p_prio == prio + 2,
"unexpected priority level");
test_assert(8, chThdSelf()->p_realprio == prio + 1,
"unexpected returned real priority level");
/* Tries to raise above the boost level. */
p1 = chThdSetPriority(prio + 3);
test_assert(9, p1 == prio + 1,
"unexpected returned priority level");
test_assert(10, chThdSelf()->p_prio == prio + 3,
"unexpected priority level");
test_assert(11, chThdSelf()->p_realprio == prio + 3,
"unexpected real priority level");
chSysLock();
chThdSelf()->p_prio = prio;
chThdSelf()->p_realprio = prio;
chSysUnlock();
#endif
}
ROMCONST struct testcase testthd3 = {
"Threads, priority change",
NULL,
NULL,
thd3_execute
};
/**
* @page test_threads_004 Threads delays test
*
* <h2>Description</h2>
* Delay APIs and associated macros are tested, the invoking thread is verified
* to wake up at the exact expected time.
*/
static void thd4_execute(void) {
systime_t time;
test_wait_tick();
/* Timeouts in microseconds.*/
time = chTimeNow();
chThdSleepMicroseconds(100000);
test_assert_time_window(1, time + US2ST(100000), time + US2ST(100000) + 1);
/* Timeouts in milliseconds.*/
time = chTimeNow();
chThdSleepMilliseconds(100);
test_assert_time_window(2, time + MS2ST(100), time + MS2ST(100) + 1);
/* Timeouts in seconds.*/
time = chTimeNow();
chThdSleepSeconds(1);
test_assert_time_window(3, time + S2ST(1), time + S2ST(1) + 1);
/* Absolute timelines.*/
time = chTimeNow() + MS2ST(100);
chThdSleepUntil(time);
test_assert_time_window(4, time, time + 1);
}
ROMCONST struct testcase testthd4 = {
"Threads, delays",
NULL,
NULL,
thd4_execute
};
/**
* @brief Test sequence for threads.
*/
ROMCONST struct testcase * ROMCONST patternthd[] = {
&testthd1,
&testthd2,
&testthd3,
&testthd4,
NULL
};

View File

@ -0,0 +1,22 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _TESTRDY_H_
#define _TESTRDY_H_
extern ROMCONST struct testcase * ROMCONST patternthd[];
#endif /* _TESTRDY_H_ */