[PATCH 1/1] Implement clockrdlock / clockwrlock and test

Matt Joyce mfjoyce2004 at gmail.com
Fri Oct 8 13:22:59 UTC 2021


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



More information about the devel mailing list