[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