Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:26

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreObject
0007  *
0008  * @brief This source file contains the implementation of
0009  *   _Objects_Extend_information().
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-1999.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <rtems/score/objectimpl.h>
0043 #include <rtems/score/address.h>
0044 #include <rtems/score/assert.h>
0045 #include <rtems/score/chainimpl.h>
0046 #include <rtems/score/isrlevel.h>
0047 #include <rtems/score/sysstate.h>
0048 #include <rtems/score/wkspace.h>
0049 
0050 #include <string.h>  /* for memcpy() */
0051 
0052 Objects_Maximum _Objects_Extend_information(
0053   Objects_Information *information
0054 )
0055 {
0056   Objects_Control  *the_object;
0057   uint32_t          block_count;
0058   uint32_t          block;
0059   uint32_t          index_base;
0060   uint32_t          index_end;
0061   uint32_t          index;
0062   uint32_t          extend_count;
0063   Objects_Maximum   old_maximum;
0064   uint32_t          new_maximum;
0065   size_t            object_block_size;
0066   Objects_Control  *new_object_block;
0067   bool              do_extend;
0068   Objects_Id        api_class_and_node;
0069 
0070   _Assert(
0071     _Objects_Allocator_is_owner()
0072       || !_System_state_Is_up( _System_state_Get() )
0073   );
0074   _Assert( _Objects_Is_auto_extend( information ) );
0075 
0076   extend_count = _Objects_Extend_size( information );
0077   old_maximum = _Objects_Get_maximum_index( information );
0078   new_maximum = (uint32_t) old_maximum + extend_count;
0079   api_class_and_node = information->maximum_id & ~OBJECTS_INDEX_MASK;
0080 
0081   /*
0082    *  Search for a free block of indexes. If we do NOT need to allocate or
0083    *  extend the block table, then we will change do_extend.
0084    */
0085   do_extend     = true;
0086   index_base    = extend_count;
0087   block         = 1;
0088 
0089   if ( information->object_blocks == NULL ) {
0090     block_count = 1;
0091   } else {
0092     block_count = old_maximum / extend_count;
0093 
0094     for ( ; block < block_count; block++ ) {
0095       if ( information->object_blocks[ block ] == NULL ) {
0096         do_extend = false;
0097         break;
0098       } else
0099         index_base += extend_count;
0100     }
0101   }
0102 
0103   index_end = index_base + extend_count;
0104 
0105   /*
0106    *  We need to limit the number of objects to the maximum number
0107    *  representable in the index portion of the object Id.  In the
0108    *  case of 16-bit Ids, this is only 256 object instances.
0109    */
0110   if ( new_maximum > OBJECTS_ID_FINAL_INDEX ) {
0111     return 0;
0112   }
0113 
0114   /*
0115    * Allocate the name table, and the objects and if it fails either return or
0116    * generate a fatal error depending on auto-extending being active.
0117    */
0118   object_block_size = extend_count * information->object_size;
0119   new_object_block = _Workspace_Allocate( object_block_size );
0120   if ( new_object_block == NULL ) {
0121     return 0;
0122   }
0123 
0124   /*
0125    *  Do we need to grow the tables?
0126    */
0127   if ( do_extend ) {
0128     ISR_lock_Context  lock_context;
0129     Objects_Control **object_blocks;
0130     Objects_Control **local_table;
0131     Objects_Maximum  *inactive_per_block;
0132     void             *old_tables;
0133     size_t            table_size;
0134     uintptr_t         object_blocks_size;
0135     uintptr_t         local_table_size;
0136 
0137     /*
0138      *  Growing the tables means allocating a new area, doing a copy and
0139      *  updating the information table.
0140      *
0141      *  If the maximum is minimum we do not have a table to copy. First
0142      *  time through.
0143      *
0144      *  The allocation has:
0145      *
0146      *      Objects_Control *object_blocks[ block_count ];
0147      *      Objects_Control *local_table[ maximum ];
0148      *      Objects_Maximum  inactive_count[ block_count ];
0149      *
0150      *  This is the order in memory. Watch changing the order. See the memcpy
0151      *  below.
0152      */
0153 
0154     /*
0155      *  Up the block count and maximum.
0156      */
0157     block_count++;
0158 
0159     /*
0160      *  Allocate the tables and break it up.
0161      */
0162     object_blocks_size = block_count * sizeof( *object_blocks );
0163     local_table_size =  new_maximum * sizeof( *local_table );
0164     table_size = object_blocks_size
0165       + local_table_size
0166       + block_count * sizeof( *inactive_per_block );
0167     object_blocks = _Workspace_Allocate( table_size );
0168     if ( object_blocks == NULL ) {
0169       _Workspace_Free( new_object_block );
0170       return 0;
0171     }
0172 
0173     /*
0174      *  Break the block into the various sections.
0175      */
0176     local_table = _Addresses_Add_offset(
0177       object_blocks,
0178       object_blocks_size
0179     );
0180     inactive_per_block = _Addresses_Add_offset(
0181       local_table,
0182       local_table_size
0183     );
0184 
0185     /*
0186      *  Take the block count down. Saves all the (block_count - 1)
0187      *  in the copies.
0188      */
0189     block_count--;
0190 
0191     if ( old_maximum > extend_count ) {
0192       /*
0193        * Coverity thinks there is a way for this to be NULL (CID #26033).
0194        * After much time spent analyzing this, no one has identified the
0195        * conditions where this can actually occur. Adding this _Assert ensures
0196        * that it is never NULL. If this assert is triggered, condition
0197        * generating this case will have been identified and it can be revisted.
0198        * This is being done out of an abundance of caution since we could have
0199        * easily flagged this as a false positive and ignored it completely.
0200        */
0201       _Assert(information->object_blocks != NULL);
0202 
0203       /*
0204        *  Copy each section of the table over. This has to be performed as
0205        *  separate parts as size of each block has changed.
0206        */
0207       memcpy(
0208         object_blocks,
0209         information->object_blocks,
0210         block_count * sizeof( *object_blocks )
0211       );
0212       memcpy(
0213         inactive_per_block,
0214         information->inactive_per_block,
0215         block_count * sizeof( *inactive_per_block )
0216       );
0217     } else {
0218       object_blocks[ 0 ] = NULL;
0219       inactive_per_block[ 0 ] = 0;
0220     }
0221 
0222     memcpy(
0223       local_table,
0224       information->local_table,
0225       old_maximum * sizeof( *local_table )
0226     );
0227 
0228     /*
0229      *  Initialise the new entries in the table.
0230      */
0231     for ( index = index_base ; index < index_end ; ++index ) {
0232       local_table[ index ] = NULL;
0233     }
0234 
0235     /* FIXME: https://gitlab.rtems.org/rtems/rtos/rtems/-/issues/2280 */
0236     _ISR_lock_ISR_disable( &lock_context );
0237 
0238     old_tables = information->object_blocks;
0239 
0240     information->object_blocks = object_blocks;
0241     information->inactive_per_block = inactive_per_block;
0242     information->local_table = local_table;
0243     information->maximum_id = api_class_and_node
0244       | (new_maximum << OBJECTS_INDEX_START_BIT);
0245 
0246     _ISR_lock_ISR_enable( &lock_context );
0247 
0248     _Workspace_Free( old_tables );
0249 
0250     block_count++;
0251   }
0252 
0253   /*
0254    *  Assign the new object block to the object block table.
0255    */
0256   information->object_blocks[ block ] = new_object_block;
0257   information->inactive_per_block[ block ] = information->objects_per_block;
0258   information->inactive += information->objects_per_block;
0259 
0260   /*
0261    *  Append to inactive chain.
0262    */
0263   the_object = new_object_block;
0264   for ( index = index_base ; index < index_end ; ++index ) {
0265     the_object->id = api_class_and_node
0266       | ( ( index + OBJECTS_INDEX_MINIMUM ) << OBJECTS_INDEX_START_BIT );
0267 
0268     _Chain_Initialize_node( &the_object->Node );
0269     _Chain_Append_unprotected( &information->Inactive, &the_object->Node );
0270 
0271     the_object = _Addresses_Add_offset( the_object, information->object_size );
0272   }
0273 
0274   return block;
0275 }