Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Object File cache buffers a section of the
0009  *        object file in a buffer to localise read performance.
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include <errno.h>
0042 #include <stdio.h>
0043 #include <string.h>
0044 #include <unistd.h>
0045 #include <inttypes.h>
0046 #include <rtems/inttypes.h>
0047 
0048 #include <rtems/rtl/rtl-allocator.h>
0049 #include <rtems/rtl/rtl-obj-cache.h>
0050 #include "rtl-error.h"
0051 #include <rtems/rtl/rtl-trace.h>
0052 
0053 bool
0054 rtems_rtl_obj_cache_open (rtems_rtl_obj_cache* cache, size_t size)
0055 {
0056   cache->fd        = -1;
0057   cache->file_size = 0;
0058   cache->offset    = 0;
0059   cache->size      = size;
0060   cache->level     = 0;
0061   cache->buffer    = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
0062   if (!cache->buffer)
0063   {
0064     rtems_rtl_set_error (ENOMEM, "no memory for cache buffer");
0065     return false;
0066   }
0067   return true;
0068 }
0069 
0070 void
0071 rtems_rtl_obj_cache_close (rtems_rtl_obj_cache* cache)
0072 {
0073   if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0074     printf ("rtl: cache: %2d: close\n", cache->fd);
0075   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, cache->buffer);
0076   cache->buffer    = NULL;
0077   cache->fd        = -1;
0078   cache->file_size = 0;
0079   cache->level     = 0;
0080 }
0081 
0082 void
0083 rtems_rtl_obj_cache_flush (rtems_rtl_obj_cache* cache)
0084 {
0085   if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0086     printf ("rtl: cache: %2d: flush\n", cache->fd);
0087   cache->fd        = -1;
0088   cache->file_size = 0;
0089   cache->offset    = 0;
0090   cache->level     = 0;
0091 }
0092 
0093 bool
0094 rtems_rtl_obj_cache_read (rtems_rtl_obj_cache* cache,
0095                           int                  fd,
0096                           off_t                offset,
0097                           void**               buffer,
0098                           size_t*              length)
0099 {
0100   struct stat sb;
0101 
0102   if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0103     printf ("rtl: cache: %2d: fd=%d offset=%" PRIdoff_t " length=%zu area=[%"
0104             PRIdoff_t ",%" PRIdoff_t "] cache=[%" PRIdoff_t ",%" PRIdoff_t "] size=%zu\n",
0105             fd, cache->fd, offset, *length,
0106             offset, offset + *length,
0107             cache->offset, cache->offset + cache->level,
0108             cache->file_size);
0109 
0110   if (*length > cache->size)
0111   {
0112     rtems_rtl_set_error (EINVAL, "read size larger than cache size");
0113     return false;
0114   }
0115 
0116   if (cache->fd == fd)
0117   {
0118     if (offset >= cache->file_size)
0119     {
0120       rtems_rtl_set_error (EINVAL, "offset past end of file: offset=%i size=%i",
0121                            (int) offset, (int) cache->file_size);
0122       return false;
0123     }
0124 
0125     /*
0126      * We sometimes are asked to read strings of a length we do not know.
0127      */
0128     if ((offset + *length) > cache->file_size)
0129     {
0130       *length = cache->file_size - offset;
0131       if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0132         printf ("rtl: cache: %2d: truncate length=%d\n", fd, (int) *length);
0133 
0134     }
0135   }
0136 
0137   while (true)
0138   {
0139     size_t buffer_offset = 0;
0140     size_t buffer_read = cache->size;
0141 
0142     /*
0143      * Is the data in the cache for this file ?
0144      */
0145     if (fd == cache->fd)
0146     {
0147       /*
0148        * Do not read past the end of the file.
0149        */
0150       if ((offset + buffer_read) > cache->file_size)
0151         buffer_read = cache->file_size - offset;
0152 
0153       /*
0154        * Is any part of the data in the cache ?
0155        */
0156       if ((offset >= cache->offset) &&
0157           (offset < (cache->offset + cache->level)))
0158       {
0159         size_t size;
0160 
0161         buffer_offset = offset - cache->offset;
0162         size          = cache->level - buffer_offset;
0163 
0164         /*
0165          * Return the location of the data in the cache.
0166          */
0167         *buffer = cache->buffer + buffer_offset;
0168 
0169         /*
0170          * Is all the data in the cache or just a part ?
0171          */
0172         if (*length <= size)
0173           return true;
0174 
0175         if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0176           printf ("rtl: cache: %2d: copy-down: buffer_offset=%d size=%d level=%d\n",
0177                   fd, (int) buffer_offset, (int) size, (int) cache->level);
0178 
0179         /*
0180          * Copy down the data in the buffer and then fill the remaining space
0181          * with as much data we are able to read.
0182          */
0183         memmove (cache->buffer, cache->buffer + buffer_offset, size);
0184 
0185         cache->offset = offset;
0186         cache->level  = size;
0187         buffer_read   = cache->size - cache->level;
0188         buffer_offset = size;
0189 
0190         /*
0191          * Do not read past the end of the file.
0192          */
0193         if ((offset + buffer_offset + buffer_read) > cache->file_size)
0194           buffer_read = cache->file_size - (offset + buffer_offset);
0195       }
0196     }
0197 
0198     if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0199       printf ("rtl: cache: %2d: seek: offset=%" PRIdoff_t " buffer_offset=%zu"
0200               " read=%zu cache=[%" PRIdoff_t ",%" PRIdoff_t "] "
0201               "dist=%" PRIdoff_t "\n",
0202               fd, offset + buffer_offset, buffer_offset, buffer_read,
0203               offset, offset + buffer_read,
0204               (cache->file_size - offset));
0205 
0206     if (lseek (fd, offset + buffer_offset, SEEK_SET) < 0)
0207     {
0208       rtems_rtl_set_error (errno, "file seek failed");
0209       return false;
0210     }
0211 
0212     /*
0213      * Loop reading the data from the file until either an error or 0 is
0214      * returned and if data has been read check if the amount is what we
0215      * want. If not it is an error. A POSIX read can read data in fragments.
0216      */
0217 
0218     cache->level = buffer_offset + buffer_read;
0219 
0220     while (buffer_read)
0221     {
0222       int r = read (fd, cache->buffer + buffer_offset, buffer_read);
0223       if (r < 0)
0224       {
0225         rtems_rtl_set_error (errno, "file read failed");
0226         return false;
0227       }
0228       if ((r == 0) && buffer_read)
0229       {
0230         if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
0231           printf ("rtl: cache: %2d: read: past end by=%d\n", fd, (int) buffer_read);
0232         cache->level = cache->level - buffer_read;
0233         buffer_read = 0;
0234       }
0235       else
0236       {
0237         buffer_read -= r;
0238         buffer_offset += r;
0239       }
0240     }
0241 
0242     cache->offset = offset;
0243 
0244     if (cache->fd != fd)
0245     {
0246       cache->fd = fd;
0247 
0248       if (fstat (cache->fd, &sb) < 0)
0249       {
0250         rtems_rtl_set_error (errno, "file stat failed");
0251         return false;
0252       }
0253 
0254       cache->file_size = sb.st_size;
0255     }
0256   }
0257 
0258   return false;
0259 }
0260 
0261 bool
0262 rtems_rtl_obj_cache_read_byval (rtems_rtl_obj_cache* cache,
0263                                 int                  fd,
0264                                 off_t                offset,
0265                                 void*                buffer,
0266                                 size_t               length)
0267 {
0268   void*  cbuffer = 0;
0269   size_t len = length;
0270   bool   ok = rtems_rtl_obj_cache_read (cache, fd, offset, &cbuffer, &len);
0271   if (ok && (len != length))
0272     ok = false;
0273   if (ok)
0274     memcpy (buffer, cbuffer, length);
0275   return ok;
0276 }