Skip to content

Instantly share code, notes, and snippets.

@joycemaferko
Created August 20, 2021 13:55
Show Gist options
  • Save joycemaferko/cd6877c6592d12f9bd4169ff3a6ede57 to your computer and use it in GitHub Desktop.
Save joycemaferko/cd6877c6592d12f9bd4169ff3a6ede57 to your computer and use it in GitHub Desktop.
pthread_mutex_clocklock Test (psx18)
/*
* Copyright (C) 2021 Matthew Joyce
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Defined to have access to function prototype in pthread.h */
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sched.h>
#define CONFIGURE_INIT
#include "system.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <rtems/score/todimpl.h>
#define NOT_ENOUGH_SECONDS 4
#define ENOUGH_SECONDS 6
pthread_t t1;
struct timespec to;
struct timespec abstime;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
/*
* Further testing required. Call to mutex_lock or mutex_clocklock with
* Uninitialized global mutex object returns 0. Same call with unitialized
* mutex object declared in function scope returns EINVAL.
*/
//pthread_mutex_t bad_mutex2;
clockid_t clock_id1 = CLOCK_MONOTONIC;
clockid_t clock_id2 = CLOCK_REALTIME;
clockid_t clock_id3 = CLOCK_MONOTONIC_RAW;
int eno;
int count;
int status;
const char rtems_test_name[] = "PSX 18";
static void test_mutex_auto_initialization( void )
{
/* Expected pass: Standard lock without timeout */
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
eno = pthread_mutex_lock( &mutex );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_unlock( &mutex );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_destroy( &mutex );
rtems_test_assert( eno == 0 );
}
/* Expected pass: CLOCK_MONOTONIC */
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
to.tv_sec = 0;
to.tv_nsec = 1;
eno = pthread_mutex_clocklock( &mutex, clock_id1, &to );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_unlock( &mutex );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_destroy( &mutex );
rtems_test_assert( eno == 0 );
}
/* Expected pass: CLOCK_REALTIME */
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
eno = clock_gettime( clock_id2, &to );
rtems_test_assert( eno == 0 );
to.tv_sec += 0;
to.tv_nsec += 1;
eno = pthread_mutex_clocklock( &mutex, clock_id2, &to );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_unlock( &mutex );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_destroy( &mutex );
rtems_test_assert( eno == 0 );
}
/* Expected fail: Unsupported clock */
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
to.tv_sec = 2;
to.tv_nsec = 1;
eno = pthread_mutex_clocklock( &mutex, clock_id3, &to );
rtems_test_assert( eno == EINVAL );
eno = pthread_mutex_destroy( &mutex );
rtems_test_assert( eno == 0 );
}
/* Expected fail: Try to acquire lock already held in the same thread. */
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock( &mutex );
eno = clock_gettime( clock_id2, &to );
rtems_test_assert( eno == 0 );
to.tv_sec += 10;
eno = pthread_mutex_clocklock( &mutex, clock_id2, &to);
rtems_test_assert( eno != 0 );
eno = pthread_mutex_unlock( &mutex );
rtems_test_assert( eno == 0 );
eno = pthread_mutex_destroy( &mutex );
rtems_test_assert( eno == 0 );
}
}
void *POSIX_Init(
void *argument
)
{
TEST_BEGIN();
test_mutex_auto_initialization();
/* Expected fail: Insufficient time to acquire lock */
printf( "1st iteration Begin (Clock Monotonic)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_monotonic_fail, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "1st iteration END\n" );
empty_line();
/* Expected pass: Sufficient time to acquire lock */
printf(" 2nd iteration Begin (Clock Monotonic)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_monotonic_pass, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "2nd iteration END\n" );
empty_line();
/* Expected fail: Insufficient time to acquire lock */
printf( "3rd iteration Begin (Clock Realtime)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_realtime_fail, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "3rd iteration END\n" );
empty_line();
/* Expected pass: Sufficient time to acquire lock */
printf( "4th iteration Begin (Clock Realtime)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_realtime_pass, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "4th iteration END\n" );
empty_line();
/* Expected fail: unsupported clock */
printf( "5th iteration Begin (Unsupported Clock)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_bad_clock, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "5th iteration END\n" );
empty_line();
/* Expected fail: Invalid Abstime */
printf( "6th iteration Begin (Invalid Abstime)\n" );
status = pthread_mutex_lock( &mutex2 );
rtems_test_assert( status == 0 );
status = pthread_create( &t1, NULL, thread_func_bad_time, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "6th iteration END\n" );
empty_line();
/* Expected fail: Invalid Mutex */
/*
* Potential bug: pthread_mutex_lock should have undefined behavior when
* passing an uninitialized mutex. Currently it returns success.
*/
printf( "7th iteration Begin (Invalid Mutex)\n" );
pthread_mutex_t bad_mutex2;
status = pthread_mutex_lock( &bad_mutex2 );
rtems_test_assert( status == EINVAL );
status = pthread_create( &t1, NULL, thread_func_monotonic_bad_mutex, NULL );
rtems_test_assert( status == 0 );
/* Arbitrary sleep to test mutex_clocklock. */
sleep(5);
while ( count == 0 ){
eno = pthread_cond_wait( &cond, &bad_mutex2 );
if ( eno != 0 ) {
break;
}
}
count -= 1;
status = pthread_mutex_unlock( &bad_mutex2 );
rtems_test_assert( status == EINVAL );
rtems_test_assert( eno == 0 );
status = pthread_join( t1, NULL );
rtems_test_assert( status == 0 );
printf( "7th iteration END\n" );
empty_line();
TEST_END();
rtems_test_exit( 0 );
return NULL;
}
void *thread_func_monotonic_fail( void *arg )
{
int status;
status = clock_gettime( clock_id1, &abstime );
rtems_test_assert( status == 0 );
abstime.tv_sec += NOT_ENOUGH_SECONDS;
status = pthread_mutex_clocklock( &mutex2, clock_id1, &abstime );
rtems_test_assert( status == ETIMEDOUT );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == EPERM );
return NULL;
}
void *thread_func_monotonic_pass( void *arg )
{
int status;
status = clock_gettime( clock_id1, &abstime );
rtems_test_assert( status == 0 );
abstime.tv_sec += ENOUGH_SECONDS;
status = pthread_mutex_clocklock( &mutex2, clock_id1, &abstime );
rtems_test_assert( status == 0 );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
return NULL;
}
void *thread_func_realtime_fail( void *arg )
{
int status;
status = clock_gettime( clock_id2, &abstime );
rtems_test_assert( status == 0 );
abstime.tv_sec += NOT_ENOUGH_SECONDS;
status = pthread_mutex_clocklock( &mutex2, clock_id2, &abstime );
rtems_test_assert( status == ETIMEDOUT );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == EPERM );
return NULL;
}
void *thread_func_realtime_pass( void *arg )
{
int status;
status = clock_gettime( clock_id2, &abstime );
rtems_test_assert( status == 0 );
abstime.tv_sec += ENOUGH_SECONDS;
status = pthread_mutex_clocklock( &mutex2, clock_id2, &abstime );
rtems_test_assert( status == 0 );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == 0 );
return NULL;
}
void *thread_func_bad_clock( void *arg )
{
int status;
status = pthread_mutex_clocklock( &mutex2, clock_id3, &abstime );
rtems_test_assert( status == EINVAL );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == EPERM );
return NULL;
}
void *thread_func_bad_time( void *arg )
{
int status;
status = pthread_mutex_clocklock( &mutex2, clock_id3, NULL );
rtems_test_assert( status == EINVAL );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &mutex2 );
rtems_test_assert( status == EPERM );
return NULL;
}
void *thread_func_monotonic_bad_mutex( void *arg )
{
int status;
pthread_mutex_t bad_mutex2;
status = clock_gettime( clock_id1, &abstime );
rtems_test_assert( status == 0 );
abstime.tv_sec += ENOUGH_SECONDS;
status = pthread_mutex_clocklock( &bad_mutex2, clock_id1, &abstime );
rtems_test_assert( status == EINVAL );
printf("Return value of mutex_clocklock in thread_func is %d\n", status);
if ( count == 0 ) {
status = pthread_cond_signal( &cond );
rtems_test_assert( status == 0 );
}
count +=1;
status = pthread_mutex_unlock( &bad_mutex2 );
rtems_test_assert( status == EINVAL );
return NULL;
}
/* system.h
*
* This include file contains information that is included in every
* function in the test set.
*
* COPYRIGHT (c) 1989-1999.
* 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.
*/
/* functions */
#include <pmacros.h>
void *POSIX_Init(
void *argument
);
void *thread_func_monotonic_fail(
void *argument
);
void *thread_func_monotonic_pass(
void *argument
);
void *thread_func_realtime_fail(
void *argument
);
void *thread_func_realtime_pass(
void *argument
);
void *thread_func_bad_clock(
void *argument
);
void *thread_func_bad_time(
void *argument
);
void *thread_func_monotonic_bad_mutex(
void *argument
);
/* configuration information */
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_MAXIMUM_POSIX_THREADS 4
#define CONFIGURE_POSIX_INIT_THREAD_TABLE
#include <rtems/confdefs.h>
/* end of include file */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment