Added implementations of the pthread_rwlock_clockrdlock and the pthread_rwlock_clockwrlock methods to cpukit/posix/src. Both of these methods have been newly added to the POSIX Issue 8 Standard.
psxrwlock02 test added to testsuites/psxtests to test the newly added methods. --- cpukit/posix/src/prwlockclockrdlock.c | 70 ++ cpukit/posix/src/prwlockclockwrlock.c | 71 ++ spec/build/testsuites/psxtests/grp.yml | 2 + .../build/testsuites/psxtests/psxrwlock02.yml | 22 + testsuites/psxtests/Makefile.am | 9 + testsuites/psxtests/configure.ac | 1 + testsuites/psxtests/psxrwlock02/main.c | 55 ++ testsuites/psxtests/psxrwlock02/test.c | 750 ++++++++++++++++++ 8 files changed, 980 insertions(+) create mode 100644 cpukit/posix/src/prwlockclockrdlock.c create mode 100644 cpukit/posix/src/prwlockclockwrlock.c create mode 100644 spec/build/testsuites/psxtests/psxrwlock02.yml create mode 100644 testsuites/psxtests/psxrwlock02/main.c create mode 100644 testsuites/psxtests/psxrwlock02/test.c diff --git a/cpukit/posix/src/prwlockclockrdlock.c b/cpukit/posix/src/prwlockclockrdlock.c new file mode 100644 index 0000000000..d7187ebfb7 --- /dev/null +++ b/cpukit/posix/src/prwlockclockrdlock.c @@ -0,0 +1,70 @@ +/** + * @file + * + * @ingroup POSIXAPI + * + * @brief Attempt to Obtain a Read Lock on a RWLock Instance + */ + +/* + * POSIX RWLock Manager -- Attempt to Obtain a Read Lock on a RWLock Instance. + * The timeout is specified by abstime on the clock specified by clock_id. + * + * COPYRIGHT (c) 2021 Matthew Joyce + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/* 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/rwlockimpl.h> +#include <rtems/posix/posixapi.h> + +/* The POSIX Issue 8 Standard adds pthread_rwlock_clockrdlock */ +int pthread_rwlock_clockrdlock( + pthread_rwlock_t *rwlock, + clockid_t clock_id, + const struct timespec *abstime +) +{ + POSIX_RWLock_Control *the_rwlock; + Thread_queue_Context queue_context; + Status_Control status; + + the_rwlock = _POSIX_RWLock_Get( rwlock ); + POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); + + _Thread_queue_Context_initialize( &queue_context ); + + if ( clock_id == CLOCK_REALTIME ) { + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime, + true + ); + } + + if ( clock_id == CLOCK_MONOTONIC ) { + _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + &queue_context, + abstime, + true + ); + } + + status = _CORE_RWLock_Seize_for_reading( + &the_rwlock->RWLock, + true, + &queue_context + ); + return _POSIX_Get_error( status ); +} diff --git a/cpukit/posix/src/prwlockclockwrlock.c b/cpukit/posix/src/prwlockclockwrlock.c new file mode 100644 index 0000000000..c0ed7fe01c --- /dev/null +++ b/cpukit/posix/src/prwlockclockwrlock.c @@ -0,0 +1,71 @@ +/** + * @file + * + * @ingroup POSIXAPI + * + * @brief Attempt to Obtain a Write lock on a RWLock instance + */ + +/* + * POSIX RWLock Manager -- Attempt to Obtain a Write Lock on a RWLock Instance + * The timeout is specified by abstime on the clock specified by clock_id. + * + * COPYRIGHT (c) 2021 Matthew Joyce + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/* 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/rwlockimpl.h> +#include <rtems/posix/posixapi.h> + + +/* The POSIX Issue 8 Standard adds pthread_rwlock_clockwrlock */ +int pthread_rwlock_clockwrlock( + pthread_rwlock_t *rwlock, + clockid_t clock_id, + const struct timespec *abstime +) +{ + POSIX_RWLock_Control *the_rwlock; + Thread_queue_Context queue_context; + Status_Control status; + + the_rwlock = _POSIX_RWLock_Get( rwlock ); + POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); + + _Thread_queue_Context_initialize( &queue_context ); + + if ( clock_id == CLOCK_REALTIME ) { + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime, + true + ); + } + + if ( clock_id == CLOCK_MONOTONIC ) { + _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + &queue_context, + abstime, + true + ); + } + + status = _CORE_RWLock_Seize_for_writing( + &the_rwlock->RWLock, + true, + &queue_context + ); + return _POSIX_Get_error( status ); +} diff --git a/spec/build/testsuites/psxtests/grp.yml b/spec/build/testsuites/psxtests/grp.yml index fb7ce465ae..51b8d1d758 100644 --- a/spec/build/testsuites/psxtests/grp.yml +++ b/spec/build/testsuites/psxtests/grp.yml @@ -183,6 +183,8 @@ links: uid: psxreaddir - role: build-dependency uid: psxrwlock01 +- role: build-dependency + uid: psxrwlock02 - role: build-dependency uid: psxsem01 - role: build-dependency diff --git a/spec/build/testsuites/psxtests/psxrwlock02.yml b/spec/build/testsuites/psxtests/psxrwlock02.yml new file mode 100644 index 0000000000..35244d3e03 --- /dev/null +++ b/spec/build/testsuites/psxtests/psxrwlock02.yml @@ -0,0 +1,22 @@ +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/psxrwlock02/main.c +- testsuites/psxtests/psxrwlock02/test.c +- cpukit/posix/src/prwlockclockrdlock.c +- cpukit/posix/src/prwlockclockwrlock.c +stlib: [] +target: testsuites/psxtests/psxrwlock02.exe +type: build +use-after: [] +use-before: [] diff --git a/testsuites/psxtests/Makefile.am b/testsuites/psxtests/Makefile.am index a35f00b665..6e3c30a012 100755 --- a/testsuites/psxtests/Makefile.am +++ b/testsuites/psxtests/Makefile.am @@ -811,6 +811,15 @@ psxrwlock01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxrwlock01) \ $(support_includes) -I$(top_srcdir)/include endif +if TEST_psxrwlock02 +psx_tests += psxrwlock02 +psx_screens += psxrwlock02/psxrwlock02.scn +psxrwlock02_SOURCES = psxrwlock02/main.c psxrwlock02/test.c \ + include/pmacros.h +psxrwlock02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxrwlock02) \ + $(support_includes) -I$(top_srcdir)/include +endif + if TEST_psxsem01 psx_tests += psxsem01 psx_screens += psxsem01/psxsem01.scn diff --git a/testsuites/psxtests/configure.ac b/testsuites/psxtests/configure.ac index 3f95010cd3..a49f809d54 100644 --- a/testsuites/psxtests/configure.ac +++ b/testsuites/psxtests/configure.ac @@ -127,6 +127,7 @@ RTEMS_TEST_CHECK([psxpipe01]) RTEMS_TEST_CHECK([psxrdwrv]) RTEMS_TEST_CHECK([psxreaddir]) RTEMS_TEST_CHECK([psxrwlock01]) +RTEMS_TEST_CHECK([psxrwlock02]) RTEMS_TEST_CHECK([psxsem01]) RTEMS_TEST_CHECK([psxshm01]) RTEMS_TEST_CHECK([psxshm02]) diff --git a/testsuites/psxtests/psxrwlock02/main.c b/testsuites/psxtests/psxrwlock02/main.c new file mode 100644 index 0000000000..d71218bfff --- /dev/null +++ b/testsuites/psxtests/psxrwlock02/main.c @@ -0,0 +1,55 @@ +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/test-info.h> +#include <bsp.h> +#include <pmacros.h> + +/* forward declarations to avoid warnings */ +rtems_task Init(rtems_task_argument ignored); +void test_main(void); + +rtems_task Init( + rtems_task_argument ignored +) +{ + test_main(); + rtems_test_exit( 0 ); +} + +/* configuration information */ + +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_MAXIMUM_POSIX_THREADS 2 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE +#define CONFIGURE_INIT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2) +#define CONFIGURE_INIT_TASK_PRIORITY 2 +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_PREEMPT + +#define CONFIGURE_EXTRA_TASK_STACKS RTEMS_MINIMUM_STACK_SIZE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> + +/* end of file */ diff --git a/testsuites/psxtests/psxrwlock02/test.c b/testsuites/psxtests/psxrwlock02/test.c new file mode 100644 index 0000000000..50e58c5402 --- /dev/null +++ b/testsuites/psxtests/psxrwlock02/test.c @@ -0,0 +1,750 @@ +/** + * @file + * + * This test exercises the POSIX RWLock manager. + */ + +/* COPYRIGHT (c) 2021 Matthew Joyce + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/* Defining to have access to function prototype in libc/include/pthread.h */ +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tmacros.h" +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> + +/* #define __USE_XOPEN2K XXX already defined on GNU/Linux */ +#include <pthread.h> + +const char rtems_test_name[] = "PSXRWLOCK 2"; + +/* forward declarations to avoid warnings */ +void *ReadLockThread(void *arg); +void *WriteLockThread(void *arg); +int test_main(void); + +#define NUMBER_THREADS 2 +pthread_t ThreadIds[NUMBER_THREADS]; +pthread_rwlock_t RWLock; +clockid_t clock_id = CLOCK_MONOTONIC; +clockid_t clock_id2 = CLOCK_REALTIME; + +/* + * Test thread to block for read lock and unlock it + */ +void *ReadLockThread(void *arg) +{ + int status; + + /* + * Detach ourselves so we don't wait for a join that won't happen. + */ + pthread_detach( pthread_self() ); + + status = pthread_rwlock_rdlock(&RWLock); + rtems_test_assert( !status ); + + status = pthread_rwlock_unlock(&RWLock); + rtems_test_assert( !status ); + return NULL; +} + +/* + * Test thread to block for write lock and unlock it + */ +void *WriteLockThread(void *arg) +{ + int status; + + /* + * Detach ourselves so we don't wait for a join that won't happen. + */ + pthread_detach( pthread_self() ); + + status = pthread_rwlock_wrlock(&RWLock); + rtems_test_assert( !status ); + + sleep( 2 ); + + status = pthread_rwlock_unlock(&RWLock); + if ( status ) + printf( "status=%s\n", strerror(status) ); + rtems_test_assert( !status ); + return NULL; +} + +static void test_rwlock_pshared_init(void) +{ + pthread_rwlock_t rwlock; + pthread_rwlockattr_t attr; + int eno; + + eno = pthread_rwlockattr_init( &attr ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlockattr_setpshared( &attr, PTHREAD_PROCESS_PRIVATE ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_init( &rwlock, &attr ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_destroy( &rwlock ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlockattr_setpshared( &attr, PTHREAD_PROCESS_SHARED ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_init( &rwlock, &attr ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_destroy(&rwlock); + rtems_test_assert( eno == 0 ); + + attr.process_shared = -1; + + eno = pthread_rwlock_init( &rwlock, &attr ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlockattr_destroy( &attr ); + rtems_test_assert( eno == 0 ); +} + +static void test_rwlock_null( void ) +{ + struct timespec to; + int eno; + + eno = pthread_rwlock_destroy( NULL ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_init( NULL, NULL ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_rdlock( NULL ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( NULL, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( NULL, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( NULL, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( NULL, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_tryrdlock( NULL ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_trywrlock( NULL ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_unlock( NULL ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_wrlock( NULL ); + rtems_test_assert( eno == EINVAL ); +} + +static void test_rwlock_not_initialized( void ) +{ + pthread_rwlock_t rw; + struct timespec to; + int eno; + + memset( &rw, 0xff, sizeof( rw ) ); + + eno = pthread_rwlock_destroy( &rw ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_rdlock( &rw ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_tryrdlock( &rw ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_trywrlock( &rw ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_unlock( &rw ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_wrlock( &rw ); + rtems_test_assert( eno == EINVAL ); +} + +static void test_rwlock_invalid_copy( void ) +{ + pthread_rwlock_t rw; + pthread_rwlock_t rw2; + struct timespec to; + int eno; + + eno = pthread_rwlock_init( &rw, NULL ); + rtems_test_assert( eno == 0 ); + + memcpy( &rw2, &rw, sizeof( rw2 ) ); + + eno = pthread_rwlock_destroy( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_rdlock( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw2, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw2, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw2, clock_id, &to ); + rtems_test_assert( eno == EINVAL ); + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw2, clock_id2, &to ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_tryrdlock( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_trywrlock( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_unlock( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_wrlock( &rw2 ); + rtems_test_assert( eno == EINVAL ); + + eno = pthread_rwlock_destroy( &rw ); + rtems_test_assert( eno == 0 ); +} + +static void test_rwlock_auto_initialization( void ) +{ + struct timespec to; + int eno; + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_destroy( &rw ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_destroy( &rw ); + rtems_test_assert( eno == EINVAL ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_rdlock( &rw ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_unlock( &rw ); + rtems_test_assert( eno == 0 ); + + eno = pthread_rwlock_destroy( &rw ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw, clock_id, &to ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockrdlock( &rw, clock_id2, &to ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw, clock_id, &to ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + to.tv_sec = 1; + to.tv_nsec = 1; + eno = pthread_rwlock_clockwrlock( &rw, clock_id2, &to ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_tryrdlock( &rw ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_trywrlock( &rw ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_unlock( &rw ); + rtems_test_assert( eno == 0 ); + } + + { + static pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + + eno = pthread_rwlock_wrlock( &rw ); + rtems_test_assert( eno == 0 ); + } +} + +/* + * main entry point to the test + */ + +#if defined(__rtems__) +int test_main(void) +#else +int main( + int argc, + char **argv +) +#endif +{ + pthread_rwlock_t rwlock; + pthread_rwlockattr_t attr; + int status; + int p; + int i; + struct timespec abstime; + + TEST_BEGIN(); + + test_rwlock_pshared_init(); + test_rwlock_null(); + test_rwlock_not_initialized(); + test_rwlock_invalid_copy(); + test_rwlock_auto_initialization(); + + /*************** NULL POINTER CHECKS *****************/ + status = pthread_rwlockattr_init( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_setpshared( NULL, PTHREAD_PROCESS_PRIVATE ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_setpshared( NULL, PTHREAD_PROCESS_SHARED ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_getpshared( NULL, &p ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_destroy( NULL ); + rtems_test_assert( status == EINVAL ); + + /*************** NOT INITIALIZED CHECKS *****************/ + /* cheat visibility */ + attr.is_initialized = 0; + status = pthread_rwlockattr_setpshared( &attr, PTHREAD_PROCESS_SHARED ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_getpshared( &attr, NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlockattr_destroy( &attr ); + rtems_test_assert( status == EINVAL ); + + /*************** BAD PSHARED CHECK *****************/ + status = pthread_rwlockattr_setpshared( &attr, ~PTHREAD_PROCESS_PRIVATE ); + rtems_test_assert( status == EINVAL ); + + /*************** ACTUALLY WORK THIS TIME *****************/ + status = pthread_rwlockattr_init( &attr ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlockattr_setpshared( &attr, PTHREAD_PROCESS_PRIVATE ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlockattr_getpshared( &attr, &p ); + rtems_test_assert( status == 0 ); + rtems_test_assert( p == PTHREAD_PROCESS_PRIVATE ); + + status = pthread_rwlockattr_setpshared( &attr, PTHREAD_PROCESS_SHARED ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlockattr_getpshared( &attr, &p ); + rtems_test_assert( status == 0 ); + rtems_test_assert( p == PTHREAD_PROCESS_SHARED ); + + /*************** DESTROY/REUSE CHECK *****************/ + status = pthread_rwlockattr_destroy( &attr ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlockattr_getpshared( &attr, &p ); + rtems_test_assert( status == EINVAL ); + + /*************** NULL ARGUMENT CHECKS *****************/ + abstime.tv_sec = 0; + abstime.tv_nsec = 0; + + status = pthread_rwlock_init(NULL, &attr); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_destroy(NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_rdlock(NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( NULL, clock_id, &abstime); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( &rwlock, clock_id, NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( NULL, clock_id2, &abstime); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( &rwlock, clock_id2, NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_tryrdlock(NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_wrlock(NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( NULL, clock_id, &abstime ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( &rwlock, clock_id, NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( NULL, clock_id2, &abstime ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( &rwlock, clock_id2, NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_trywrlock(NULL); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_unlock(NULL); + rtems_test_assert( status == EINVAL ); + + /*************** BAD ID CHECK *****************/ + /* make a valid abstime */ + status = clock_gettime( CLOCK_REALTIME, &abstime ); + rtems_test_assert( !status ); + abstime.tv_sec += 5; + + status = pthread_rwlock_destroy( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_rdlock( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( NULL, clock_id, &abstime); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockrdlock( NULL, clock_id2, &abstime); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_tryrdlock( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_wrlock( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( NULL, clock_id, &abstime ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_clockwrlock( NULL, clock_id2, &abstime ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_trywrlock( NULL ); + rtems_test_assert( status == EINVAL ); + + status = pthread_rwlock_unlock( NULL ); + rtems_test_assert( status == EINVAL ); + + /*************** ACTUALLY CREATE ONE CHECK *****************/ + status = pthread_rwlockattr_init( &attr ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_init( &rwlock, &attr ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_destroy( &rwlock ); + rtems_test_assert( status == 0 ); + + /********* CREATE RWLOCK WITH DEFAULT ATTRIBUTES AND DESTROY IT *********/ + status = pthread_rwlock_init( &rwlock, NULL ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_destroy( &rwlock ); + rtems_test_assert( status == 0 ); + + /*************** CREATE THREADS AND LET THEM OBTAIN READLOCK ***************/ + status = pthread_rwlock_init( &RWLock, &attr ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_tryrdlock( &RWLock ); + rtems_test_assert( !status ); + + for (i=0 ; i<NUMBER_THREADS ; i++ ) { + status = + pthread_create(&ThreadIds[i], NULL, ReadLockThread, &ThreadIds[i]); + rtems_test_assert( !status ); + + sleep(1); + } + + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + sleep(1); + + /*************** CREATE THREADS AND LET THEM OBTAIN READLOCK ***************/ + status = pthread_rwlock_trywrlock( &RWLock ); + rtems_test_assert( !status ); + + status = pthread_rwlock_tryrdlock( &RWLock ); + rtems_test_assert( status == EBUSY ); + + for (i=0 ; i<NUMBER_THREADS ; i++ ) { + status = + pthread_create(&ThreadIds[i], NULL, ReadLockThread, &ThreadIds[i]); + rtems_test_assert( !status ); + + sleep(1); + } + + /* Attempt delete while threads are blocked */ + status = pthread_rwlock_destroy( &RWLock ); + rtems_test_assert( status == EBUSY ); + + /* now unlock it so the threads can continue */ + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + sleep(2); + + /*************** CREATE THREADS AND LET THEM OBTAIN WRITE LOCK *************/ + status = pthread_rwlock_trywrlock( &RWLock ); + rtems_test_assert( !status ); + + status = pthread_rwlock_trywrlock( &RWLock ); + rtems_test_assert( status == EBUSY ); + + for (i=0 ; i<NUMBER_THREADS ; i++ ) { + status = + pthread_create(&ThreadIds[i], NULL, WriteLockThread, &ThreadIds[i]); + rtems_test_assert( !status ); + + sleep(2); + } + + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + sleep(6); + + /*************** CREATE THREADS AND LET THEM OBTAIN WRITE LOCK *************/ + /*************** THEN ATTEMPT TO OBTAIN A READLOCK *************/ + + status = pthread_rwlock_tryrdlock( &RWLock ); + rtems_test_assert( !status ); + + status = + pthread_create(&ThreadIds[0], NULL, WriteLockThread, &ThreadIds[0]); + rtems_test_assert( !status ); + + sleep(1); + status = + pthread_create(&ThreadIds[1], NULL, ReadLockThread, &ThreadIds[1]); + rtems_test_assert( !status ); + + sleep(1); + + status = pthread_rwlock_tryrdlock( &RWLock ); + rtems_test_assert( status == EBUSY ); + + status = pthread_rwlock_trywrlock( &RWLock ); + rtems_test_assert( status == EBUSY ); + + sleep( 5 ); + + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + sleep( 5 ); + + status = pthread_rwlock_destroy( &RWLock ); + rtems_test_assert( status == 0 ); + + /*************** TIMEOUT ON RWLOCK MONOTONIC ***************/ + + status = pthread_rwlock_init( &RWLock, NULL ); + rtems_test_assert( status == 0 ); + + status = clock_gettime( CLOCK_MONOTONIC, &abstime ); + rtems_test_assert( !status ); + + abstime.tv_sec += 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == 0 ); + + abstime.tv_sec += 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + /*************** OBTAIN RWLOCK FOR READ WITH ABSTIME IN PAST ***************/ + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == 0 ); + + /*************** OBTAIN RWLOCK FOR WRITE WITH ABSTIME IN PAST ***************/ + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id, &abstime ); + rtems_test_assert( status == 0 ); + + /*************** DESTROY RWLOCK ***************/ + status = pthread_rwlock_destroy( &RWLock ); + rtems_test_assert( status == 0 ); + + /*************** TIMEOUT ON RWLOCK REALTIME ***************/ + status = pthread_rwlock_init( &RWLock, NULL ); + rtems_test_assert( status == 0 ); + + status = clock_gettime( CLOCK_REALTIME, &abstime ); + rtems_test_assert( status == 0 ); + + abstime.tv_sec += 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + + abstime.tv_sec += 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == ETIMEDOUT ); + + /*************** OBTAIN RWLOCK FOR READ WITH ABSTIME IN PAST ***************/ + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockrdlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + + /*************** OBTAIN RWLOCK FOR WRITE WITH ABSTIME IN PAST ***************/ + status = pthread_rwlock_unlock( &RWLock ); + rtems_test_assert( !status ); + + abstime.tv_sec -= 1; + status = pthread_rwlock_clockwrlock( &RWLock, clock_id2, &abstime ); + rtems_test_assert( status == 0 ); + + /*************** DESTROY RWLOCK ***************/ + status = pthread_rwlock_destroy( &RWLock ); + rtems_test_assert( status == 0 ); + + /*************** OBTAIN A LOCK AND THEN RELEASE IT TWICE ***************/ + status = pthread_rwlock_init( &rwlock, NULL ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_unlock( &rwlock ); + rtems_test_assert( status == 0 ); + + status = pthread_rwlock_unlock( &rwlock ); + rtems_test_assert( status == 0 ); + + /*************** END OF TEST *****************/ + TEST_END(); + exit(0); +} -- 2.31.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel