[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