[PATCH 1/1] Implement clockrdlock / clockwrlock and test
Joel Sherrill
joel at rtems.org
Fri Oct 8 14:55:18 UTC 2021
On Fri, Oct 8, 2021 at 8:23 AM Matt Joyce <mfjoyce2004 at gmail.com> wrote:
>
> 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.
> + */
Since this is new, feel free to convert the license to BSD-2-Clause and add
SPDX annotation. Plenty of examples for this.
> +
> +/* 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
These don't look lined up.
> +)
> +{
> + POSIX_RWLock_Control *the_rwlock;
> + Thread_queue_Context queue_context;
> + Status_Control status;
Lined up again?
> +
> + 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
> + );
> + }
Should there be an else here?
What if it is another CLOCK_ABC value? Shouldn't that be an error?
> + 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.
> + */
BSD-2 again
> +
> +/* 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
Alignment
> +)
> +{
> + POSIX_RWLock_Control *the_rwlock;
> + Thread_queue_Context queue_context;
> + Status_Control status;
Alignment
> +
> + 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
> + );
> + }
Same issue on else and error checking other clock values.
There is likely a need to exit a critical section on clock type error.
> +
> + 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.
> + */
> +
Add your name? BSD-2?
> +
> +#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);
Init can be static and avoid the forward declaration.
> +
> +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
This is the default so isn't needed. May just be remnant of other test.
Probably should convert the Classic API init task to a pthread init
thread. This is a POSIX
test.
> +
> +#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;
I don't see why you have these variables. Just use the constants.
I could be missing something.
> +
> +/*
> + * 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
I think this can just be main() and invoke it not test_main from the
init pthread.
> +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);
> +}
As a general question, did you copy an existing test and add to it?
If so, you may have a lot of test cases that are not needed just based
on the new additions.
> --
> 2.31.1
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list