diff --git a/examples/mm/Makefile b/examples/mm/Makefile index 1a832863b..a74edc7a2 100644 --- a/examples/mm/Makefile +++ b/examples/mm/Makefile @@ -1,7 +1,7 @@ ############################################################################ # apps/examples/mm/Makefile # -# 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 @@ -37,13 +37,18 @@ # Memory Management Test +CONFIG_EXAMPLES_MM_PRIORITY ?= SCHED_PRIORITY_DEFAULT +CONFIG_EXAMPLES_MM_STACKSIZE ?= 2048 + APPNAME = mm +PRIORITY = $(CONFIG_EXAMPLES_MM_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_MM_STACKSIZE) ASRCS = CSRCS = MAINSRC = mm_main.c -CONFIG_XYZ_PROGNAME ?= mm$(EXEEXT) -PROGNAME = $(CONFIG_XYZ_PROGNAME) +CONFIG_EXAMPLES_MM_PROGNAME ?= mm$(EXEEXT) +PROGNAME = $(CONFIG_EXAMPLES_MM_PROGNAME) include $(APPDIR)/Application.mk diff --git a/examples/ostest/Makefile b/examples/ostest/Makefile index 381ca1d33..99d4d3adf 100644 --- a/examples/ostest/Makefile +++ b/examples/ostest/Makefile @@ -72,11 +72,15 @@ endif ifneq ($(CONFIG_DISABLE_PTHREAD),y) CSRCS += cancel.c cond.c mutex.c sem.c semtimed.c barrier.c timedwait.c +ifneq ($(CONFIG_PTHREAD_MUTEX_UNSAFE),y) +CSRCS += robust.c +endif + ifeq ($(CONFIG_FS_NAMED_SEMAPHORES),y) CSRCS += nsem.c endif -ifeq ($(CONFIG_MUTEX_TYPES),y) +ifeq ($(CONFIG_PTHREAD_MUTEX_TYPES),y) CSRCS += rmutex.c endif diff --git a/examples/ostest/ostest.h b/examples/ostest/ostest.h index fdbde3165..17ee5b85d 100644 --- a/examples/ostest/ostest.h +++ b/examples/ostest/ostest.h @@ -177,6 +177,12 @@ void timedmqueue_test(void); void cancel_test(void); +/* robust.c *****************************************************************/ + +#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE +void robust_test(void); +#endif + /* timedwait.c **************************************************************/ void timedwait_test(void); diff --git a/examples/ostest/ostest_main.c b/examples/ostest/ostest_main.c index e35f91b41..7d1734c97 100644 --- a/examples/ostest/ostest_main.c +++ b/examples/ostest/ostest_main.c @@ -373,7 +373,7 @@ static int user_main(int argc, char *argv[]) check_test_memory_usage(); #endif -#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_MUTEX_TYPES) +#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_PTHREAD_MUTEX_TYPES) /* Verify recursive mutexes */ printf("\nuser_main: recursive mutex test\n"); @@ -387,6 +387,12 @@ static int user_main(int argc, char *argv[]) printf("\nuser_main: cancel test\n"); cancel_test(); check_test_memory_usage(); + +#ifndef CONFIG_PTHREAD_MUTEX_UNSAFE + printf("\nuser_main: robust test\n"); + robust_test(); + check_test_memory_usage(); +#endif #endif #ifndef CONFIG_DISABLE_PTHREAD diff --git a/examples/ostest/robust.c b/examples/ostest/robust.c new file mode 100644 index 000000000..40eefc4c3 --- /dev/null +++ b/examples/ostest/robust.c @@ -0,0 +1,252 @@ +/**************************************************************************** + * examples/ostest/robust.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 "ostest.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static pthread_mutex_t g_robust_mutex; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static FAR void *robust_waiter(FAR void *parameter) +{ + int status; + + /* Take the mutex */ + + printf("robust_waiter: Taking mutex\n"); + status = pthread_mutex_lock(&g_robust_mutex); + if (status != 0) + { + printf("thread_waiter: ERROR: pthread_mutex_lock failed, status=%d\n", status); + } + + if (status != 0) + { + printf("robust_waiter: ERROR: pthread_mutex_lock failed, status=%d\n", status); + } + else + { + printf("robust_waiter: Exitting with mutex\n"); + } + + sleep(2); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void robust_test(void) +{ + pthread_attr_t pattr; + pthread_mutexattr_t mattr; + pthread_t waiter; + void *result; + int nerrors = 0; + int status; + + /* Initialize the mutex */ + + printf("robust_test: Initializing mutex\n"); + + status = pthread_mutexattr_init(&mattr); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutexattr_init failed, status=%d\n", + status); + nerrors++; + } + + status = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutexattr_setrobust failed, status=%d\n", + status); + nerrors++; + } + + status = pthread_mutex_init(&g_robust_mutex, &mattr); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_init failed, status=%d\n", + status); + nerrors++; + } + + /* Set up pthread attributes */ + + printf("robust_test: Starting thread\n"); + + status = pthread_attr_init(&pattr); + if (status != 0) + { + printf("robust_test: ERROR: pthread_attr_init failed, status=%d\n", + status); + nerrors++; + } + + status = pthread_attr_setstacksize(&pattr, STACKSIZE); + if (status != 0) + { + printf("robust_test: ERROR: pthread_attr_setstacksize failed, status=%d\n", + status); + nerrors++; + } + + /* Start the robust waiter thread. It will take the mutex, sleep for two + * seconds, and exit holding the mutex. + */ + + status = pthread_create(&waiter, &pattr, robust_waiter, NULL); + if (status != 0) + { + printf("robust_test: ERROR: pthread_create failed, status=%d\n", status); + printf(" ERROR: Terminating test\n"); + nerrors++; + return; + } + + /* Wait one second.. the robust waiter should still be waiting */ + + sleep(1); + + /* Now try to take the mutex held by the robust waiter. This should wait + * one second there fail with EOWNERDEAD. + */ + + status = pthread_mutex_lock(&g_robust_mutex); + if (status == 0) + { + printf("robust_test: ERROR: pthread_mutex_lock succeeded\n"); + nerrors++; + } + else if (status != EOWNERDEAD) + { + printf("robust_test: ERROR: pthread_mutex_lock failed with %d\n", status); + printf(" ERROR: expected %d (EOWNERDEAD)\n", EOWNERDEAD); + nerrors++; + } + + /* Try again, this should return immediately, still failing with EOWNERDEAD */ + + printf("robust_test: Take the lock again\n"); + status = pthread_mutex_lock(&g_robust_mutex); + if (status == 0) + { + printf("robust_test: ERROR: pthread_mutex_lock succeeded\n"); + nerrors++; + } + else if (status != EOWNERDEAD) + { + printf("robust_test: ERROR: pthread_mutex_lock failed with %d\n", status); + printf(" ERROR: expected %d (EOWNERDEAD)\n", EOWNERDEAD); + nerrors++; + } + + /* Make the mutex consistent and try again. It should succeed this time. */ + + printf("robust_test: Make the mutex consistent again.\n"); + status = pthread_mutex_consistent(&g_robust_mutex); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_consistent failed: %d\n", status); + nerrors++; + } + + printf("robust_test: Take the lock again\n"); + status = pthread_mutex_lock(&g_robust_mutex); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_lock failed with: %d\n", status); + nerrors++; + } + + /* Then join to the thread to pick up the result (if we don't do this we + * will have a memory leak!) + */ + + printf("robust_test: Joining\n"); + status = pthread_join(waiter, &result); + if (status != 0) + { + printf("robust_test: ERROR: pthread_join failed, status=%d\n", status); + nerrors++; + } + else + { + printf("robust_test: waiter exited with result=%p\n", result); + if (result != NULL) + { + printf("robust_test: ERROR: expected result=%p\n", PTHREAD_CANCELED); + nerrors++; + } + } + + /* Release and destory the mutex then return success */ + + status = pthread_mutex_unlock(&g_robust_mutex); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_unlock failed, status=%d\n", status); + nerrors++; + } + + status = pthread_mutex_destroy(&g_robust_mutex); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_unlock failed, status=%d\n", status); + nerrors++; + } + + printf("robust_test: Test complete with nerrors=%d\n", nerrors); +}