summaryrefslogblamecommitdiffstats
path: root/cpukit/posix/src/keycreate.c
blob: 59a5e5a9273fe717d1dd8a45399d18e5860eb84d (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                           
   
        
  
                    

                                         

   
  

                                                   
                                                   
  



















                                                                              

   
                    


                   
                                


                                    
 

                  
   

                                                                     





                                       
 
                                   
 
                   
                                



                                   
                                                       
                                                                     
                            
                              

           



















































































































                                                                              
/* SPDX-License-Identifier: BSD-2-Clause */

/**
 * @file
 *
 * @ingroup POSIXAPI
 *
 * @brief Thread-Specific Data Key Create
 */

/*
 * COPYRIGHT (c) 1989-2010.
 * On-Line Applications Research Corporation (OAR).
 * Copyright (c) 2016 embedded brains GmbH & Co. KG
 *
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/posix/keyimpl.h>
#include <rtems/score/userextimpl.h>
#include <rtems/score/wkspace.h>
#include <rtems/sysinit.h>

#include <errno.h>

/**
 *  17.1.1 Thread-Specific Data Key Create, P1003.1c/Draft 10, p. 163
 */
int pthread_key_create(
  pthread_key_t  *key,
  void          (*destructor)( void * )
)
{
  POSIX_Keys_Control  *the_key;

  the_key = _POSIX_Keys_Allocate();

  if ( !the_key ) {
    _Objects_Allocator_unlock();
    return EAGAIN;
  }

  the_key->destructor = destructor;
  _Chain_Initialize_empty( &the_key->Key_value_pairs );
  _Objects_Open_u32( &_POSIX_Keys_Information, &the_key->Object, 0 );
  *key = the_key->Object.id;
  _Objects_Allocator_unlock();
  return 0;
}

Freechain_Control _POSIX_Keys_Keypool;

static uint32_t _POSIX_Keys_Get_keypool_bump_count( void )
{
  uint32_t max;

  max = _POSIX_Keys_Key_value_pair_maximum;
  return _Objects_Is_unlimited( max ) ?
    _Objects_Maximum_per_allocation( max ) : 0;
}

static uint32_t _POSIX_Keys_Get_initial_keypool_size( void )
{
  uint32_t max;

  max = _POSIX_Keys_Key_value_pair_maximum;
  return _Objects_Maximum_per_allocation( max );
}

static void _POSIX_Keys_Initialize_keypool( void )
{
  _Freechain_Initialize(
    &_POSIX_Keys_Keypool,
    _POSIX_Keys_Key_value_pairs,
    _POSIX_Keys_Get_initial_keypool_size(),
    sizeof( _POSIX_Keys_Key_value_pairs[ 0 ] )
  );
}

POSIX_Keys_Key_value_pair * _POSIX_Keys_Key_value_allocate( void )
{
  return (POSIX_Keys_Key_value_pair *) _Freechain_Get(
    &_POSIX_Keys_Keypool,
    _Workspace_Allocate,
    _POSIX_Keys_Get_keypool_bump_count(),
    sizeof( POSIX_Keys_Key_value_pair )
  );
}

static void _POSIX_Keys_Run_destructors( Thread_Control *the_thread )
{
  while ( true ) {
    ISR_lock_Context  lock_context;
    RBTree_Node      *node;

    _Objects_Allocator_lock();
    _POSIX_Keys_Key_value_acquire( the_thread, &lock_context );

    node = _RBTree_Root( &the_thread->Keys.Key_value_pairs );
    if ( node != NULL ) {
      POSIX_Keys_Key_value_pair *key_value_pair;
      pthread_key_t              key;
      void                      *value;
      POSIX_Keys_Control        *the_key;
      void                    ( *destructor )( void * );

      key_value_pair = POSIX_KEYS_RBTREE_NODE_TO_KEY_VALUE_PAIR( node );
      key = key_value_pair->key;
      value = key_value_pair->value;
      _RBTree_Extract(
        &the_thread->Keys.Key_value_pairs,
        &key_value_pair->Lookup_node
      );

      _POSIX_Keys_Key_value_release( the_thread, &lock_context );
      _POSIX_Keys_Key_value_free( key_value_pair );

      the_key = _POSIX_Keys_Get( key );
      _Assert( the_key != NULL );
      destructor = the_key->destructor;

      _Objects_Allocator_unlock();

      if ( destructor != NULL && value != NULL ) {
        ( *destructor )( value );
      }
    } else {
      _POSIX_Keys_Key_value_release( the_thread, &lock_context );
      _Objects_Allocator_unlock();
      break;
    }
  }
}

static void _POSIX_Keys_Restart_run_destructors(
  Thread_Control *executing,
  Thread_Control *the_thread
)
{
  (void) executing;
  _POSIX_Keys_Run_destructors( the_thread );
}

static User_extensions_Control _POSIX_Keys_Extensions = {
  .Callouts = {
    .thread_restart = _POSIX_Keys_Restart_run_destructors,
    .thread_terminate = _POSIX_Keys_Run_destructors
  }
};

/**
 * @brief This routine performs the initialization necessary for this manager.
 */
static void _POSIX_Keys_Manager_initialization(void)
{
  _Objects_Initialize_information( &_POSIX_Keys_Information );
  _POSIX_Keys_Initialize_keypool();
  _User_extensions_Add_API_set( &_POSIX_Keys_Extensions );
}

RTEMS_SYSINIT_ITEM(
  _POSIX_Keys_Manager_initialization,
  RTEMS_SYSINIT_POSIX_KEYS,
  RTEMS_SYSINIT_ORDER_MIDDLE
);