diff --git a/TODO b/TODO index ad47655bf40..d19ac0f067a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated March 14, 2017) +NuttX TODO List (Last updated March 26, 2017) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -14,7 +14,7 @@ nuttx/: (1) Memory Management (mm/) (0) Power Management (drivers/pm) (3) Signals (sched/signal, arch/) - (2) pthreads (sched/pthread) + (4) pthreads (sched/pthread) (0) Message Queues (sched/mqueue) (8) Kernel/Protected Build (3) C++ Support @@ -346,7 +346,7 @@ o Signals (sched/signal, arch/) Priority: Low. Even if there are only 31 usable signals, that is still a lot. o pthreads (sched/pthreads) - ^^^^^^^^^^^^^^^^^ + ^^^^^^^^^^^^^^^^^^^^^^^^^ Title: PTHREAD_PRIO_PROTECT Description: Extend pthread_mutexattr_setprotocol(). It should support @@ -448,6 +448,30 @@ o pthreads (sched/pthreads) Status: Not really open. This is just the way it is. Priority: Nothing additional is planned. + Title: PTHREAD FILES IN WRONG LOCATTION + Description: There are many pthread interface functions in files located in + sched/pthread. These should be moved from that location to + libc/pthread. In the flat build, this really does not matter, + but in the protected build that location means that system calls + are required to access the pthread interface functions. + Status: Open + Priority: Medium-low. Priority may be higher if system call overheade becomes + an issue. + + Title: ROBUST MUTEX ATTRIBUTE NOT SUPPORTED + Description: In NuttX, all mutexes are 'robust' in the sense that an attmpt + to lock a mutex will return EOWNDERDEAD if the holder of the + mutex has died. Unlocking of a mutex will fail if the caller + is not the holder of the mutex. + + POSIX, however, requires that there be a mutex attribute called + robust that determines which behavior is supported. non-robust + should be the default. NuttX does not support this attribute + and robust behavior is the default and only supported behavior. + Status: Open + Priority: Low. The non-robust behavior is dangerous and really should never + be used. + o Message Queues (sched/mqueue) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/arch/arm/src/lpc43xx/lpc43_allocateheap.c b/arch/arm/src/lpc43xx/lpc43_allocateheap.c index b7a947b668f..a6a73284d14 100644 --- a/arch/arm/src/lpc43xx/lpc43_allocateheap.c +++ b/arch/arm/src/lpc43xx/lpc43_allocateheap.c @@ -186,7 +186,7 @@ #ifndef CONFIG_LPC43_BOOT_SRAM /* Configuration A */ -/* CONFIG_RAM_START shoudl be set to the base of local SRAM, Bank 0. */ +/* CONFIG_RAM_START should be set to the base of local SRAM, Bank 0. */ # if CONFIG_RAM_START != LPC43_LOCSRAM_BANK0_BASE # error "CONFIG_RAM_START must be set to the base address of RAM bank 0" diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index eba911dfc56..97f097fc653 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -1450,7 +1450,7 @@ config STM32_STM32F33XX select STM32_HAVE_COMP2 select STM32_HAVE_COMP4 select STM32_HAVE_COMP6 - select STM32_HAVE_OPAMP + select STM32_HAVE_OPAMP2 select STM32_HAVE_CCM select STM32_HAVE_TIM1 select STM32_HAVE_TIM15 @@ -1907,18 +1907,34 @@ config STM32_HAVE_CAN2 bool default n +config STM32_HAVE_COMP1 + bool + default n + config STM32_HAVE_COMP2 bool default n +config STM32_HAVE_COMP3 + bool + default n + config STM32_HAVE_COMP4 bool default n +config STM32_HAVE_COMP5 + bool + default n + config STM32_HAVE_COMP6 bool default n +config STM32_HAVE_COMP7 + bool + default n + config STM32_HAVE_DAC1 bool default n @@ -1971,7 +1987,19 @@ config STM32_HAVE_I2SPLL bool default n -config STM32_HAVE_OPAMP +config STM32_HAVE_OPAMP1 + bool + default n + +config STM32_HAVE_OPAMP2 + bool + default n + +config STM32_HAVE_OPAMP3 + bool + default n + +config STM32_HAVE_OPAMP4 bool default n @@ -2032,21 +2060,41 @@ config STM32_COMP default n depends on STM32_STM32L15XX +config STM32_COMP1 + bool "COMP1" + default n + depends on STM32_HAVE_COMP1 + config STM32_COMP2 bool "COMP2" default n depends on STM32_HAVE_COMP2 +config STM32_COMP3 + bool "COMP3" + default n + depends on STM32_HAVE_COMP3 + config STM32_COMP4 bool "COMP4" default n depends on STM32_HAVE_COMP4 +config STM32_COMP5 + bool "COMP5" + default n + depends on STM32_HAVE_COMP5 + config STM32_COMP6 bool "COMP6" default n depends on STM32_HAVE_COMP6 +config STM32_COMP7 + bool "COMP7" + default n + depends on STM32_HAVE_COMP6 + config STM32_BKP bool "BKP" default n @@ -2185,7 +2233,26 @@ config STM32_DMA2D config STM32_OPAMP bool "OPAMP" default n - depends on STM32_HAVE_OPAMP + +config STM32_OPAMP1 + bool "OPAMP1" + default n + depends on STM32_HAVE_OPAMP1 + +config STM32_OPAMP2 + bool "OPAMP2" + default n + depends on STM32_HAVE_OPAMP2 + +config STM32_OPAMP3 + bool "OPAMP3" + default n + depends on STM32_HAVE_OPAMP3 + +config STM32_OPAMP4 + bool "OPAMP4" + default n + depends on STM32_HAVE_OPAMP4 config STM32_OTGFS bool "OTG FS" diff --git a/arch/arm/src/stm32/stm32_comp.c b/arch/arm/src/stm32/stm32_comp.c index 548baa9b110..b580f853987 100644 --- a/arch/arm/src/stm32/stm32_comp.c +++ b/arch/arm/src/stm32/stm32_comp.c @@ -45,21 +45,25 @@ #include #include +#include +#include #include "chip.h" #include "stm32_gpio.h" #include "stm32_comp.h" -#ifdef CONFIG_STM32_COMP - /* Some COMP peripheral must be enabled */ -/* Up to 7 comparators in STM32F2 Series */ +/* Up to 7 comparators in STM32F3 Series */ #if defined(CONFIG_STM32_COMP1) || defined(CONFIG_STM32_COMP2) || \ defined(CONFIG_STM32_COMP3) || defined(CONFIG_STM32_COMP4) || \ defined(CONFIG_STM32_COMP5) || defined(CONFIG_STM32_COMP6) || \ defined(CONFIG_STM32_COMP7) +#ifndef CONFIG_STM32_SYSCFG +# error "SYSCFG clock enable must be set" +#endif + /* @TODO: support for STM32F30XX and STM32F37XX comparators */ #if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F33XX) || \ @@ -81,6 +85,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* COMP2 default configuration **********************************************/ #ifdef CONFIG_STM32_COMP2 @@ -145,6 +150,61 @@ * Private Types ****************************************************************************/ +/* This structure describes the configuration of one COMP device */ + +struct stm32_comp_s +{ + uint8_t blanking; /* Blanking source */ + uint8_t pol; /* Output polarity */ + uint8_t inm; /* Inverting input selection */ + uint8_t out; /* Comparator output */ + uint8_t lock; /* Comparator Lock */ + uint32_t csr; /* Control and status register */ +#ifndef CONFIG_STM32_STM32F33XX + uint8_t mode; /* Comparator mode */ + uint8_t hyst; /* Comparator hysteresis */ + /* @TODO: Window mode + INP selection */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* COMP Register access */ + +static inline void comp_modify_csr(FAR struct stm32_comp_s *priv, + uint32_t clearbits, uint32_t setbits); +static inline uint32_t comp_getreg_csr(FAR struct stm32_comp_s *priv); +static inline void comp_putreg_csr(FAR struct stm32_comp_s *priv, + uint32_t value); +static bool stm32_complock_get(FAR struct stm32_comp_s *priv); +static int stm32_complock(FAR struct stm32_comp_s *priv, bool lock); + +/* COMP Driver Methods */ + +static void comp_shutdown(FAR struct comp_dev_s *dev); +static int comp_setup(FAR struct comp_dev_s *dev); +static int comp_read(FAR struct comp_dev_s *dev); +static int comp_ioctl(FAR struct comp_dev_s *dev, int cmd, unsigned long arg); + +/* Initialization */ + +static int stm32_compconfig(FAR struct stm32_comp_s *priv); +static int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct comp_ops_s g_compops = +{ + .ao_shutdown = comp_shutdown, + .ao_setup = comp_setup, + .ao_read = comp_read, + .ao_ioctl = comp_ioctl, +}; + #ifdef CONFIG_STM32_COMP1 static struct stm32_comp_s g_comp1priv = { @@ -159,6 +219,12 @@ static struct stm32_comp_s g_comp1priv = .hyst = COMP1_HYST, #endif }; + +static struct comp_dev_s g_comp1dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp1priv, +}; #endif #ifdef CONFIG_STM32_COMP2 @@ -175,6 +241,12 @@ static struct stm32_comp_s g_comp2priv = .hyst = COMP2_HYST, #endif }; + +static struct comp_dev_s g_comp2dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp2priv, +}; #endif #ifdef CONFIG_STM32_COMP3 @@ -187,10 +259,16 @@ static struct stm32_comp_s g_comp3priv = .lock = COMP3_LOCK, .csr = STM32_COMP3_CSR, #ifndef CONFIG_STM32_STM32F33XX - .mode = COMP3_MODE, - .hyst = COMP3_HYST, + .mode = COMP3_MODE, + .hyst = COMP3_HYST, #endif }; + +static struct comp_dev_s g_comp3dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp3priv, +}; #endif #ifdef CONFIG_STM32_COMP4 @@ -207,6 +285,12 @@ static struct stm32_comp_s g_comp4priv = .hyst = COMP4_HYST, #endif }; + +static struct comp_dev_s g_comp4dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp4priv, +}; #endif #ifdef CONFIG_STM32_COMP5 @@ -223,6 +307,12 @@ static struct stm32_comp_s g_comp5priv = .hyst = COMP5_HYST, #endif }; + +static struct comp_dev_s g_comp5dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp5priv, +}; #endif #ifdef CONFIG_STM32_COMP6 @@ -239,6 +329,12 @@ static struct stm32_comp_s g_comp6priv = .hyst = COMP6_HYST, #endif }; + +static struct comp_dev_s g_comp6dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp6priv, +}; #endif #ifdef CONFIG_STM32_COMP7 @@ -255,19 +351,14 @@ static struct stm32_comp_s g_comp7priv = .hyst = COMP7_HYST, #endif }; + +static struct comp_dev_s g_comp7dev = +{ + .ad_ops = &g_compops, + .ad_priv = &g_comp7priv, +}; #endif -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static inline void comp_modify_csr(FAR struct stm32_comp_s *priv, - uint32_t clearbits, uint32_t setbits); -static inline uint32_t comp_getreg_csr(FAR struct stm32_comp_s *priv); -static inline void comp_putreg_csr(FAR struct stm32_comp_s *priv, - uint32_t value); -static bool stm32_complock_get(FAR struct stm32_comp_s *priv); - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -360,13 +451,52 @@ static bool stm32_complock_get(FAR struct stm32_comp_s *priv) regval = comp_getreg_csr(priv); - return ((regval & COMP_CSR_LOCK == 0) ? false : true); + return (((regval & COMP_CSR_LOCK) == 0) ? false : true); } /**************************************************************************** - * Public Functions + * Name: stm32_complock + * + * Description: + * Lock comparator CSR register + * + * Input Parameters: + * priv - A reference to the COMP structure + * enable - lock flag + * + * Returned Value: + * 0 on success, a negated errno value on failure + * ****************************************************************************/ +static int stm32_complock(FAR struct stm32_comp_s *priv, bool lock) +{ + bool current; + + current = stm32_complock_get(priv); + + if (current) + { + if (lock == false) + { + aerr("ERROR: COMP LOCK can be cleared only by a system reset\n"); + + return -EPERM; + } + } + else + { + if (lock == true) + { + comp_modify_csr(priv, 0, COMP_CSR_LOCK); + + priv->lock = COMP_LOCK_RO; + } + } + + return OK; +} + /**************************************************************************** * Name: stm32_compconfig * @@ -383,9 +513,9 @@ static bool stm32_complock_get(FAR struct stm32_comp_s *priv) * ****************************************************************************/ -int stm32_compconfig(FAR struct stm32_comp_s *priv) +static int stm32_compconfig(FAR struct stm32_comp_s *priv) { - uint32_t regval; + uint32_t regval = 0; int index; /* Get comparator index */ @@ -665,98 +795,6 @@ int stm32_compconfig(FAR struct stm32_comp_s *priv) return OK; } -/**************************************************************************** - * Name: stm32_compinitialize - * - * Description: - * Initialize the COMP. - * - * Input Parameters: - * intf - The COMP interface number. - * - * Returned Value: - * Valid COMP device structure reference on succcess; a NULL on failure. - * - * Assumptions: - * 1. Clock to the COMP block has enabled, - * 2. Board-specific logic has already configured - * - ****************************************************************************/ - -FAR struct stm32_comp_s* stm32_compinitialize(int intf) -{ - FAR struct stm32_comp_s *priv; - int ret; - - switch (intf) - { -#ifdef CONFIG_STM32_COMP1 - case 1: - ainfo("COMP1 selected\n"); - priv = &g_comp1priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP2 - case 2: - ainfo("COMP2 selected\n"); - priv = &g_comp2priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP3 - case 3: - ainfo("COMP3 selected\n"); - priv = &g_comp3priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP4 - case 4: - ainfo("COMP4 selected\n"); - priv = &g_comp4priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP5 - case 5: - ainfo("COMP5 selected\n"); - priv = &g_comp5priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP6 - case 6: - ainfo("COMP6 selected\n"); - priv = &g_comp6priv; - break; -#endif - -#ifdef CONFIG_STM32_COMP7 - case 7: - ainfo("COMP7 selected\n"); - priv = &g_comp7priv; - break; -#endif - - default: - aerr("ERROR: No COMP interface defined\n"); - return NULL; - } - - /* Configure selected comparator */ - - ret = stm32_compconfig(priv); - if (ret < 0) - { - aerr("ERROR: Failed to initialize COMP%d: %d\n", intf, ret); - errno = -ret; - return NULL; - } - - return priv; -} - /**************************************************************************** * Name: stm32_compenable * @@ -772,7 +810,7 @@ FAR struct stm32_comp_s* stm32_compinitialize(int intf) * ****************************************************************************/ -int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable) +static int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable) { bool lock; @@ -792,13 +830,13 @@ int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable) { /* Enable the COMP */ - comp_modify_csr(priv, COMP_CSR_COMPEN, 0); + comp_modify_csr(priv, 0, COMP_CSR_COMPEN); } else { /* Disable the COMP */ - comp_modify_csr(priv, 0, COMP_CSR_COMPEN); + comp_modify_csr(priv, COMP_CSR_COMPEN, 0); } } @@ -806,46 +844,190 @@ int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable) } /**************************************************************************** - * Name: stm32_complock + * Name: adc_setup * * Description: - * Lock comparator CSR register + * Configure the COMP. This method is called the first time that the COMP + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching COMP interrupts. + * Interrupts are all disabled upon return. * * Input Parameters: - * priv - A reference to the COMP structure - * enable - lock flag * * Returned Value: - * 0 on success, a negated errno value on failure * ****************************************************************************/ -int stm32_complock(FAR struct stm32_comp_s *priv, bool lock) +static int comp_setup(FAR struct comp_dev_s *dev) { - bool current; +#warning "Missing logic" + return OK; +} - current = stm32_complock_get(priv); +/**************************************************************************** + * Name: comp_shutdown + * + * Description: + * Disable the COMP. This method is called when the COMP device is closed. + * This method reverses the operation the setup method. + * Works only if COMP device is not locked. + * + * Input Parameters: + * + * Returned Value: + * None + * + ****************************************************************************/ - if (current) +static void comp_shutdown(FAR struct comp_dev_s *dev) +{ +#warning "Missing logic" +} + +/**************************************************************************** + * Name: comp_read + * + * Description: + * Get the COMP output state. + * + * Input Parameters: + * + * Returned Value: + * 0 if output is low (non-inverting input below inverting input), + * 1 if output is high (non inverting input above inverting input). + * + ****************************************************************************/ + +static int comp_read(FAR struct comp_dev_s *dev) +{ + FAR struct stm32_comp_s *priv; + uint32_t regval; + + priv = dev->ad_priv; + regval = comp_getreg_csr(priv); + + return (((regval & COMP_CSR_OUT) == 0) ? 0 : 1); +} + +/**************************************************************************** + * Name: comp_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int comp_ioctl(FAR struct comp_dev_s *dev, int cmd, unsigned long arg) +{ +#warning "Missing logic" + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_compinitialize + * + * Description: + * Initialize the COMP. + * + * Input Parameters: + * intf - The COMP interface number. + * + * Returned Value: + * Valid COMP device structure reference on succcess; a NULL on failure. + * + * Assumptions: + * 1. Clock to the COMP block has enabled, + * 2. Board-specific logic has already configured + * + ****************************************************************************/ + +FAR struct comp_dev_s* stm32_compinitialize(int intf) +{ + FAR struct comp_dev_s *dev; + FAR struct stm32_comp_s *comp; + int ret; + + switch (intf) { - if (lock == false) - { - aerr("ERROR: COMP LOCK can be cleared only by a system reset\n"); +#ifdef CONFIG_STM32_COMP1 + case 1: + ainfo("COMP1 selected\n"); + dev = &g_comp1dev; + break; +#endif - return -EPERM; - } - } - else - { - if (lock == true) - { - comp_modify_csr(priv, COMP_CSR_LOCK, 0); +#ifdef CONFIG_STM32_COMP2 + case 2: + ainfo("COMP2 selected\n"); + dev = &g_comp2dev; + break; +#endif - priv->lock = COMP_LOCK_RO; - } +#ifdef CONFIG_STM32_COMP3 + case 3: + ainfo("COMP3 selected\n"); + dev = &g_comp3dev; + break; +#endif + +#ifdef CONFIG_STM32_COMP4 + case 4: + ainfo("COMP4 selected\n"); + dev = &g_comp4dev; + break; +#endif + +#ifdef CONFIG_STM32_COMP5 + case 5: + ainfo("COMP5 selected\n"); + dev = &g_comp5dev; + break; +#endif + +#ifdef CONFIG_STM32_COMP6 + case 6: + ainfo("COMP6 selected\n"); + dev = &g_comp6dev; + break; +#endif + +#ifdef CONFIG_STM32_COMP7 + case 7: + ainfo("COMP7 selected\n"); + dev = &g_comp7dev; + break; +#endif + + default: + aerr("ERROR: No COMP interface defined\n"); + return NULL; } - return OK; + /* Configure selected comparator */ + + comp = dev->ad_priv; + + ret = stm32_compconfig(comp); + if (ret < 0) + { + aerr("ERROR: Failed to initialize COMP%d: %d\n", intf, ret); + errno = -ret; + return NULL; + } + + return dev; } #endif /* CONFIG_STM32_STM32F30XX || CONFIG_STM32_STM32F33XX || @@ -853,5 +1035,3 @@ int stm32_complock(FAR struct stm32_comp_s *priv, bool lock) #endif /* CONFIG_STM32_COMP2 || CONFIG_STM32_COMP4 || * CONFIG_STM32_COMP6 */ - -#endif /* CONFIG_STM32_COMP */ diff --git a/arch/arm/src/stm32/stm32_comp.h b/arch/arm/src/stm32/stm32_comp.h index c703689d171..16a0ad69713 100644 --- a/arch/arm/src/stm32/stm32_comp.h +++ b/arch/arm/src/stm32/stm32_comp.h @@ -60,7 +60,7 @@ #define COMP_POL_DEFAULT COMP_POL_NONINVERT /* Output is not inverted */ #define COMP_INM_DEFAULT COMP_INMSEL_1P4VREF /* 1/4 of Vrefint as INM */ #define COMP_OUTSEL_DEFAULT COMP_OUTSEL_NOSEL /* Output not selected */ -#define COMP_LOCK_DEFAULT COMP_LOCK_RO /* Do not lock CSR register */ +#define COMP_LOCK_DEFAULT COMP_LOCK_RW /* Do not lock CSR register */ #ifndef CONFIG_STM32_STM32F33XX #define COMP_MODE_DEFAULT @@ -172,23 +172,6 @@ enum stm32_comp_winmode_e #endif -/* Comparator configuration ***********************************************************/ - -struct stm32_comp_s -{ - uint8_t blanking; /* Blanking source */ - uint8_t pol; /* Output polarity */ - uint8_t inm; /* Inverting input selection */ - uint8_t out; /* Comparator output */ - uint8_t lock; /* Comparator Lock */ - uint32_t csr; /* Control and status register */ -#ifndef CONFIG_STM32_STM32F33XX - uint8_t mode; /* Comparator mode */ - uint8_t hyst; /* Comparator hysteresis */ - /* @TODO: Window mode + INP selection */ -#endif -}; - /************************************************************************************ * Public Function Prototypes ************************************************************************************/ @@ -202,22 +185,6 @@ extern "C" #define EXTERN extern #endif -/**************************************************************************** -* Name: stm32_compconfig -* -* Description: -* Configure comparator and used I/Os -* -* Input Parameters: -* priv - A reference to the COMP structure -* -* Returned Value: -* 0 on success, a negated errno value on failure -* -****************************************************************************/ - -int stm32_compconfig(FAR struct stm32_comp_s *priv); - /**************************************************************************** * Name: stm32_compinitialize * @@ -236,41 +203,7 @@ int stm32_compconfig(FAR struct stm32_comp_s *priv); * ****************************************************************************/ -FAR struct stm32_comp_s* stm32_compinitialize(int intf); - -/**************************************************************************** -* Name: stm32_compenable -* -* Description: -* Enable/disable comparator -* -* Input Parameters: -* priv - A reference to the COMP structure -* enable - enable/disable flag -* -* Returned Value: -* 0 on success, a negated errno value on failure -* -****************************************************************************/ - -int stm32_compenable(FAR struct stm32_comp_s *priv, bool enable); - -/**************************************************************************** -* Name: stm32_complock -* -* Description: -* Lock comparator CSR register -* -* Input Parameters: -* priv - A reference to the COMP structure -* enable - lock flag -* -* Returned Value: -* 0 on success, a negated errno value on failure -* -****************************************************************************/ - -int stm32_complock(FAR struct stm32_comp_s *priv, bool lock); +FAR struct comp_dev_s* stm32_compinitialize(int intf); #undef EXTERN #ifdef __cplusplus diff --git a/configs/clicker2-stm32/nsh/defconfig b/configs/clicker2-stm32/nsh/defconfig index 1b5c06b7d3f..d13af3965b8 100644 --- a/configs/clicker2-stm32/nsh/defconfig +++ b/configs/clicker2-stm32/nsh/defconfig @@ -625,9 +625,9 @@ CONFIG_USEC_PER_TICK=10000 # CONFIG_CLOCK_MONOTONIC is not set CONFIG_ARCH_HAVE_TIMEKEEPING=y # CONFIG_JULIAN_TIME is not set -CONFIG_START_YEAR=2013 -CONFIG_START_MONTH=1 -CONFIG_START_DAY=1 +CONFIG_START_YEAR=2017 +CONFIG_START_MONTH=3 +CONFIG_START_DAY=25 CONFIG_MAX_WDOGPARMS=2 CONFIG_PREALLOC_WDOGS=8 CONFIG_WDOG_INTRESERVE=1 @@ -884,10 +884,7 @@ CONFIG_FS_WRITABLE=y # CONFIG_FS_NAMED_SEMAPHORES is not set CONFIG_FS_MQUEUE_MPATH="/var/mqueue" # CONFIG_FS_RAMMAP is not set -CONFIG_FS_FAT=y -CONFIG_FAT_LCNAMES=y -CONFIG_FAT_LFN=y -CONFIG_FAT_MAXFNAME=32 +# CONFIG_FS_FAT is not set # CONFIG_FS_FATTIME is not set # CONFIG_FAT_FORCE_INDIRECT is not set # CONFIG_FAT_DMAMEMORY is not set diff --git a/configs/nucleo-f334r8/src/stm32_comp.c b/configs/nucleo-f334r8/src/stm32_comp.c index 0f775e1f3dc..c6b8be8249c 100644 --- a/configs/nucleo-f334r8/src/stm32_comp.c +++ b/configs/nucleo-f334r8/src/stm32_comp.c @@ -44,7 +44,7 @@ #include #include -/* #include */ +#include #include "stm32.h" @@ -52,6 +52,20 @@ defined(CONFIG_STM32_COMP4) || \ defined(CONFIG_STM32_COMP6)) +#ifdef CONFIG_STM32_COMP2 +# if defined(CONFIG_STM32_COMP4) || defined(CONFIG_STM32_COMP6) +# error "Currently only one COMP device supported" +# endif +#elif CONFIG_STM32_COMP4 +# if defined(CONFIG_STM32_COMP2) || defined(CONFIG_STM32_COMP6) +# error "Currently only one COMP device supported" +# endif +#elif CONFIG_STM32_COMP6 +# if defined(CONFIG_STM32_COMP2) || defined(CONFIG_STM32_COMP4) +# error "Currently only one COMP device supported" +# endif +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -67,12 +81,13 @@ int stm32_comp_setup(void) { static bool initialized = false; - struct stm32_comp_s* comp = NULL; + struct comp_dev_s* comp = NULL; int ret; - UNUSED(ret); if (!initialized) { + /* Get the comparator interface */ + #ifdef CONFIG_STM32_COMP2 comp = stm32_compinitialize(2); if (comp == NULL) @@ -100,8 +115,7 @@ int stm32_comp_setup(void) } #endif -#if 0 - /* COMP driver not implemented yet */ + /* Register the comparator character driver at /dev/comp0 */ ret = comp_register("/dev/comp0", comp); if (ret < 0) @@ -109,7 +123,6 @@ int stm32_comp_setup(void) aerr("ERROR: comp_register failed: %d\n", ret); return ret; } -#endif initialized = true; } diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig index 20d99f8acb4..c9a2334361b 100644 --- a/drivers/analog/Kconfig +++ b/drivers/analog/Kconfig @@ -109,6 +109,12 @@ config PGA11X_MULTIPLE endif # if ADC_PGA11X endif # ADC +config COMP + bool "Analog Comparator" + default n + ---help--- + Select to enable support for Analog Comparators (COMPs). + config DAC bool "Digital-to-Analog Conversion" default n diff --git a/drivers/analog/Make.defs b/drivers/analog/Make.defs index 2d12a1695d1..fbcc369a4ce 100644 --- a/drivers/analog/Make.defs +++ b/drivers/analog/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # drivers/analog/Make.defs # -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. +# Copyright (C) 2011-2012, 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -50,6 +50,16 @@ ifeq ($(CONFIG_DAC_AD5410),y) endif endif +# Check for COMP devices + +ifeq ($(CONFIG_COMP),y) + +# Include the common COMP character driver + +CSRCS += comp.c + +endif + # Check for ADC devices ifeq ($(CONFIG_ADC),y) @@ -86,6 +96,11 @@ ifeq ($(CONFIG_ADC),y) DEPPATH += --dep-path analog VPATH += :analog CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} +else +ifeq ($(CONFIG_COMP),y) + DEPPATH += --dep-path analog + VPATH += :analog + CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} +endif endif endif - diff --git a/drivers/analog/comp.c b/drivers/analog/comp.c new file mode 100644 index 00000000000..d2b95d77674 --- /dev/null +++ b/drivers/analog/comp.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * drivers/analog/comp.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int comp_open(FAR struct file *filep); +static int comp_close(FAR struct file *filep); +static ssize_t comp_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int comp_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations comp_fops = +{ + comp_open, /* open */ + comp_close, /* close */ + comp_read, /* read */ + NULL, /* write */ + NULL, /* seek */ + comp_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , NULL /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: comp_open + * + * Description: + * This function is called whenever the COMP device is opened. + * + ****************************************************************************/ + +static int comp_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct comp_dev_s *dev = inode->i_private; + uint8_t tmp; + int ret = OK; + + /* If the port is the middle of closing, wait until the close is finished */ + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Increment the count of references to the device. If this the first + * time that the driver has been opened for this device, then initialize + * the device. + */ + + tmp = dev->ad_ocount + 1; + if (tmp == 0) + { + /* More than 255 opens; uint8_t overflows to zero */ + + ret = -EMFILE; + } + else + { + /* Check if this is the first time that the driver has been opened. */ + + if (tmp == 1) + { + /* Yes.. perform one time hardware initialization. */ + + irqstate_t flags = enter_critical_section(); + ret = dev->ad_ops->ao_setup(dev); + if (ret == OK) + { + /* Save the new open count on success */ + + dev->ad_ocount = tmp; + } + + leave_critical_section(flags); + } + } + + sem_post(&dev->ad_closesem); + } + + return ret; +} + +/**************************************************************************** + * Name: comp_close + * + * Description: + * This routine is called when the COMP device is closed. + * It waits for the last remaining data to be sent. + * + ****************************************************************************/ + +static int comp_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct comp_dev_s *dev = inode->i_private; + irqstate_t flags; + int ret = OK; + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + if (dev->ad_ocount > 1) + { + dev->ad_ocount--; + sem_post(&dev->ad_closesem); + } + else + { + /* There are no more references to the port */ + + dev->ad_ocount = 0; + + /* Free the IRQ and disable the COMP device */ + + flags = enter_critical_section(); /* Disable interrupts */ + dev->ad_ops->ao_shutdown(dev); /* Disable the COMP */ + leave_critical_section(flags); + + sem_post(&dev->ad_closesem); + } + } + + return ret; +} + +/**************************************************************************** + * Name: comp_read + ****************************************************************************/ + +static ssize_t comp_read(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct comp_dev_s *dev = inode->i_private; + int ret; + + ret = dev->ad_ops->ao_read(dev); + + buffer[0] = (uint8_t)ret; + + return 1; +} + +/**************************************************************************** + * Name: comp_ioctl +****************************************************************************/ + +static int comp_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct comp_dev_s *dev = inode->i_private; + int ret; + + ret = dev->ad_ops->ao_ioctl(dev, cmd, arg); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: comp_register + ****************************************************************************/ + +int comp_register(FAR const char *path, FAR struct comp_dev_s *dev) +{ + int ret; + + /* Initialize the COMP device structure */ + + dev->ad_ocount = 0; + + /* Initialize semaphores */ + + sem_init(&dev->ad_closesem, 0, 1); + + /* Register the COMP character driver */ + + ret = register_driver(path, &comp_fops, 0444, dev); + if (ret < 0) + { + sem_destroy(&dev->ad_closesem); + } + + return ret; +} diff --git a/include/errno.h b/include/errno.h index d6d4ec8e191..fd701d79cd4 100644 --- a/include/errno.h +++ b/include/errno.h @@ -156,7 +156,7 @@ #define ENOMEM_STR "Out of memory" #define EACCES 13 #define EACCES_STR "Permission denied" -#define EFAULT 14 +#define EFAULT 14 /* Linux errno extension */ #define EFAULT_STR "Bad address" #define ENOTBLK 15 #define ENOTBLK_STR "Block device required" @@ -198,53 +198,48 @@ #define EDOM_STR "Math argument out of domain of func" #define ERANGE 34 #define ERANGE_STR "Math result not representable" -#define EDEADLK 35 -#define EDEADLOCK EDEADLK -#define EDEADLK_STR "Resource deadlock would occur" -#define ENAMETOOLONG 36 -#define ENAMETOOLONG_STR "File name too long" -#define ENOLCK 37 -#define ENOLCK_STR "No record locks available" -#define ENOSYS 38 -#define ENOSYS_STR "Function not implemented" -#define ENOTEMPTY 39 -#define ENOTEMPTY_STR "Directory not empty" -#define ELOOP 40 -#define ELOOP_STR "Too many symbolic links encountered" -#define ENOMSG 42 +#define ENOMSG 35 #define ENOMSG_STR "No message of desired type" -#define EIDRM 43 +#define EIDRM 36 #define EIDRM_STR "Identifier removed" -#define ECHRNG 44 +#define ECHRNG 37 /* Linux errno extension */ #define ECHRNG_STR "Channel number out of range" -#define EL2NSYNC 45 +#define EL2NSYNC 38 /* Linux errno extension */ #define EL2NSYNC_STR "Level 2 not synchronized" -#define EL3HLT 46 +#define EL3HLT 39 /* Linux errno extension */ #define EL3HLT_STR "Level 3 halted" -#define EL3RST 47 +#define EL3RST 40 /* Linux errno extension */ #define EL3RST_STR "Level 3 reset" -#define ELNRNG 48 +#define ELNRNG 41 /* Linux errno extension */ #define ELNRNG_STR "Link number out of range" -#define EUNATCH 49 +#define EUNATCH 42 /* Linux errno extension */ #define EUNATCH_STR "Protocol driver not attached" -#define ENOCSI 50 +#define ENOCSI 43 /* Linux errno extension */ #define ENOCSI_STR "No CSI structure available" -#define EL2HLT 51 +#define EL2HLT 44 /* Linux errno extension */ #define EL2HLT_STR "Level 2 halted" -#define EBADE 52 +#define EDEADLK 45 +#define EDEADLK_STR "Resource deadlock would occur" +#define ENOLCK 46 +#define ENOLCK_STR "No record locks available" + +#define EBADE 50 /* Linux errno extension */ #define EBADE_STR "Invalid exchange" -#define EBADR 53 +#define EBADR 51 /* Linux errno extension */ #define EBADR_STR "Invalid request descriptor" -#define EXFULL 54 +#define EXFULL 52 /* Linux errno extension */ #define EXFULL_STR "Exchange full" -#define ENOANO 55 +#define ENOANO 53 /* Linux errno extension */ #define ENOANO_STR "No anode" -#define EBADRQC 56 +#define EBADRQC 54 /* Linux errno extension */ #define EBADRQC_STR "Invalid request code" -#define EBADSLT 57 +#define EBADSLT 55 /* Linux errno extension */ #define EBADSLT_STR "Invalid slot" -#define EBFONT 59 +#define EDEADLOCK 56 /* Linux errno extension */ +#define EDEADLOCK_STR "File locking deadlock error" +#define EBFONT 57 /* Linux errno extension */ #define EBFONT_STR "Bad font file format" + #define ENOSTR 60 #define ENOSTR_STR "Device not a stream" #define ENODATA 61 @@ -253,130 +248,148 @@ #define ETIME_STR "Timer expired" #define ENOSR 63 #define ENOSR_STR "Out of streams resources" -#define ENONET 64 +#define ENONET 64 /* Linux errno extension */ #define ENONET_STR "Machine is not on the network" -#define ENOPKG 65 +#define ENOPKG 65 /* Linux errno extension */ #define ENOPKG_STR "Package not installed" -#define EREMOTE 66 +#define EREMOTE 66 /* Linux errno extension */ #define EREMOTE_STR "Object is remote" #define ENOLINK 67 #define ENOLINK_STR "Link has been severed" -#define EADV 68 +#define EADV 68 /* Linux errno extension */ #define EADV_STR "Advertise error" -#define ESRMNT 69 +#define ESRMNT 69 /* Linux errno extension */ #define ESRMNT_STR "Srmount error" -#define ECOMM 70 +#define ECOMM 70 /* Linux errno extension */ #define ECOMM_STR "Communication error on send" #define EPROTO 71 #define EPROTO_STR "Protocol error" -#define EMULTIHOP 72 + +#define EMULTIHOP 74 #define EMULTIHOP_STR "Multihop attempted" -#define EDOTDOT 73 +#define ELBIN 75 /* Linux errno extension */ +#define ELBIN_STR "Inode is remote" +#define EDOTDOT 76 /* Linux errno extension */ #define EDOTDOT_STR "RFS specific error" -#define EBADMSG 74 +#define EBADMSG 77 #define EBADMSG_STR "Not a data message" -#define EOVERFLOW 75 -#define EOVERFLOW_STR "Value too large for defined data type" -#define ENOTUNIQ 76 + +#define EFTYPE 79 +#define EFTYPE_STR "Inappropriate file type or format" +#define ENOTUNIQ 80 /* Linux errno extension */ #define ENOTUNIQ_STR "Name not unique on network" -#define EBADFD 77 +#define EBADFD 81 /* Linux errno extension */ #define EBADFD_STR "File descriptor in bad state" -#define EREMCHG 78 +#define EREMCHG 82 /* Linux errno extension */ #define EREMCHG_STR "Remote address changed" -#define ELIBACC 79 +#define ELIBACC 83 /* Linux errno extension */ #define ELIBACC_STR "Can not access a needed shared library" -#define ELIBBAD 80 +#define ELIBBAD 84 /* Linux errno extension */ #define ELIBBAD_STR "Accessing a corrupted shared library" -#define ELIBSCN 81 +#define ELIBSCN 85 /* Linux errno extension */ #define ELIBSCN_STR ".lib section in a.out corrupted" -#define ELIBMAX 82 +#define ELIBMAX 86 /* Linux errno extension */ #define ELIBMAX_STR "Attempting to link in too many shared libraries" -#define ELIBEXEC 83 +#define ELIBEXEC 87 /* Linux errno extension */ #define ELIBEXEC_STR "Cannot exec a shared library directly" -#define EILSEQ 84 -#define EILSEQ_STR "Illegal byte sequence" -#define ERESTART 85 -#define ERESTART_STR "Interrupted system call should be restarted" -#define ESTRPIPE 86 -#define ESTRPIPE_STR "Streams pipe error" -#define EUSERS 87 -#define EUSERS_STR "Too many users" -#define ENOTSOCK 88 -#define ENOTSOCK_STR "Socket operation on non-socket" -#define EDESTADDRREQ 89 -#define EDESTADDRREQ_STR "Destination address required" -#define EMSGSIZE 90 -#define EMSGSIZE_STR "Message too long" -#define EPROTOTYPE 91 -#define EPROTOTYPE_STR "Protocol wrong type for socket" -#define ENOPROTOOPT 92 -#define ENOPROTOOPT_STR "Protocol not available" -#define EPROTONOSUPPORT 93 -#define EPROTONOSUPPORT_STR "Protocol not supported" -#define ESOCKTNOSUPPORT 94 -#define ESOCKTNOSUPPORT_STR "Socket type not supported" +#define ENOSYS 88 +#define ENOSYS_STR "Function not implemented" +#define ENMFILE 89 /* Cygwin */ +#define ENMFILE_STR "No more files" +#define ENOTEMPTY 90 +#define ENOTEMPTY_STR "Directory not empty" +#define ENAMETOOLONG 91 +#define ENAMETOOLONG_STR "File name too long" +#define ELOOP 92 +#define ELOOP_STR "Too many symbolic links encountered" + #define EOPNOTSUPP 95 #define EOPNOTSUPP_STR "Operation not supported on transport endpoint" #define EPFNOSUPPORT 96 #define EPFNOSUPPORT_STR "Protocol family not supported" -#define EAFNOSUPPORT 97 -#define EAFNOSUPPORT_STR "Address family not supported by protocol" -#define EADDRINUSE 98 -#define EADDRINUSE_STR "Address already in use" -#define EADDRNOTAVAIL 99 -#define EADDRNOTAVAIL_STR "Cannot assign requested address" -#define ENETDOWN 100 -#define ENETDOWN_STR "Network is down" -#define ENETUNREACH 101 -#define ENETUNREACH_STR "Network is unreachable" -#define ENETRESET 102 -#define ENETRESET_STR "Network dropped connection because of reset" -#define ECONNABORTED 103 -#define ECONNABORTED_STR "Software caused connection abort" + #define ECONNRESET 104 #define ECONNRESET_STR "Connection reset by peer" #define ENOBUFS 105 #define ENOBUFS_STR "No buffer space available" -#define EISCONN 106 -#define EISCONN_STR "Transport endpoint is already connected" -#define ENOTCONN 107 -#define ENOTCONN_STR "Transport endpoint is not connected" -#define ESHUTDOWN 108 +#define EAFNOSUPPORT 106 +#define EAFNOSUPPORT_STR "Address family not supported by protocol" +#define EPROTOTYPE 107 +#define EPROTOTYPE_STR "Protocol wrong type for socket" +#define ENOTSOCK 108 +#define ENOTSOCK_STR "Socket operation on non-socket" +#define ENOPROTOOPT 109 +#define ENOPROTOOPT_STR "Protocol not available" +#define ESHUTDOWN 110 /* Linux errno extension */ #define ESHUTDOWN_STR "Cannot send after transport endpoint shutdown" -#define ETOOMANYREFS 109 -#define ETOOMANYREFS_STR "Too many references: cannot splice" -#define ETIMEDOUT 110 -#define ETIMEDOUT_STR "Connection timed out" #define ECONNREFUSED 111 #define ECONNREFUSED_STR "Connection refused" -#define EHOSTDOWN 112 +#define EADDRINUSE 112 +#define EADDRINUSE_STR "Address already in use" +#define ECONNABORTED 113 +#define ECONNABORTED_STR "Software caused connection abort" +#define ENETUNREACH 114 +#define ENETUNREACH_STR "Network is unreachable" +#define ENETDOWN 115 +#define ENETDOWN_STR "Network is down" +#define ETIMEDOUT 116 +#define ETIMEDOUT_STR "Connection timed out" +#define EHOSTDOWN 117 #define EHOSTDOWN_STR "Host is down" -#define EHOSTUNREACH 113 +#define EHOSTUNREACH 118 #define EHOSTUNREACH_STR "No route to host" -#define EALREADY 114 -#define EALREADY_STR "Operation already in progress" -#define EINPROGRESS 115 +#define EINPROGRESS 119 #define EINPROGRESS_STR "Operation now in progress" -#define ESTALE 116 -#define ESTALE_STR "Stale NFS file handle" -#define EUCLEAN 117 -#define EUCLEAN_STR "Structure needs cleaning" -#define ENOTNAM 118 -#define ENOTNAM_STR "Not a XENIX named type file" -#define ENAVAIL 119 -#define ENAVAIL_STR "No XENIX semaphores available" -#define EISNAM 120 -#define EISNAM_STR "Is a named type file" -#define EREMOTEIO 121 -#define EREMOTEIO_STR "Remote I/O error" -#define EDQUOT 122 +#define EALREADY 120 +#define EALREADY_STR "Socket already connected" +#define EDESTADDRREQ 121 +#define EDESTADDRREQ_STR "Destination address required" +#define EMSGSIZE 122 +#define EMSGSIZE_STR "Message too long" +#define EPROTONOSUPPORT 123 +#define EPROTONOSUPPORT_STR "Protocol not supported" +#define ESOCKTNOSUPPORT 124 /* Linux errno extension */ +#define ESOCKTNOSUPPORT_STR "Socket type not supported" +#define EADDRNOTAVAIL 125 +#define EADDRNOTAVAIL_STR "Cannot assign requested address" +#define ENETRESET 126 +#define ENETRESET_STR "Network dropped connection because of reset" +#define EISCONN 127 +#define EISCONN_STR "Transport endpoint is already connected" +#define ENOTCONN 128 +#define ENOTCONN_STR "Transport endpoint is not connected" +#define ETOOMANYREFS 129 +#define ETOOMANYREFS_STR "Too many references: cannot splice" +#define EPROCLIM 130 +#define EPROCLIM_STR "Limit would be exceeded by attempted fork" +#define EUSERS 131 +#define EUSERS_STR "Too many users" +#define EDQUOT 132 #define EDQUOT_STR "Quota exceeded" -#define ENOMEDIUM 123 +#define ESTALE 133 +#define ESTALE_STR "Stale NFS file handle" +#define ENOTSUP 134 +#define ENOTSUP_STR "Not supported" +#define ENOMEDIUM 135 /* Linux errno extension */ #define ENOMEDIUM_STR "No medium found" -#define EMEDIUMTYPE 124 -#define EMEDIUMTYPE_STR "Wrong medium type" -#define ECANCELED 125 +#define ENOSHARE 136 /* Cygwin */ +#define ENOSHARE_STR "No such host or network path" +#define ECASECLASH 137 /* Cygwin */ +#define ECASECLASH_STR "Filename exists with different case" +#define EILSEQ 138 +#define EILSEQ_STR "Illegal byte sequence" +#define EOVERFLOW 139 +#define EOVERFLOW_STR "Value too large for defined data type" +#define ECANCELED 140 #define ECANCELED_STR "Operation cancelled" +#define ENOTRECOVERABLE 141 +#define ENOTRECOVERABLE_STR "State not recoverable" +#define EOWNERDEAD 142 +#define EOWNERDEAD_STR "Previous owner died" +#define ESTRPIPE 143 /* Linux errno extension */ +#define ESTRPIPE_STR "Streams pipe error" + +#define __ELASTERROR 2000 /* Users can add values starting here */ /**************************************************************************** * Public Type Definitions diff --git a/include/nuttx/analog/comp.h b/include/nuttx/analog/comp.h new file mode 100644 index 00000000000..9934d831eaf --- /dev/null +++ b/include/nuttx/analog/comp.h @@ -0,0 +1,113 @@ +/************************************************************************************ + * include/nuttx/analog/comp.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __INCLUDE_NUTTX_ANALOG_COMP_H +#define __INCLUDE_NUTTX_ANALOG_COMP_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +struct comp_dev_s; +struct comp_ops_s +{ + /* Configure the COMP. This method is called the first time that the COMP + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching COMP interrupts. Interrupts + * are all disabled upon return. + */ + + CODE int (*ao_setup)(FAR struct comp_dev_s *dev); + + /* Disable the COMP. This method is called when the COMP device is closed. + * This method reverses the operation the setup method. + * Works only if COMP device is not locked. + */ + + CODE void (*ao_shutdown)(FAR struct comp_dev_s *dev); + + /* Read COMP output state */ + + CODE int (*ao_read)(FAR struct comp_dev_s *dev); + + /* All ioctl calls will be routed through this method */ + + CODE int (*ao_ioctl)(FAR struct comp_dev_s *dev, int cmd, unsigned long arg); +}; + +struct comp_dev_s +{ +#ifdef CONFIG_COMP + /* Fields managed by common upper half COMP logic */ + + uint8_t ad_ocount; /* The number of times the device has been opened */ + sem_t ad_closesem; /* Locks out new opens while close is in progress */ +#endif + + /* Fields provided by lower half COMP logic */ + + FAR const struct comp_ops_s *ad_ops; /* Arch-specific operations */ + FAR void *ad_priv; /* Used by the arch-specific logic */ +}; + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +int comp_register(FAR const char *path, FAR struct comp_dev_s *dev); + +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_ANALOG_COMP_H */ diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 687d19dcf9b..f618ac94cea 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -697,6 +697,10 @@ struct pthread_tcb_s pthread_addr_t arg; /* Startup argument */ FAR void *joininfo; /* Detach-able info to support join */ + /* Robust mutex support *******************************************************/ + + FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */ + /* Clean-up stack *************************************************************/ #ifdef CONFIG_PTHREAD_CLEANUP diff --git a/include/pthread.h b/include/pthread.h index d943a843e2f..305bb8db212 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -1,7 +1,7 @@ /******************************************************************************** * include/pthread.h * - * Copyright (C) 2007-2009, 2011-2012, 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2012, 2015-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -143,6 +143,13 @@ #define PTHREAD_PRIO_INHERIT SEM_PRIO_INHERIT #define PTHREAD_PRIO_PROTECT SEM_PRIO_PROTECT +/* Values for struct pthread_mutex_s flags. These are non-standard and + * intended only for internal use within the OS. + */ + +#define _PTHREAD_MFLAGS_INCONSISTENT (1 << 0) /* Mutex is in an inconsistent state */ +#define _PTHREAD_MFLAGS_NOTRECOVRABLE (1 << 1) /* Inconsistent mutex has been unlocked */ + /* Definitions to map some non-standard, BSD thread management interfaces to * the non-standard Linux-like prctl() interface. Since these are simple * mappings to prctl, they will return 0 on success and -1 on failure with the @@ -233,11 +240,18 @@ typedef struct pthread_mutexattr_s pthread_mutexattr_t; struct pthread_mutex_s { - int pid; /* ID of the holder of the mutex */ + /* Supports a singly linked list */ + + FAR struct pthread_mutex_s *flink; + + /* Payload */ + sem_t sem; /* Semaphore underlying the implementation of the mutex */ + pid_t pid; /* ID of the holder of the mutex */ + uint8_t flags; /* See _PTHREAD_MFLAGS_* */ #ifdef CONFIG_MUTEX_TYPES uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */ - int nlocks; /* The number of recursive locks held */ + int16_t nlocks; /* The number of recursive locks held */ #endif }; @@ -424,6 +438,10 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex); int pthread_mutex_trylock(FAR pthread_mutex_t *mutex); int pthread_mutex_unlock(FAR pthread_mutex_t *mutex); +/* Make sure that the pthread mutex is in a consistent state */ + +int pthread_mutex_consistent(FAR pthread_mutex_t *mutex); + /* Operations on condition variables */ int pthread_condattr_init(FAR pthread_condattr_t *attr); diff --git a/libc/string/lib_strerror.c b/libc/string/lib_strerror.c index 00eb2248a2e..409501f3900 100644 --- a/libc/string/lib_strerror.c +++ b/libc/string/lib_strerror.c @@ -110,12 +110,6 @@ static const struct errno_strmap_s g_errnomap[] = { EPIPE, EPIPE_STR }, { EDOM, EDOM_STR }, { ERANGE, ERANGE_STR }, - { EDEADLK, EDEADLK_STR }, - { ENAMETOOLONG, ENAMETOOLONG_STR }, - { ENOLCK, ENOLCK_STR }, - { ENOSYS, ENOSYS_STR }, - { ENOTEMPTY, ENOTEMPTY_STR }, - { ELOOP, ELOOP_STR }, { ENOMSG, ENOMSG_STR }, { EIDRM, EIDRM_STR }, { ECHRNG, ECHRNG_STR }, @@ -126,12 +120,15 @@ static const struct errno_strmap_s g_errnomap[] = { EUNATCH, EUNATCH_STR }, { ENOCSI, ENOCSI_STR }, { EL2HLT, EL2HLT_STR }, + { EDEADLK, EDEADLK_STR }, + { ENOLCK, ENOLCK_STR }, { EBADE, EBADE_STR }, { EBADR, EBADR_STR }, { EXFULL, EXFULL_STR }, { ENOANO, ENOANO_STR }, { EBADRQC, EBADRQC_STR }, { EBADSLT, EBADSLT_STR }, + { EDEADLOCK, EDEADLOCK_STR }, { EBFONT, EBFONT_STR }, { ENOSTR, ENOSTR_STR }, { ENODATA, ENODATA_STR }, @@ -146,9 +143,10 @@ static const struct errno_strmap_s g_errnomap[] = { ECOMM, ECOMM_STR }, { EPROTO, EPROTO_STR }, { EMULTIHOP, EMULTIHOP_STR }, + { ELBIN, ELBIN_STR }, { EDOTDOT, EDOTDOT_STR }, { EBADMSG, EBADMSG_STR }, - { EOVERFLOW, EOVERFLOW_STR }, + { EFTYPE, EFTYPE_STR }, { ENOTUNIQ, ENOTUNIQ_STR }, { EBADFD, EBADFD_STR }, { EREMCHG, EREMCHG_STR }, @@ -157,47 +155,53 @@ static const struct errno_strmap_s g_errnomap[] = { ELIBSCN, ELIBSCN_STR }, { ELIBMAX, ELIBMAX_STR }, { ELIBEXEC, ELIBEXEC_STR }, - { EILSEQ, EILSEQ_STR }, - { ERESTART, ERESTART_STR }, - { ESTRPIPE, ESTRPIPE_STR }, - { EUSERS, EUSERS_STR }, - { ENOTSOCK, ENOTSOCK_STR }, - { EDESTADDRREQ, EDESTADDRREQ_STR }, - { EMSGSIZE, EMSGSIZE_STR }, - { EPROTOTYPE, EPROTOTYPE_STR }, - { ENOPROTOOPT, ENOPROTOOPT_STR }, - { EPROTONOSUPPORT, EPROTONOSUPPORT_STR }, - { ESOCKTNOSUPPORT, ESOCKTNOSUPPORT_STR }, + { ENOSYS, ENOSYS_STR }, + { ENMFILE, ENMFILE_STR }, + { ENOTEMPTY, ENOTEMPTY_STR }, + { ENAMETOOLONG, ENAMETOOLONG_STR }, + { ELOOP, ELOOP_STR }, { EOPNOTSUPP, EOPNOTSUPP_STR }, { EPFNOSUPPORT, EPFNOSUPPORT_STR }, - { EAFNOSUPPORT, EAFNOSUPPORT_STR }, - { EADDRINUSE, EADDRINUSE_STR }, - { EADDRNOTAVAIL, EADDRNOTAVAIL_STR }, - { ENETDOWN, ENETDOWN_STR }, - { ENETUNREACH, ENETUNREACH_STR }, - { ENETRESET, ENETRESET_STR }, - { ECONNABORTED, ECONNABORTED_STR }, { ECONNRESET, ECONNRESET_STR }, { ENOBUFS, ENOBUFS_STR }, - { EISCONN, EISCONN_STR }, - { ENOTCONN, ENOTCONN_STR }, + { EAFNOSUPPORT, EAFNOSUPPORT_STR }, + { EPROTOTYPE, EPROTOTYPE_STR }, + { ENOTSOCK, ENOTSOCK_STR }, + { ENOPROTOOPT, ENOPROTOOPT_STR }, { ESHUTDOWN, ESHUTDOWN_STR }, - { ETOOMANYREFS, ETOOMANYREFS_STR }, - { ETIMEDOUT, ETIMEDOUT_STR }, { ECONNREFUSED, ECONNREFUSED_STR }, + { EADDRINUSE, EADDRINUSE_STR }, + { ECONNABORTED, ECONNABORTED_STR }, + { ENETUNREACH, ENETUNREACH_STR }, + { ENETDOWN, ENETDOWN_STR }, + { ETIMEDOUT, ETIMEDOUT_STR }, { EHOSTDOWN, EHOSTDOWN_STR }, { EHOSTUNREACH, EHOSTUNREACH_STR }, - { EALREADY, EALREADY_STR }, { EINPROGRESS, EINPROGRESS_STR }, - { ESTALE, ESTALE_STR }, - { EUCLEAN, EUCLEAN_STR }, - { ENOTNAM, ENOTNAM_STR }, - { ENAVAIL, ENAVAIL_STR }, - { EISNAM, EISNAM_STR }, - { EREMOTEIO, EREMOTEIO_STR }, + { EALREADY, EALREADY_STR }, + { EDESTADDRREQ, EDESTADDRREQ_STR }, + { EMSGSIZE, EMSGSIZE_STR }, + { EPROTONOSUPPORT, EPROTONOSUPPORT_STR }, + { ESOCKTNOSUPPORT, ESOCKTNOSUPPORT_STR }, + { EADDRNOTAVAIL, EADDRNOTAVAIL_STR }, + { ENETRESET, ENETRESET_STR }, + { EISCONN, EISCONN_STR }, + { ENOTCONN, ENOTCONN_STR }, + { ETOOMANYREFS, ETOOMANYREFS_STR }, + { EPROCLIM, EPROCLIM_STR }, + { EUSERS, EUSERS_STR }, { EDQUOT, EDQUOT_STR }, + { ESTALE, ESTALE_STR }, + { ENOTSUP, ENOTSUP_STR }, { ENOMEDIUM, ENOMEDIUM_STR }, - { EMEDIUMTYPE, EMEDIUMTYPE_STR } + { ENOSHARE, ENOSHARE_STR }, + { ECASECLASH, ECASECLASH_STR }, + { EILSEQ, EILSEQ_STR }, + { EOVERFLOW, EOVERFLOW_STR }, + { ECANCELED, ECANCELED_STR }, + { ENOTRECOVERABLE, ENOTRECOVERABLE_STR }, + { EOWNERDEAD, EOWNERDEAD_STR }, + { ESTRPIPE, ESTRPIPE_STR } }; #else /* CONFIG_LIBC_STRERROR_SHORT */ @@ -238,28 +242,25 @@ static const struct errno_strmap_s g_errnomap[] = { EPIPE, "EPIPE" }, { EDOM, "EDOM" }, { ERANGE, "ERANGE" }, - { EDEADLK, "EDEADLK" }, - { ENAMETOOLONG, "ENAMETOOLONG" }, - { ENOLCK, "ENOLCK" }, - { ENOSYS, "ENOSYS" }, - { ENOTEMPTY, "ENOTEMPTY" }, - { ELOOP, "ELOOP" }, { ENOMSG, "ENOMSG" }, { EIDRM, "EIDRM" }, { ECHRNG, "ECHRNG" }, { EL2NSYNC, "EL2NSYNC" }, { EL3HLT, "EL3HLT" }, { EL3RST, "EL3RST" }, - { EL3RST, "EL3RST" }, + { ELNRNG, "ELNRNG" }, { EUNATCH, "EUNATCH" }, { ENOCSI, "ENOCSI" }, { EL2HLT, "EL2HLT" }, + { EDEADLK, "EDEADLK" }, + { ENOLCK, "ENOLCK" }, { EBADE, "EBADE" }, { EBADR, "EBADR" }, { EXFULL, "EXFULL" }, { ENOANO, "ENOANO" }, { EBADRQC, "EBADRQC" }, { EBADSLT, "EBADSLT" }, + { EDEADLOCK, "EDEADLOCK" }, { EBFONT, "EBFONT" }, { ENOSTR, "ENOSTR" }, { ENODATA, "ENODATA" }, @@ -274,9 +275,10 @@ static const struct errno_strmap_s g_errnomap[] = { ECOMM, "ECOMM" }, { EPROTO, "EPROTO" }, { EMULTIHOP, "EMULTIHOP" }, + { ELBIN, "ELBIN" }, { EDOTDOT, "EDOTDOT" }, { EBADMSG, "EBADMSG" }, - { EOVERFLOW, "EOVERFLOW" }, + { EFTYPE, "EFTYPE" }, { ENOTUNIQ, "ENOTUNIQ" }, { EBADFD, "EBADFD" }, { EREMCHG, "EREMCHG" }, @@ -285,47 +287,53 @@ static const struct errno_strmap_s g_errnomap[] = { ELIBSCN, "ELIBSCN" }, { ELIBMAX, "ELIBMAX" }, { ELIBEXEC, "ELIBEXEC" }, - { EILSEQ, "EILSEQ" }, - { ERESTART, "ERESTART" }, - { ESTRPIPE, "ESTRPIPE" }, - { EUSERS, "EUSERS" }, - { ENOTSOCK, "ENOTSOCK" }, - { EDESTADDRREQ, "EDESTADDRREQ" }, - { EMSGSIZE, "EMSGSIZE" }, - { EPROTOTYPE, "EPROTOTYPE" }, - { ENOPROTOOPT, "ENOPROTOOPT" }, - { EPROTONOSUPPORT, "EPROTONOSUPPORT" }, - { ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" }, + { ENOSYS, "ENOSYS" }, + { ENMFILE, "ENMFILE" }, + { ENOTEMPTY, "ENOTEMPTY" }, + { ENAMETOOLONG, "ENAMETOOLONG" }, + { ELOOP, "ELOOP" }, { EOPNOTSUPP, "EOPNOTSUPP" }, { EPFNOSUPPORT, "EPFNOSUPPORT" }, - { EAFNOSUPPORT, "EAFNOSUPPORT" }, - { EADDRINUSE, "EADDRINUSE" }, - { EADDRNOTAVAIL, "EADDRNOTAVAIL" }, - { ENETDOWN, "ENETDOWN" }, - { ENETUNREACH, "ENETUNREACH" }, - { ENETRESET, "ENETRESET" }, - { ECONNABORTED, "ECONNABORTED" }, { ECONNRESET, "ECONNRESET" }, { ENOBUFS, "ENOBUFS" }, - { EISCONN, "EISCONN" }, - { ENOTCONN, "ENOTCONN" }, + { EAFNOSUPPORT, "EAFNOSUPPORT" }, + { EPROTOTYPE, "EPROTOTYPE" }, + { ENOTSOCK, "ENOTSOCK" }, + { ENOPROTOOPT, "ENOPROTOOPT" }, { ESHUTDOWN, "ESHUTDOWN" }, - { ETOOMANYREFS, "ETOOMANYREFS" }, - { ETIMEDOUT, "ETIMEDOUT" }, { ECONNREFUSED, "ECONNREFUSED" }, + { EADDRINUSE, "EADDRINUSE" }, + { ECONNABORTED, "ECONNABORTED" }, + { ENETUNREACH, "ENETUNREACH" }, + { ENETDOWN, "ENETDOWN" }, + { ETIMEDOUT, "ETIMEDOUT" }, { EHOSTDOWN, "EHOSTDOWN" }, { EHOSTUNREACH, "EHOSTUNREACH" }, - { EALREADY, "EALREADY" }, { EINPROGRESS, "EINPROGRESS" }, - { ESTALE, "ESTALE" }, - { EUCLEAN, "EUCLEAN" }, - { ENOTNAM, "ENOTNAM" }, - { ENAVAIL, "ENAVAIL" }, - { EISNAM, "EISNAM" }, - { EREMOTEIO, "EREMOTEIO" }, + { EALREADY, "EALREADY" }, + { EDESTADDRREQ, "EDESTADDRREQ" }, + { EMSGSIZE, "EMSGSIZE" }, + { EPROTONOSUPPORT, "EPROTONOSUPPORT" }, + { ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" }, + { EADDRNOTAVAIL, "EADDRNOTAVAIL" }, + { ENETRESET, "ENETRESET" }, + { EISCONN, "EISCONN" }, + { ENOTCONN, "ENOTCONN" }, + { ETOOMANYREFS, "ETOOMANYREFS" }, + { EPROCLIM, "EPROCLIM" }, + { EUSERS, "EUSERS" }, { EDQUOT, "EDQUOT" }, + { ESTALE, "ESTALE" }, + { ENOTSUP, "ENOTSUP" }, { ENOMEDIUM, "ENOMEDIUM" }, - { EMEDIUMTYPE, "EMEDIUMTYPE" } + { ENOSHARE, "ENOSHARE" }, + { ECASECLASH, "ECASECLASH" }, + { EILSEQ, "EILSEQ" }, + { EOVERFLOW, "EOVERFLOW" }, + { ECANCELED, "ECANCELED" }, + { ENOTRECOVERABLE, "ENOTRECOVERABLE" }, + { EOWNERDEAD, "EOWNERDEAD" }, + { ESTRPIPE, "ESTRPIPE" } }; #endif /* CONFIG_LIBC_STRERROR_SHORT */ diff --git a/sched/pthread/Make.defs b/sched/pthread/Make.defs index 6156dd54112..a39a35d2084 100644 --- a/sched/pthread/Make.defs +++ b/sched/pthread/Make.defs @@ -37,8 +37,9 @@ ifneq ($(CONFIG_DISABLE_PTHREAD),y) CSRCS += pthread_create.c pthread_exit.c pthread_join.c pthread_detach.c CSRCS += pthread_yield.c pthread_getschedparam.c pthread_setschedparam.c -CSRCS += pthread_mutexinit.c pthread_mutexdestroy.c +CSRCS += pthread_mutexinit.c pthread_mutexdestroy.c pthread_mutex.c CSRCS += pthread_mutexlock.c pthread_mutextrylock.c pthread_mutexunlock.c +CSRCS += pthread_mutexconsistent.c pthread_mutexinconsistent.c CSRCS += pthread_condinit.c pthread_conddestroy.c CSRCS += pthread_condwait.c pthread_condsignal.c pthread_condbroadcast.c CSRCS += pthread_barrierinit.c pthread_barrierdestroy.c pthread_barrierwait.c diff --git a/sched/pthread/pthread.h b/sched/pthread/pthread.h index be7a20de2ea..6ab044a3ba0 100644 --- a/sched/pthread/pthread.h +++ b/sched/pthread/pthread.h @@ -107,8 +107,11 @@ void pthread_destroyjoin(FAR struct task_group_s *group, FAR struct join_s *pthread_findjoininfo(FAR struct task_group_s *group, pid_t pid); void pthread_release(FAR struct task_group_s *group); +int pthread_takesemaphore(sem_t *sem, bool intr); int pthread_givesemaphore(sem_t *sem); -int pthread_takesemaphore(sem_t *sem); +int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr); +int pthread_mutex_give(FAR struct pthread_mutex_s *mutex); +void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb); #ifdef CONFIG_MUTEX_TYPES int pthread_mutexattr_verifytype(int type); diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c index a9b7e8270b7..3a520b1f930 100644 --- a/sched/pthread/pthread_cancel.c +++ b/sched/pthread/pthread_cancel.c @@ -162,6 +162,10 @@ int pthread_cancel(pthread_t thread) (void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED); + /* Recover any mutexes still held by the canceled thread */ + + pthread_mutex_inconsistent(tcb); + /* Then let task_terminate do the real work */ return task_terminate((pid_t)thread, false); diff --git a/sched/pthread/pthread_completejoin.c b/sched/pthread/pthread_completejoin.c index b516c9defd0..6053f6c1dab 100644 --- a/sched/pthread/pthread_completejoin.c +++ b/sched/pthread/pthread_completejoin.c @@ -99,7 +99,7 @@ static bool pthread_notifywaiters(FAR struct join_s *pjoin) * value. */ - (void)pthread_takesemaphore(&pjoin->data_sem); + (void)pthread_takesemaphore(&pjoin->data_sem, false); return true; } @@ -210,7 +210,7 @@ int pthread_completejoin(pid_t pid, FAR void *exit_value) /* First, find thread's structure in the private data set. */ - (void)pthread_takesemaphore(&group->tg_joinsem); + (void)pthread_takesemaphore(&group->tg_joinsem, false); pjoin = pthread_findjoininfo(group, pid); if (!pjoin) { diff --git a/sched/pthread/pthread_condtimedwait.c b/sched/pthread/pthread_condtimedwait.c index 9027c305ef9..4ed8c5aed6e 100644 --- a/sched/pthread/pthread_condtimedwait.c +++ b/sched/pthread/pthread_condtimedwait.c @@ -156,12 +156,10 @@ static void pthread_condtimedout(int argc, uint32_t pid, uint32_t signo) * abstime - wait until this absolute time * * Return Value: - * OK (0) on success; ERROR (-1) on failure with errno - * set appropriately. + * OK (0) on success; A non-zero errno value is returned on failure. * * Assumptions: - * Timing is of resolution 1 msec, with +/-1 millisecond - * accuracy. + * Timing is of resolution 1 msec, with +/-1 millisecond accuracy. * ****************************************************************************/ @@ -236,7 +234,7 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex, if (ret) { /* Restore interrupts (pre-emption will be enabled when - * we fall through the if/then/else + * we fall through the if/then/else) */ leave_critical_section(flags); @@ -262,8 +260,8 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex, /* Give up the mutex */ mutex->pid = -1; - ret = pthread_givesemaphore((FAR sem_t *)&mutex->sem); - if (ret) + ret = pthread_mutex_give(mutex); + if (ret != 0) { /* Restore interrupts (pre-emption will be enabled when * we fall through the if/then/else) @@ -318,12 +316,12 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex, /* Reacquire the mutex (retaining the ret). */ sinfo("Re-locking...\n"); - status = pthread_takesemaphore((FAR sem_t *)&mutex->sem); - if (!status) + status = pthread_mutex_take(mutex, false); + if (status == OK) { mutex->pid = mypid; } - else if (!ret) + else if (ret == 0) { ret = status; } diff --git a/sched/pthread/pthread_condwait.c b/sched/pthread/pthread_condwait.c index e7c6a9af255..9bcba234a5f 100644 --- a/sched/pthread/pthread_condwait.c +++ b/sched/pthread/pthread_condwait.c @@ -71,6 +71,7 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex) { + int status; int ret; sinfo("cond=0x%p mutex=0x%p\n", cond, mutex); @@ -100,11 +101,18 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex) sched_lock(); mutex->pid = -1; - ret = pthread_givesemaphore((FAR sem_t *)&mutex->sem); + ret = pthread_mutex_give(mutex); /* Take the semaphore */ - ret |= pthread_takesemaphore((FAR sem_t *)&cond->sem); + status = pthread_takesemaphore((FAR sem_t *)&cond->sem, false); + if (ret == OK) + { + /* Report the first failure that occurs */ + + ret = status; + } + sched_unlock(); /* Reacquire the mutex. @@ -114,7 +122,16 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex) */ sinfo("Reacquire mutex...\n"); - ret |= pthread_takesemaphore((FAR sem_t *)&mutex->sem); + status = pthread_mutex_take(mutex, false); + if (ret == OK) + { + /* Report the first failure that occurs */ + + ret = status; + } + + /* Was all of the above successful? */ + if (ret == OK) { mutex->pid = getpid(); diff --git a/sched/pthread/pthread_create.c b/sched/pthread/pthread_create.c index 957936cd826..4fbf646424a 100644 --- a/sched/pthread/pthread_create.c +++ b/sched/pthread/pthread_create.c @@ -177,7 +177,7 @@ static void pthread_start(void) /* Sucessfully spawned, add the pjoin to our data set. */ - (void)pthread_takesemaphore(&group->tg_joinsem); + (void)pthread_takesemaphore(&group->tg_joinsem, false); pthread_addjoininfo(group, pjoin); (void)pthread_givesemaphore(&group->tg_joinsem); @@ -555,7 +555,7 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, * its join structure. */ - (void)pthread_takesemaphore(&pjoin->data_sem); + (void)pthread_takesemaphore(&pjoin->data_sem, false); /* Return the thread information to the caller */ diff --git a/sched/pthread/pthread_detach.c b/sched/pthread/pthread_detach.c index 0d165e2d23b..9e3d900d7ec 100644 --- a/sched/pthread/pthread_detach.c +++ b/sched/pthread/pthread_detach.c @@ -87,7 +87,7 @@ int pthread_detach(pthread_t thread) /* Find the entry associated with this pthread. */ - (void)pthread_takesemaphore(&group->tg_joinsem); + (void)pthread_takesemaphore(&group->tg_joinsem, false); pjoin = pthread_findjoininfo(group, (pid_t)thread); if (!pjoin) { diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c index 40a5b7fb0de..4654d863710 100644 --- a/sched/pthread/pthread_exit.c +++ b/sched/pthread/pthread_exit.c @@ -123,6 +123,10 @@ void pthread_exit(FAR void *exit_value) exit(EXIT_FAILURE); } + /* Recover any mutexes still held by the canceled thread */ + + pthread_mutex_inconsistent(tcb); + /* Perform common task termination logic. This will get called again later * through logic kicked off by _exit(). However, we need to call it before * calling _exit() in order certain operations if this is the last thread diff --git a/sched/pthread/pthread_initialize.c b/sched/pthread/pthread_initialize.c index 0ced8d61819..e5965d8b60d 100644 --- a/sched/pthread/pthread_initialize.c +++ b/sched/pthread/pthread_initialize.c @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include #include "pthread/pthread.h" @@ -63,8 +65,6 @@ * Return Value: * None * - * Assumptions: - * ****************************************************************************/ void pthread_initialize(void) @@ -78,44 +78,45 @@ void pthread_initialize(void) * Support managed access to the private data sets. * * Parameters: - * None + * sem - The semaphore to lock or unlock + * intr - false: ignore EINTR errors when locking; true tread EINTR as + * other errors by returning the errno value * * Return Value: - * 0 on success or an ERROR on failure with errno value set to EINVAL. - * Note that the errno EINTR is never returned by this function. - * - * Assumptions: + * 0 on success or an errno value on failure. * ****************************************************************************/ -int pthread_takesemaphore(sem_t *sem) +int pthread_takesemaphore(sem_t *sem, bool intr) { /* Verify input parameters */ - if (sem) + DEBUGASSERT(sem != NULL); + if (sem != NULL) { /* Take the semaphore */ while (sem_wait(sem) != OK) { + int errcode = get_errno(); + /* Handle the special case where the semaphore wait was * awakened by the receipt of a signal. */ - if (get_errno() != EINTR) + if (intr || errcode != EINTR) { - set_errno(EINVAL); - return ERROR; + return errcode; } } + return OK; } else { /* NULL semaphore pointer! */ - set_errno(EINVAL); - return ERROR; + return EINVAL; } } @@ -123,7 +124,9 @@ int pthread_givesemaphore(sem_t *sem) { /* Verify input parameters */ - if (sem) + + DEBUGASSERT(sem != NULL); + if (sem != NULL) { /* Give the semaphore */ @@ -135,16 +138,14 @@ int pthread_givesemaphore(sem_t *sem) { /* sem_post() reported an error */ - set_errno(EINVAL); - return ERROR; + return get_errno(); } } else { /* NULL semaphore pointer! */ - set_errno(EINVAL); - return ERROR; + return EINVAL; } } diff --git a/sched/pthread/pthread_join.c b/sched/pthread/pthread_join.c index 01c1c713eaa..6d2b48c81a8 100644 --- a/sched/pthread/pthread_join.c +++ b/sched/pthread/pthread_join.c @@ -114,7 +114,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) * because it will also attempt to get this semaphore. */ - (void)pthread_takesemaphore(&group->tg_joinsem); + (void)pthread_takesemaphore(&group->tg_joinsem, false); /* Find the join information associated with this thread. * This can fail for one of three reasons: (1) There is no @@ -197,7 +197,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) * pthread to exit. */ - (void)pthread_takesemaphore(&pjoin->exit_sem); + (void)pthread_takesemaphore(&pjoin->exit_sem, false); /* The thread has exited! Get the thread exit value */ @@ -217,7 +217,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) * pthread_destroyjoin is called. */ - (void)pthread_takesemaphore(&group->tg_joinsem); + (void)pthread_takesemaphore(&group->tg_joinsem, false); } /* Pre-emption is okay now. The logic still cannot be re-entered diff --git a/sched/pthread/pthread_mutex.c b/sched/pthread/pthread_mutex.c new file mode 100644 index 00000000000..03bf35ea49e --- /dev/null +++ b/sched/pthread/pthread_mutex.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * sched/pthread/pthread_mutex.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "sched/sched.h" +#include "pthread/pthread.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_mutex_take + * + * Description: + * Take the pthread_mutex and, if successful, add the mutex to the ist of + * mutexes held by this thread. + * + * Parameters: + * mutex - The mux to be locked + * intr - false: ignore EINTR errors when locking; true tread EINTR as + * other errors by returning the errno value + * + * Return Value: + * 0 on success or an errno value on failure. + * + ****************************************************************************/ + +int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr) +{ + int ret = EINVAL; + + /* Verify input parameters */ + + DEBUGASSERT(mutex != NULL); + if (mutex != NULL) + { + /* Make sure that no unexpected context switches occur */ + + sched_lock(); + + /* Take semaphore underlying the mutex */ + + ret = pthread_takesemaphore(&mutex->sem, intr); + if (ret == OK) + { + DEBUGASSERT(mutex->flink == NULL); + + /* Check if the holder of the mutex has terminated. In that case, + * the state of the mutex is inconsistent and we return EOWNERDEAD. + */ + + if ((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0) + { + ret = EOWNERDEAD; + } + + /* Add the mutex to the list of mutexes held by this task */ + + else + { + FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task(); + irqstate_t flags; + + flags = enter_critical_section(); + mutex->flink = rtcb->mhead; + rtcb->mhead = mutex; + leave_critical_section(flags); + } + } + } + + sched_unlock(); + return ret; +} + +/**************************************************************************** + * Name: pthread_mutex_give + * + * Description: + * Take the pthread_mutex and, if successful, add the mutex to the ist of + * mutexes held by this thread. + * + * Parameters: + * mutex - The mux to be unlocked + * + * Return Value: + * 0 on success or an errno value on failure. + * + ****************************************************************************/ + +int pthread_mutex_give(FAR struct pthread_mutex_s *mutex) +{ + FAR struct pthread_mutex_s *curr; + FAR struct pthread_mutex_s *prev; + int ret = EINVAL; + + /* Verify input parameters */ + + DEBUGASSERT(mutex != NULL); + if (mutex != NULL) + { + FAR struct pthread_tcb_s *rtcb = (FAR struct pthread_tcb_s *)this_task(); + irqstate_t flags; + + flags = enter_critical_section(); + + /* Remove the mutex from the list of mutexes held by this task */ + + for (prev = NULL, curr = rtcb->mhead; + curr != NULL && curr != mutex; + prev = curr, curr = curr->flink); + + DEBUGASSERT(curr == mutex); + + /* Remove the mutex from the list. prev == NULL means that the mutex + * to be removed is at the head of the list. + */ + + if (prev == NULL) + { + rtcb->mhead = mutex->flink; + } + else + { + prev->flink = mutex->flink; + } + + mutex->flink = NULL; + leave_critical_section(flags); + + /* Now release the underlying semaphore */ + + ret = pthread_givesemaphore(&mutex->sem); + } + + return ret; +} + diff --git a/sched/pthread/pthread_mutexconsistent.c b/sched/pthread/pthread_mutexconsistent.c new file mode 100644 index 00000000000..3febab2d0b0 --- /dev/null +++ b/sched/pthread/pthread_mutexconsistent.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * sched/pthread/pthread_mutexconsistent.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "pthread/pthread.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_mutex_consistent + * + * Description: + * If mutex is a robust mutex in an inconsistent state, the + * pthread_mutex_consistent() function can be used to mark the state + * protected by the mutex referenced by mutex as consistent again. + * + * If an owner of a robust mutex terminates while holding the mutex, the + * mutex becomes inconsistent and the next thread that acquires the mutex + * lock will be notified of the state by the return value EOWNERDEAD. + * In this case, the mutex does not become normally usable again until the + * state is marked consistent. + * + * If the thread which acquired the mutex lock with the return value + * EOWNERDEAD terminates before calling either pthread_mutex_consistent() + * or pthread_mutex_unlock(), the next thread that acquires the mutex lock + * will be notified about the state of the mutex by the return value + * EOWNERDEAD. + * + * The behavior is undefined if the value specified by the mutex argument + * to pthread_mutex_consistent() does not refer to an initialized mutex. + * + * Input Parameters: + * mutex -- a reference to the mutex to be made consistent + * + * Returned Value: + * Upon successful completion, the pthread_mutex_consistent() function + * will return zero. Otherwise, an error value will be returned to + * indicate the error. + * + ****************************************************************************/ + +int pthread_mutex_consistent(FAR pthread_mutex_t *mutex) +{ + int ret = EINVAL; + int status; + + sinfo("mutex=0x%p\n", mutex); + DEBUGASSERT(mutex != NULL); + + if (mutex != NULL) + { + /* Make sure the mutex is stable while we make the following checks. */ + + sched_lock(); + + /* Is the mutex available? */ + + DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ + if (mutex->pid >= 0) + { + /* No.. Verify that the PID still exists. We may be destroying + * the mutex after cancelling a pthread and the mutex may have + * been in a bad state owned by the dead pthread. NOTE: The + * folling is unspecified behavior (see pthread_mutex_consistent()). + * + * If the holding thread is still valid, then we should be able to + * map its PID to the underlying TCB. That is what sched_gettcb() + * does. + */ + + if (sched_gettcb(mutex->pid) == NULL) + { + /* The thread associated with the PID no longer exists */ + + mutex->pid = -1; + mutex->flags = 0; + + /* Reset the semaphore. This has the same affect as if the + * dead task had called pthread_mutex_unlock(). + */ + + status = sem_reset((FAR sem_t *)&mutex->sem, 1); + ret = (status != OK) ? get_errno() : OK; + } + } + + sched_unlock(); + ret = OK; + } + + sinfo("Returning %d\n", ret); + return ret; +} diff --git a/sched/pthread/pthread_mutexdestroy.c b/sched/pthread/pthread_mutexdestroy.c index 8bab62c4743..23905fd407e 100644 --- a/sched/pthread/pthread_mutexdestroy.c +++ b/sched/pthread/pthread_mutexdestroy.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/pthread/pthread_mutexdestroy.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,8 @@ #include #include +#include + #include "pthread/pthread.h" /**************************************************************************** @@ -70,60 +72,86 @@ int pthread_mutex_destroy(FAR pthread_mutex_t *mutex) { - int ret = OK; + int ret = EINVAL; int status; sinfo("mutex=0x%p\n", mutex); + DEBUGASSERT(mutex != NULL); - if (mutex == NULL) + if (mutex != NULL) { - ret = EINVAL; - } - else - { - /* Make sure the semaphore is stable while we make the following - * checks - */ + /* Make sure the semaphore is stable while we make the following checks */ sched_lock(); - /* Is the semaphore available? */ + /* Is the mutex available? */ - if (mutex->pid != -1) + if (mutex->pid >= 0) { -#ifndef CONFIG_DISABLE_SIGNALS - /* Verify that the PID still exists. We may be destroying the - * mutex after cancelling a pthread and the mutex may have been - * in a bad state owned by the dead pthread. + DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ + + /* No.. Verify that the PID still exists. We may be destroying + * the mutex after cancelling a pthread and the mutex may have + * been in a bad state owned by the dead pthread. NOTE: The + * following behavior is unspecified for pthread_mutex_destroy() + * (see pthread_mutex_consistent()). + * + * If the holding thread is still valid, then we should be able to + * map its PID to the underlying TCB. That is what sched_gettcb() + * does. */ - ret = kill(mutex->pid, 0); - if (ret < 0) - { - /* The thread associated with the PID no longer exists */ + if (sched_gettcb(mutex->pid) == NULL) + { + /* The thread associated with the PID no longer exists */ - mutex->pid = -1; + mutex->pid = -1; - /* Destroy the semaphore */ + /* Reset the semaphore. If threads are were on this + * semaphore, then this will awakened them and make + * destruction of the semaphore impossible here. + */ - status = sem_destroy((FAR sem_t *)&mutex->sem); - ret = (status != OK) ? get_errno() : OK; + status = sem_reset((FAR sem_t *)&mutex->sem, 1); + if (status < 0) + { + ret = -status; + } + + /* Check if the reset caused some other thread to lock the + * mutex. + */ + + else if (mutex->pid != -1) + { + /* Yes.. then we cannot destroy the mutex now. */ + + ret = EBUSY; + } + + /* Destroy the underlying semaphore */ + + else + { + status = sem_destroy((FAR sem_t *)&mutex->sem); + ret = (status != OK) ? get_errno() : OK; + } + } + else + { + ret = EBUSY; } - else -#endif - { - ret = EBUSY; - } } else { - /* Destroy the semaphore */ + /* Destroy the semaphore + * + * REVISIT: What if there are threads waiting on the semaphore? + * Perhaps this logic should all sem_reset() first? + */ status = sem_destroy((FAR sem_t *)&mutex->sem); - if (status != OK) - { - ret = get_errno(); - } + ret = ((status != OK) ? get_errno() : OK); } sched_unlock(); diff --git a/sched/pthread/pthread_mutexinconsistent.c b/sched/pthread/pthread_mutexinconsistent.c new file mode 100644 index 00000000000..c9d2b203711 --- /dev/null +++ b/sched/pthread/pthread_mutexinconsistent.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * sched/pthread/pthread_mutexinconsistent.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "pthread/pthread.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_mutex_inconsistent + * + * Description: + * This function is called when a pthread is terminated via either + * pthread_exit() or pthread_cancel(). It will check for any mutexes + * held by exitting thread. It will mark them as inconsistent and + * then wake up the highest priority waiter for the mutex. That + * instance of pthread_mutex_lock() will then return EOWNERDEAD. + * + * Input Parameters: + * tcb -- a reference to the TCB of the exitting pthread. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb) +{ + FAR struct pthread_mutex_s *mutex; + irqstate_t flags; + + DEBUGASSERT(tcb != NULL); + + sched_lock(); + + /* Remove and process each mutex from the list of mutexes held by this task */ + + while (tcb->mhead != NULL) + { + /* Remove the mutex from the TCB list */ + + flags = enter_critical_section(); + mutex = tcb->mhead; + tcb->mhead = mutex->flink; + mutex->flink = NULL; + leave_critical_section(flags); + + /* Mark the mutex as INCONSISTENT and wake up any waiting thread */ + + mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT; + (void)pthread_givesemaphore(&mutex->sem); + } + + sched_unlock(); +} diff --git a/sched/pthread/pthread_mutexinit.c b/sched/pthread/pthread_mutexinit.c index fe9620da0b4..b521137683d 100644 --- a/sched/pthread/pthread_mutexinit.c +++ b/sched/pthread/pthread_mutexinit.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/pthread/pthread_mutexinit.c * - * Copyright (C) 2007-2009, 2011, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -123,6 +123,10 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex, ret = get_errno(); } #endif + /* Initial internal fields of the mutex */ + + mutex->flink = NULL; + mutex->flags = 0; /* Set up attributes unique to the mutex type */ diff --git a/sched/pthread/pthread_mutexlock.c b/sched/pthread/pthread_mutexlock.c index d5c8af2db2f..67b668bf9d8 100644 --- a/sched/pthread/pthread_mutexlock.c +++ b/sched/pthread/pthread_mutexlock.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/pthread/pthread_mutexlock.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -42,9 +42,12 @@ #include #include #include +#include #include #include +#include + #include "pthread/pthread.h" /**************************************************************************** @@ -104,15 +107,12 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex) { int mypid = (int)getpid(); - int ret = OK; + int ret = EINVAL; sinfo("mutex=0x%p\n", mutex); + DEBUGASSERT(mutex != NULL); - if (!mutex) - { - ret = EINVAL; - } - else + if (mutex != NULL) { /* Make sure the semaphore is stable while we make the following * checks. This all needs to be one atomic action. @@ -120,7 +120,7 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex) sched_lock(); - /* Does this task already hold the semaphore? */ + /* Does this thread already hold the semaphore? */ if (mutex->pid == mypid) { @@ -129,9 +129,19 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex) #ifdef CONFIG_MUTEX_TYPES if (mutex->type == PTHREAD_MUTEX_RECURSIVE) { - /* Yes... just increment the number of locks held and return success */ + /* Yes... just increment the number of locks held and return + * success. + */ - mutex->nlocks++; + if (mutex->nlocks < INT16_MAX) + { + mutex->nlocks++; + ret = OK; + } + else + { + ret = EOVERFLOW; + } } else #endif @@ -139,27 +149,49 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex) /* No, then we would deadlock... return an error (default * behavior is like PTHREAD_MUTEX_ERRORCHECK) * - * NOTE: This is non-compliant behavior for the case of a - * NORMAL mutex. In that case, it the deadlock condition should - * not be detected and the thread should be permitted to - * deadlock. + * NOTE: This is the correct behavior for a 'robust', NORMAL + * mutex. Compiant behavior for non-robust mutex should not + * include these checks. In that case, it the deadlock + * condition should not be detected and the thread should be + * permitted to deadlock. */ serr("ERROR: Returning EDEADLK\n"); ret = EDEADLK; } } + + /* The calling thread does not hold the semaphore. The correct + * behavior for the 'robust' mutex is to verify that the holder of the + * mutex is still valid. This is protection from the case + * where the holder of the mutex has exitted without unlocking it. + */ + + else if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) + { + DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ + DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0); + + /* A thread holds the mutex, but there is no such thread. POSIX + * requires that the 'robust' mutex return EOWNERDEAD in this case. + * It is then the caller's responsibility to call pthread_mutx_consistent() + * fo fix the mutex. + */ + + mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT; + ret = EOWNERDEAD; + } else { - /* Take the semaphore */ + /* Take the underlying semaphore, waiting if necessary */ - ret = pthread_takesemaphore((FAR sem_t *)&mutex->sem); + ret = pthread_mutex_take(mutex, true); /* If we successfully obtained the semaphore, then indicate * that we own it. */ - if (!ret) + if (ret == OK) { mutex->pid = mypid; #ifdef CONFIG_MUTEX_TYPES diff --git a/sched/pthread/pthread_mutextrylock.c b/sched/pthread/pthread_mutextrylock.c index 825cb992a14..683909c8594 100644 --- a/sched/pthread/pthread_mutextrylock.c +++ b/sched/pthread/pthread_mutextrylock.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/pthread/pthread_mutextrylock.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -83,15 +84,13 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) { - int ret = OK; + int status; + int ret = EINVAL; sinfo("mutex=0x%p\n", mutex); + DEBUGASSERT(mutex != NULL); - if (!mutex) - { - ret = EINVAL; - } - else + if (mutex != NULL) { int mypid = (int)getpid(); @@ -103,7 +102,8 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) /* Try to get the semaphore. */ - if (sem_trywait((FAR sem_t *)&mutex->sem) == OK) + status = sem_trywait((FAR sem_t *)&mutex->sem); + if (status == OK) { /* If we successfully obtained the semaphore, then indicate * that we own it. @@ -117,33 +117,72 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) mutex->nlocks = 1; } #endif + ret = OK; } - /* Was it not available? */ + /* sem_trywait failed */ - else if (get_errno() == EAGAIN) - { -#ifdef CONFIG_MUTEX_TYPES - - /* Check if recursive mutex was locked by ourself. */ - - if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->pid == mypid) - { - /* Increment the number of locks held and return successfully. */ - - mutex->nlocks++; - } - else - { - ret = EBUSY; - } -#else - ret = EBUSY; -#endif - } else { - ret = EINVAL; + /* Did it fail because the semaphore was not avaialabl? */ + + int errcode = get_errno(); + if (errcode == EAGAIN) + { +#ifdef CONFIG_MUTEX_TYPES + /* Check if recursive mutex was locked by the calling thread. */ + + if (mutex->type == PTHREAD_MUTEX_RECURSIVE && mutex->pid == mypid) + { + /* Increment the number of locks held and return successfully. */ + + if (mutex->nlocks < INT16_MAX) + { + mutex->nlocks++; + ret = OK; + } + else + { + ret = EOVERFLOW; + } + } + else +#endif + /* The calling thread does not hold the semaphore. The correct + * behavior for the 'robust' mutex is to verify that the holder of + * the mutex is still valid. This is protection from the case + * where the holder of the mutex has exitted without unlocking it. + */ + + if (mutex->pid > 0 && sched_gettcb(mutex->pid) == NULL) + { + DEBUGASSERT(mutex->pid != 0); /* < 0: available, >0 owned, ==0 error */ + DEBUGASSERT((mutex->flags & _PTHREAD_MFLAGS_INCONSISTENT) != 0); + + /* A thread holds the mutex, but there is no such thread. + * POSIX requires that the 'robust' mutex return EOWNERDEAD + * in this case. It is then the caller's responsibility to + * call pthread_mutx_consistent() fo fix the mutex. + */ + + mutex->flags |= _PTHREAD_MFLAGS_INCONSISTENT; + ret = EOWNERDEAD; + } + + /* The mutex is locked by another, active thread */ + + else + { + ret = EBUSY; + } + } + + /* Some other, unhandled error occurred */ + + else + { + ret = errcode; + } } sched_unlock(); diff --git a/sched/pthread/pthread_mutexunlock.c b/sched/pthread/pthread_mutexunlock.c index 56c14bb0367..7ab0c90469e 100644 --- a/sched/pthread/pthread_mutexunlock.c +++ b/sched/pthread/pthread_mutexunlock.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/pthread/pthread_mutexunlock.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -80,15 +80,12 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex) { - int ret = OK; + int ret = EINVAL; sinfo("mutex=0x%p\n", mutex); + DEBUGASSERT(mutex != NULL); - if (!mutex) - { - ret = EINVAL; - } - else + if (mutex != NULL) { /* Make sure the semaphore is stable while we make the following * checks. This all needs to be one atomic action. @@ -108,8 +105,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex) * the mutex." * * For the case of the non-robust PTHREAD_MUTEX_NORMAL mutex, - * the behavior is undefined. Here we treat that type as though - * it were PTHREAD_MUTEX_ERRORCHECK type and just return an error. + * the behavior is undefined. */ serr("ERROR: Holder=%d returning EPERM\n", mutex->pid); @@ -127,6 +123,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex) */ mutex->nlocks--; + ret = OK; } #endif @@ -142,7 +139,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex) #ifdef CONFIG_MUTEX_TYPES mutex->nlocks = 0; #endif - ret = pthread_givesemaphore((FAR sem_t *)&mutex->sem); + ret = pthread_mutex_give(mutex); } sched_unlock();