diff --git a/examples/ostest/Makefile b/examples/ostest/Makefile index 381ca1d33..7517cd87f 100644 --- a/examples/ostest/Makefile +++ b/examples/ostest/Makefile @@ -70,7 +70,7 @@ CSRCS += waitpid.c endif ifneq ($(CONFIG_DISABLE_PTHREAD),y) -CSRCS += cancel.c cond.c mutex.c sem.c semtimed.c barrier.c timedwait.c +CSRCS += cancel.c robust.c cond.c mutex.c sem.c semtimed.c barrier.c timedwait.c ifeq ($(CONFIG_FS_NAMED_SEMAPHORES),y) CSRCS += nsem.c diff --git a/examples/ostest/ostest.h b/examples/ostest/ostest.h index fdbde3165..351567494 100644 --- a/examples/ostest/ostest.h +++ b/examples/ostest/ostest.h @@ -177,6 +177,10 @@ void timedmqueue_test(void); void cancel_test(void); +/* robust.c *****************************************************************/ + +void robust_test(void); + /* timedwait.c **************************************************************/ void timedwait_test(void); diff --git a/examples/ostest/ostest_main.c b/examples/ostest/ostest_main.c index e35f91b41..595599ec5 100644 --- a/examples/ostest/ostest_main.c +++ b/examples/ostest/ostest_main.c @@ -387,6 +387,10 @@ static int user_main(int argc, char *argv[]) printf("\nuser_main: cancel test\n"); cancel_test(); check_test_memory_usage(); + + printf("\nuser_main: robust test\n"); + robust_test(); + check_test_memory_usage(); #endif #ifndef CONFIG_DISABLE_PTHREAD diff --git a/examples/ostest/robust.c b/examples/ostest/robust.c new file mode 100644 index 000000000..2d8383659 --- /dev/null +++ b/examples/ostest/robust.c @@ -0,0 +1,233 @@ +/**************************************************************************** + * 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 attr; + pthread_t waiter; + void *result; + int nerrors = 0; + int status; + + /* Initialize the mutex */ + + printf("robust_test: Initializing mutex\n"); + status = pthread_mutex_init(&g_robust_mutex, NULL); + if (status != 0) + { + printf("robust_test: ERROR: pthread_mutex_init failed, status=%d\n", + status); + nerrors++; + } + + /* Set up pthread attributes */ + + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("robust_test: ERROR: pthread_attr_init failed, status=%d\n", + status); + nerrors++; + } + + status = pthread_attr_setstacksize(&attr, 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. + */ + + printf("robust_test: Starting thread\n"); + status = pthread_create(&waiter, &attr, 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); +}