Added implementation of the pthread_cond_clockwait() method to cpukit/posix/src/condclockwait.c. Additional logic added to condwaitsupp.c to implement the new method. Pthread_cond_clockwait() has been added to the Issue 8 POSIX Standard.
psxcond03 test added to testsuites/psxtests to test the newly added method. --- cpukit/include/rtems/posix/condimpl.h | 9 +- cpukit/posix/src/condclockwait.c | 78 +++ cpukit/posix/src/condtimedwait.c | 3 +- cpukit/posix/src/condwait.c | 1 + cpukit/posix/src/condwaitsupp.c | 114 ++++- spec/build/testsuites/psxtests/grp.yml | 2 + spec/build/testsuites/psxtests/psxcond03.yml | 20 + testsuites/psxtests/Makefile.am | 9 + testsuites/psxtests/configure.ac | 1 + testsuites/psxtests/psxcond03/init.c | 466 ++++++++++++++++++ testsuites/psxtests/psxcond03/psxcond03.doc | 44 ++ testsuites/psxtests/psxcond03/psxcond03.scn | 3 + testsuites/psxtests/psxcond03/system.h | 61 +++ .../psxhdrs/pthread/pthread_cond_clockwait.c | 2 +- 14 files changed, 788 insertions(+), 25 deletions(-) create mode 100644 cpukit/posix/src/condclockwait.c create mode 100644 spec/build/testsuites/psxtests/psxcond03.yml create mode 100644 testsuites/psxtests/psxcond03/init.c create mode 100644 testsuites/psxtests/psxcond03/psxcond03.doc create mode 100644 testsuites/psxtests/psxcond03/psxcond03.scn create mode 100644 testsuites/psxtests/psxcond03/system.h diff --git a/cpukit/include/rtems/posix/condimpl.h b/cpukit/include/rtems/posix/condimpl.h index 66e09bf6d8..c49fbb24d4 100644 --- a/cpukit/include/rtems/posix/condimpl.h +++ b/cpukit/include/rtems/posix/condimpl.h @@ -39,6 +39,8 @@ typedef struct { #define POSIX_CONDITION_VARIABLES_MAGIC 0x18dfb1feUL +#define CLOCK_NOT_SPECIFIED 0xdeadbeef + /** * Constant to indicate condition variable does not currently have * a mutex assigned to it. @@ -150,9 +152,10 @@ int _POSIX_Condition_variables_Signal_support( * timed wait version of condition variable wait routines. */ int _POSIX_Condition_variables_Wait_support( - pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec *abstime + pthread_cond_t *restrict cond, + pthread_mutex_t *restrict mutex, + clockid_t clock_id, + const struct timespec *restrict abstime ); bool _POSIX_Condition_variables_Auto_initialization( diff --git a/cpukit/posix/src/condclockwait.c b/cpukit/posix/src/condclockwait.c new file mode 100644 index 0000000000..ebc95c86b4 --- /dev/null +++ b/cpukit/posix/src/condclockwait.c @@ -0,0 +1,78 @@ +/** + * @file + * + * @ingroup POSIXAPI + * + * @brief Waiting on a Condition + */ + +/* +* Copyright (C) 2021 Matthew Joyce +* +* 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. +* +* 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. +*/ + +/* Defining to have access to function prototype in libc/include/pthread.h */ +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/posix/condimpl.h> +#include <rtems/score/todimpl.h> + +/* + * pthread_cond_clockwait() appears in the Issue 8 POSIX Standard + */ +int pthread_cond_clockwait( + pthread_cond_t *restrict cond, + pthread_mutex_t *restrict mutex, + clockid_t clock_id, + const struct timespec *restrict abstime +) +{ + /* + * POSIX Issue 8 does not specify that EINVAL is returned when abstime + * equals NULL. + */ + if ( abstime == NULL ) { + return EINVAL; + } + + /* + * POSIX Issue 8 specifies that EINVAL is returned when the clock is not + * supported. + */ + if ( clock_id != CLOCK_REALTIME ) { + if ( clock_id != CLOCK_MONOTONIC ) { + return EINVAL; + } + } + + return _POSIX_Condition_variables_Wait_support( + cond, + mutex, + clock_id, + abstime + ); +} diff --git a/cpukit/posix/src/condtimedwait.c b/cpukit/posix/src/condtimedwait.c index 0bc8bfc18e..cefd1d6cb6 100644 --- a/cpukit/posix/src/condtimedwait.c +++ b/cpukit/posix/src/condtimedwait.c @@ -36,8 +36,9 @@ int pthread_cond_timedwait( return EINVAL; /* not specified */ } return _POSIX_Condition_variables_Wait_support( - cond, + cond, mutex, + CLOCK_NOT_SPECIFIED, abstime ); } diff --git a/cpukit/posix/src/condwait.c b/cpukit/posix/src/condwait.c index 09431e216d..85ca8e27c7 100644 --- a/cpukit/posix/src/condwait.c +++ b/cpukit/posix/src/condwait.c @@ -54,6 +54,7 @@ int pthread_cond_wait( return _POSIX_Condition_variables_Wait_support( cond, mutex, + CLOCK_NOT_SPECIFIED, NULL ); } diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c index ee2f8a0787..01d5ca9794 100644 --- a/cpukit/posix/src/condwaitsupp.c +++ b/cpukit/posix/src/condwaitsupp.c @@ -26,6 +26,57 @@ #include <rtems/score/status.h> #include <rtems/score/threaddispatch.h> +#ifdef CLOCK_REALTIME_COARSE + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_REALTIME_COARSE), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_PROCESS_CPUTIME_ID), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_REALTIME + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_REALTIME), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_THREAD_CPUTIME_ID), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_MONOTONIC + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_MONOTONIC), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_MONOTONIC_RAW + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_MONOTONIC_RAW), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_MONOTONIC_COARSE + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_MONOTONIC_COARSE), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_BOOTTIME + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_BOOTTIME), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_REALTIME_ALARM + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_REALTIME_ALARM), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif +#ifdef CLOCK_BOOTTIME_ALARM + RTEMS_STATIC_ASSERT( + ( CLOCK_NOT_SPECIFIED != CLOCK_BOOTTIME_ALARM), + "CLOCK_NOT_SPECIFIED conflicts with existing POSIX defined clock/n" ); +#endif + static void _POSIX_Condition_variables_Mutex_unlock( Thread_queue_Queue *queue, Thread_Control *the_thread, @@ -92,37 +143,66 @@ static void _POSIX_Condition_variables_Enqueue_with_timeout_realtime( } int _POSIX_Condition_variables_Wait_support( - pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec *abstime + pthread_cond_t *restrict cond, + pthread_mutex_t *restrict mutex, + clockid_t clock_id, + const struct timespec *restrict abstime ) { POSIX_Condition_variables_Control *the_cond; - unsigned long flags; - Thread_queue_Context queue_context; - int error; + unsigned long flags; + Thread_queue_Context queue_context; + int error; Thread_Control *executing; + pthread_condattr_t attr; the_cond = _POSIX_Condition_variables_Get( cond ); POSIX_CONDITION_VARIABLES_VALIDATE_OBJECT( the_cond, flags ); _Thread_queue_Context_initialize( &queue_context ); - if ( abstime != NULL ) { - _Thread_queue_Context_set_timeout_argument( &queue_context, abstime, true ); + _Thread_queue_Context_set_timeout_argument( &queue_context, abstime, true ); + + error = pthread_condattr_init( &attr ); + _Assert( error == 0 ); - if ( _POSIX_Condition_variables_Get_clock( flags ) == CLOCK_MONOTONIC ) { + /* + * If the parameter clock_id is not specified, then the clock from the + * condition attributes shall be used. + */ + if ( clock_id == CLOCK_NOT_SPECIFIED ) { + error = pthread_condattr_getclock( &attr, &clock_id ); + _Assert( error == 0 ); + } + + /* + * Now we have the desired clock_id, whether it came from cond_timedwait or + * cond_clockwait. If abstime is specified, we use the clock_id to set the + * correct timeout. + */ + if ( abstime != NULL ) { + /* + * We have already validated supported clocks in condclockwait.c. + * if clock_id is not CLOCK_MONOTONIC, then it is CLOCK_REALTIME. + */ + if ( clock_id == CLOCK_MONOTONIC ) { _Thread_queue_Context_set_enqueue_callout( &queue_context, _POSIX_Condition_variables_Enqueue_with_timeout_monotonic ); } else { - _Thread_queue_Context_set_enqueue_callout( + _Thread_queue_Context_set_enqueue_callout( &queue_context, _POSIX_Condition_variables_Enqueue_with_timeout_realtime - ); - } - } else { + ); + } + } + + /* + * Otherwise, if the abstime parameter is NULL, this is a call to + * pthread_cond_wait and no timeout is necessary. + */ + else { _Thread_queue_Context_set_enqueue_callout( &queue_context, _POSIX_Condition_variables_Enqueue_no_timeout @@ -138,9 +218,7 @@ int _POSIX_Condition_variables_Wait_support( _POSIX_Condition_variables_Release( the_cond, &queue_context ); return EINVAL; } - the_cond->mutex = mutex; - _Thread_queue_Context_set_thread_state( &queue_context, STATES_WAITING_FOR_CONDITION_VARIABLE @@ -151,8 +229,8 @@ int _POSIX_Condition_variables_Wait_support( executing, &queue_context ); - error = _POSIX_Get_error_after_wait( executing ); + error = _POSIX_Get_error_after_wait( executing ); /* * If the thread is interrupted, while in the thread queue, by * a POSIX signal, then pthread_cond_wait returns spuriously, @@ -160,15 +238,12 @@ int _POSIX_Condition_variables_Wait_support( * returns a success status, except for the fact that it was not * woken up a pthread_cond_signal() or a pthread_cond_broadcast(). */ - if ( error == EINTR ) { error = 0; } - /* * When we get here the dispatch disable level is 0. */ - if ( error != EPERM ) { int mutex_error; @@ -178,6 +253,5 @@ int _POSIX_Condition_variables_Wait_support( error = EINVAL; } } - return error; } diff --git a/spec/build/testsuites/psxtests/grp.yml b/spec/build/testsuites/psxtests/grp.yml index fb7ce465ae..dc55c05124 100644 --- a/spec/build/testsuites/psxtests/grp.yml +++ b/spec/build/testsuites/psxtests/grp.yml @@ -87,6 +87,8 @@ links: uid: psxcond01 - role: build-dependency uid: psxcond02 +- role: build-dependency + uid: psxcond03 - role: build-dependency uid: psxconfig01 - role: build-dependency diff --git a/spec/build/testsuites/psxtests/psxcond03.yml b/spec/build/testsuites/psxtests/psxcond03.yml new file mode 100644 index 0000000000..c0d53eb04e --- /dev/null +++ b/spec/build/testsuites/psxtests/psxcond03.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +cppflags: [] +cxxflags: [] +enabled-by: true +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/psxtests/psxcond03/init.c +- cpukit/posix/src/condclockwait.c +stlib: [] +target: testsuites/psxtests/psxcond03.exe +type: build +use-after: [] +use-before: [] \ No newline at end of file diff --git a/testsuites/psxtests/Makefile.am b/testsuites/psxtests/Makefile.am index a35f00b665..de1a87b05f 100755 --- a/testsuites/psxtests/Makefile.am +++ b/testsuites/psxtests/Makefile.am @@ -349,6 +349,15 @@ psxcond02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxcond02) \ $(support_includes) -I$(top_srcdir)/include endif +if TEST_psxcond03 +psx_tests += psxcond03 +psx_screens += psxcond03/psxcond03.scn +psx_docs += psxcond03/psxcond03.doc +psxcond03_SOURCES = psxcond03/init.c psxcond03/system.h include/pmacros.h +psxcond03_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxcond03) \ + $(support_includes) -I$(top_srcdir)/include +endif + if TEST_psxconfig01 psx_tests += psxconfig01 psx_screens += psxconfig01/psxconfig01.scn diff --git a/testsuites/psxtests/configure.ac b/testsuites/psxtests/configure.ac index 3f95010cd3..d88f52a846 100644 --- a/testsuites/psxtests/configure.ac +++ b/testsuites/psxtests/configure.ac @@ -79,6 +79,7 @@ RTEMS_TEST_CHECK([psxclockrealtime01]) RTEMS_TEST_CHECK([psxconcurrency01]) RTEMS_TEST_CHECK([psxcond01]) RTEMS_TEST_CHECK([psxcond02]) +RTEMS_TEST_CHECK([psxcond03]) RTEMS_TEST_CHECK([psxconfig01]) RTEMS_TEST_CHECK([psxdevctl01]) RTEMS_TEST_CHECK([psxeintr_join]) diff --git a/testsuites/psxtests/psxcond03/init.c b/testsuites/psxtests/psxcond03/init.c new file mode 100644 index 0000000000..54d5d5c7a4 --- /dev/null +++ b/testsuites/psxtests/psxcond03/init.c @@ -0,0 +1,466 @@ +/* +* Copyright (C) 2021 Matthew Joyce +* +* 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. +* +* 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. +*/ + +/* Defining in order to access pthread_cond_clockwait in pthread.h */ +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CONFIGURE_INIT +#include <pthread.h> +#include <sched.h> +#include <errno.h> +#include <rtems.h> +#include <tmacros.h> +#include "system.h" + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_cond_t bad_cond; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t bad_mutex; +pthread_mutex_t new_mutex = PTHREAD_MUTEX_INITIALIZER; +clockid_t clock_id1 = CLOCK_MONOTONIC; +clockid_t clock_id2 = CLOCK_REALTIME; +clockid_t clock_id3 = CLOCK_MONOTONIC_RAW; +int count; +int eno; +int status; +const char rtems_test_name[] = "PSXCOND 3"; + +void *POSIX_Init( + void *argument +) +{ + TEST_BEGIN(); + pthread_t t1; + struct timespec abstime; + + /* Expected pass: Clock Monotonic with sufficient abstime */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Clock Monotonic with insufficient abstime */ + abstime.tv_sec = 0; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == ETIMEDOUT ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected pass: Clock Realtime with sufficient abstime */ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec += 4; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Clock Realtime with insufficient abstime */ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec = 0; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == ETIMEDOUT ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Unsupported Clock */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id3, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == EINVAL ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Invalid Clock */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, (int)NULL, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == EINVAL ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Invalid Clock */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &mutex, clock_id1, NULL ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == EINVAL ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Invalid Clock */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( NULL, &mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == EINVAL ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Invalid Mutex */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, NULL, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno != 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Uninitialized condition variable */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &bad_cond, &mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno != 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Uninitialized condition variable */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &bad_mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno != 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Uninitialized condition variable */ + abstime.tv_sec = 2; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &bad_cond, &mutex, clock_id1, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno != 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected pass: Binding new mutex to condition variable */ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec += 4; + abstime.tv_nsec = 1; + status = pthread_create( &t1, NULL, thread_func2, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &new_mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected fail: Timeout (abstime < current time) */ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec -= 1; + abstime.tv_nsec -= 1; + status = pthread_create( &t1, NULL, thread_func2, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &new_mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == ETIMEDOUT ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected Pass: Sufficient abstime to exceed sleep in thread_func3*/ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec += 4; + abstime.tv_nsec += 1; + status = pthread_create( &t1, NULL, thread_func3, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &new_mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == 0 ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + /* Expected Fail: Insufficient abstime to exceed sleep in thread_func3*/ + status = clock_gettime( clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + abstime.tv_sec += 2; + abstime.tv_nsec += 1; + status = pthread_create( &t1, NULL, thread_func3, NULL ); + rtems_test_assert( status == 0 ); + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + while ( count == 0 ){ + eno = pthread_cond_clockwait( &cond, &new_mutex, clock_id2, &abstime ); + if ( eno != 0 ) { + break; + } + } + + count -= 1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + rtems_test_assert( eno == ETIMEDOUT ); + status = pthread_join( t1, NULL ); + rtems_test_assert( status == 0 ); + + TEST_END(); + rtems_test_exit( 0 ); + return NULL; +} + +void *thread_func( void *arg ) +{ + int status; + + status = pthread_mutex_lock( &mutex ); + rtems_test_assert( status == 0 ); + if (count == 0) { + status = pthread_cond_signal( &cond ); + rtems_test_assert( status == 0 ); + } + + count +=1; + status = pthread_mutex_unlock( &mutex ); + rtems_test_assert( status == 0 ); + return NULL; +} + +void *thread_func2( void *arg ) +{ + int status; + + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + if ( count == 0 ) { + status = pthread_cond_signal( &cond ); + rtems_test_assert( status == 0 ); + } + + count +=1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + return NULL; +} + +void *thread_func3( void *arg ) +{ + int status; + + status = pthread_mutex_lock( &new_mutex ); + rtems_test_assert( status == 0 ); + /* Arbitrary sleep to test timeout functionality */ + sleep(3); + if ( count == 0 ) { + status = pthread_cond_signal( &cond ); + rtems_test_assert( status == 0 ); + } + + count +=1; + status = pthread_mutex_unlock( &new_mutex ); + rtems_test_assert( status == 0 ); + return NULL; +} diff --git a/testsuites/psxtests/psxcond03/psxcond03.doc b/testsuites/psxtests/psxcond03/psxcond03.doc new file mode 100644 index 0000000000..4e9b582189 --- /dev/null +++ b/testsuites/psxtests/psxcond03/psxcond03.doc @@ -0,0 +1,44 @@ +/* +* Copyright (C) 2021 Matthew Joyce +* +* 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. +* +* 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. +*/ + +This file describes the directives and concepts tested by this test set. + +test set name: psxcond03 + +directives: + + pthread_cond_clockwait + pthread_create + pthread_mutex_lock + pthread_mutex_unlock + pthread_cond_signal + pthread_join + +concepts: + ++ Tests the newly-added Issue 8 POSIX Standard pthread_cond_clockwait method. + Tests include valid/supported and invalid/unsupported clocks, sufficient and + insufficient timeouts, and invalid or uninitialized condition/mutex + parameters. diff --git a/testsuites/psxtests/psxcond03/psxcond03.scn b/testsuites/psxtests/psxcond03/psxcond03.scn new file mode 100644 index 0000000000..5935b1d478 --- /dev/null +++ b/testsuites/psxtests/psxcond03/psxcond03.scn @@ -0,0 +1,3 @@ +*** BEGIN OF TEST PSXCOND 3 *** + +*** END OF TEST PSXCOND 3 *** diff --git a/testsuites/psxtests/psxcond03/system.h b/testsuites/psxtests/psxcond03/system.h new file mode 100644 index 0000000000..b9dcb832ad --- /dev/null +++ b/testsuites/psxtests/psxcond03/system.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2021 Matthew Joyce +* +* 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. +* +* 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. +*/ + +/* functions */ + +#include <pmacros.h> +#include <unistd.h> +#include <errno.h> + +void *POSIX_Init( + void *argument +); + +void *thread_func( + void *argument +); + +void *thread_func2( + void *argument +); + +void *thread_func3( + void *argument +); + +/* configuration information */ + +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_MAXIMUM_POSIX_THREADS 4 + +#define CONFIGURE_POSIX_INIT_THREAD_TABLE + +#include <rtems/confdefs.h> + +/* end of include file */ diff --git a/testsuites/psxtests/psxhdrs/pthread/pthread_cond_clockwait.c b/testsuites/psxtests/psxhdrs/pthread/pthread_cond_clockwait.c index 15485eb587..fe91b7954f 100644 --- a/testsuites/psxtests/psxhdrs/pthread/pthread_cond_clockwait.c +++ b/testsuites/psxtests/psxhdrs/pthread/pthread_cond_clockwait.c @@ -49,7 +49,7 @@ int test( void ) pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; clockid_t clock_id = CLOCK_REALTIME; struct timespec abstime; - abstime.tv_sec = 2; + abstime.tv_sec = 1; int result; /* This method appeared in the Issue 8 POSIX Standard */ -- 2.31.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel