From 172e953147da1d82bf5a6746b2fe6112a9509ad7 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 12 Dec 2014 13:16:11 +0100 Subject: posix: Delete key/value if value is set to NULL --- cpukit/posix/include/rtems/posix/keyimpl.h | 13 ++++ cpukit/posix/src/keyfreememory.c | 5 +- cpukit/posix/src/keysetspecific.c | 107 +++++++++++++++++++---------- testsuites/psxtests/psxkey02/init.c | 19 +++++ 4 files changed, 106 insertions(+), 38 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/keyimpl.h b/cpukit/posix/include/rtems/posix/keyimpl.h index 1dcfb4e9c6..a5c80d625b 100644 --- a/cpukit/posix/include/rtems/posix/keyimpl.h +++ b/cpukit/posix/include/rtems/posix/keyimpl.h @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -186,6 +187,18 @@ RTEMS_INLINE_ROUTINE RBTree_Node *_POSIX_Keys_Find( ); } +RTEMS_INLINE_ROUTINE void _POSIX_Keys_Free_key_value_pair( + POSIX_Keys_Key_value_pair *key_value_pair +) +{ + _RBTree_Extract( + &_POSIX_Keys_Key_value_lookup_tree, + &key_value_pair->Key_value_lookup_node + ); + _Chain_Extract_unprotected( &key_value_pair->Key_values_per_thread_node ); + _POSIX_Keys_Key_value_pair_free( key_value_pair ); +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/posix/src/keyfreememory.c b/cpukit/posix/src/keyfreememory.c index 9f03f6bd7e..8ae7fd033f 100644 --- a/cpukit/posix/src/keyfreememory.c +++ b/cpukit/posix/src/keyfreememory.c @@ -51,9 +51,8 @@ void _POSIX_Keys_Free_memory( p = POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( iter ); while ( iter != NULL && p->key == key_id ) { next = _RBTree_Next( iter, RBT_RIGHT ); - _RBTree_Extract( &_POSIX_Keys_Key_value_lookup_tree, iter ); - _Chain_Extract_unprotected( &p->Key_values_per_thread_node ); - _POSIX_Keys_Key_value_pair_free( p ); + + _POSIX_Keys_Free_key_value_pair( p ); iter = next; p = POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( iter ); diff --git a/cpukit/posix/src/keysetspecific.c b/cpukit/posix/src/keysetspecific.c index 427fff3d03..20e3042b4d 100644 --- a/cpukit/posix/src/keysetspecific.c +++ b/cpukit/posix/src/keysetspecific.c @@ -25,6 +25,67 @@ #include +static int _POSIX_Keys_Set_value( + pthread_key_t key, + const void *value, + POSIX_Keys_Control *the_key, + Thread_Control *executing, + RBTree_Node *rb_node +) +{ + POSIX_Keys_Key_value_pair *key_value_pair; + + if ( rb_node != NULL ) { + key_value_pair = POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( rb_node ); + key_value_pair->value = RTEMS_DECONST( void *, value ); + } else { + key_value_pair = _POSIX_Keys_Key_value_pair_allocate(); + + if ( key_value_pair == NULL ) { + return ENOMEM; + } + + key_value_pair->key = key; + key_value_pair->thread = executing; + key_value_pair->value = RTEMS_DECONST( void *, value ); + + /* + * The insert can only go wrong if the same node is already in a unique + * tree. This has been already checked with the _RBTree_Find(). + */ + _RBTree_Insert( + &_POSIX_Keys_Key_value_lookup_tree, + &key_value_pair->Key_value_lookup_node, + _POSIX_Keys_Key_value_compare, + true + ); + + _Chain_Append_unprotected( + &executing->Key_Chain, + &key_value_pair->Key_values_per_thread_node + ); + } + + return 0; +} + +static int _POSIX_Keys_Delete_value( + pthread_key_t key, + POSIX_Keys_Control *the_key, + RBTree_Node *rb_node +) +{ + + if ( rb_node != NULL ) { + POSIX_Keys_Key_value_pair *key_value_pair = + POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( rb_node ); + + _POSIX_Keys_Free_key_value_pair( key_value_pair ); + } + + return 0; +} + /* * 17.1.2 Thread-Specific Data Management, P1003.1c/Draft 10, p. 165 */ @@ -34,52 +95,28 @@ int pthread_setspecific( const void *value ) { - POSIX_Keys_Control *the_key; - Objects_Locations location; - POSIX_Keys_Key_value_pair *value_pair_ptr; - RBTree_Node *p; - Thread_Control *executing; + POSIX_Keys_Control *the_key; + Objects_Locations location; + Thread_Control *executing; + RBTree_Node *rb_node; + int eno; the_key = _POSIX_Keys_Get( key, &location ); switch ( location ) { case OBJECTS_LOCAL: executing = _Thread_Executing; - p = _POSIX_Keys_Find( key, executing ); - if ( p != NULL ) { - value_pair_ptr = POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( p ); - value_pair_ptr->value = RTEMS_DECONST( void *, value ); + rb_node = _POSIX_Keys_Find( key, executing ); + + if ( value != NULL ) { + eno = _POSIX_Keys_Set_value( key, value, the_key, executing, rb_node ); } else { - value_pair_ptr = _POSIX_Keys_Key_value_pair_allocate(); - - if ( !value_pair_ptr ) { - _Objects_Put( &the_key->Object ); - - return ENOMEM; - } - - value_pair_ptr->key = key; - value_pair_ptr->thread = executing; - value_pair_ptr->value = RTEMS_DECONST( void *, value ); - /* The insert can only go wrong if the same node is already in a unique - * tree. This has been already checked with the _RBTree_Find() */ - _RBTree_Insert( - &_POSIX_Keys_Key_value_lookup_tree, - &value_pair_ptr->Key_value_lookup_node, - _POSIX_Keys_Key_value_compare, - true - ); - - /** append rb_node to the thread API extension's chain */ - _Chain_Append_unprotected( - &_Thread_Executing->Key_Chain, - &value_pair_ptr->Key_values_per_thread_node - ); + eno = _POSIX_Keys_Delete_value( key, the_key, rb_node ); } _Objects_Put( &the_key->Object ); - return 0; + return eno; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never happen */ diff --git a/testsuites/psxtests/psxkey02/init.c b/testsuites/psxtests/psxkey02/init.c index 5734db76a5..23a392b004 100644 --- a/testsuites/psxtests/psxkey02/init.c +++ b/testsuites/psxtests/psxkey02/init.c @@ -30,6 +30,7 @@ rtems_task Init(rtems_task_argument ignored) bool ok; rtems_resource_snapshot snapshot; void *greedy; + void *value; TEST_BEGIN(); @@ -40,6 +41,24 @@ rtems_task Init(rtems_task_argument ignored) eno = pthread_key_create( &key1, NULL ); rtems_test_assert( eno == 0 ); + eno = pthread_setspecific( key1, (void *) 1 ); + rtems_test_assert( eno == 0 ); + + value = pthread_getspecific( key1 ); + rtems_test_assert( value == (void *) 1 ); + + eno = pthread_setspecific( key1, NULL ); + rtems_test_assert( eno == 0 ); + + value = pthread_getspecific( key1 ); + rtems_test_assert( value == NULL ); + + eno = pthread_setspecific( key1, NULL ); + rtems_test_assert( eno == 0 ); + + value = pthread_getspecific( key1 ); + rtems_test_assert( value == NULL ); + puts( "Init - pthread_key_create - EAGAIN" ); eno = pthread_key_create( &key2, NULL ); rtems_test_assert( eno == EAGAIN ); -- cgit v1.2.3