source: rtems/cpukit/libdl/rtl-obj-cache.c @ 2c23639

5
Last change on this file since 2c23639 was 2c23639, checked in by Cillian O'Donnell <cpodonnell8@…>, on 04/07/17 at 20:40:11

libdl/rtl-obj-cache.c: Using inttypes macros fixes 4 format warnings

  • Property mode set to 100644
File size: 6.8 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_rtl
12 *
13 * @brief RTEMS Run-Time Linker Object File cache buffers a section of the
14 *        object file in a buffer to localise read performance.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <errno.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25#include <inttypes.h>
26
27#include <rtems/rtl/rtl-allocator.h>
28#include "rtl-obj-cache.h"
29#include "rtl-error.h"
30#include "rtl-trace.h"
31
32bool
33rtems_rtl_obj_cache_open (rtems_rtl_obj_cache_t* cache, size_t size)
34{
35  cache->fd        = -1;
36  cache->file_size = 0;
37  cache->offset    = 0;
38  cache->size      = size;
39  cache->level     = 0;
40  cache->buffer    = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
41  if (!cache->buffer)
42  {
43    rtems_rtl_set_error (ENOMEM, "no memory for cache buffer");
44    return false;
45  }
46  return true;
47}
48
49void
50rtems_rtl_obj_cache_close (rtems_rtl_obj_cache_t* cache)
51{
52  if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
53    printf ("rtl: cache: %2d: close\n", cache->fd);
54  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, cache->buffer);
55  cache->buffer    = NULL;
56  cache->fd        = -1;
57  cache->file_size = 0;
58  cache->level     = 0;
59}
60
61void
62rtems_rtl_obj_cache_flush (rtems_rtl_obj_cache_t* cache)
63{
64  if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
65    printf ("rtl: cache: %2d: flush\n", cache->fd);
66  cache->fd        = -1;
67  cache->file_size = 0;
68  cache->offset    = 0;
69  cache->level     = 0;
70}
71
72bool
73rtems_rtl_obj_cache_read (rtems_rtl_obj_cache_t* cache,
74                          int                    fd,
75                          off_t                  offset,
76                          void**                 buffer,
77                          size_t*                length)
78{
79  struct stat sb;
80
81  if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
82    printf ("rtl: cache: %2d: fd=%d offset=%" PRIdMAX "length=%zu area=[%"
83            PRIdMAX ",%" PRIdMAX "] cache=[%" PRIdMAX ",%" PRIdMAX "] size=%zu\n",
84            fd, cache->fd, offset, *length,
85            offset, offset + *length,
86            cache->offset, cache->offset + cache->level,
87            cache->file_size);
88
89  if (*length > cache->size)
90  {
91    rtems_rtl_set_error (EINVAL, "read size larger than cache size");
92    return false;
93  }
94
95  if (cache->fd == fd)
96  {
97    if (offset > cache->file_size)
98    {
99      rtems_rtl_set_error (EINVAL, "offset past end of file: offset=%i size=%i",
100                           (int) offset, (int) cache->file_size);
101      return false;
102    }
103
104    /*
105     * We sometimes are asked to read strings of a length we do not know.
106     */
107    if ((offset + *length) > cache->file_size)
108    {
109      *length = cache->file_size - offset;
110      if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
111        printf ("rtl: cache: %2d: truncate length=%d\n", fd, (int) *length);
112    }
113  }
114
115  while (true)
116  {
117    size_t buffer_offset = 0;
118    size_t buffer_read = cache->size;
119
120    /*
121     * Is the data in the cache for this file ?
122     */
123    if (fd == cache->fd)
124    {
125      /*
126       * Do not read past the end of the file.
127       */
128      if ((offset + buffer_read) > cache->file_size)
129        buffer_read = cache->file_size - offset;
130
131      /*
132       * Is any part of the data in the cache ?
133       */
134      if ((offset >= cache->offset) &&
135          (offset < (cache->offset + cache->level)))
136      {
137        size_t size;
138
139        buffer_offset = offset - cache->offset;
140        size          = cache->level - buffer_offset;
141
142        /*
143         * Return the location of the data in the cache.
144         */
145        *buffer = cache->buffer + buffer_offset;
146
147        /*
148         * Is all the data in the cache or just a part ?
149         */
150        if (*length <= size)
151          return true;
152
153        if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
154          printf ("rtl: cache: %2d: copy-down: buffer_offset=%d size=%d level=%d\n",
155                  fd, (int) buffer_offset, (int) size, (int) cache->level);
156
157        /*
158         * Copy down the data in the buffer and then fill the remaining space
159         * with as much data we are able to read.
160         */
161        memmove (cache->buffer, cache->buffer + buffer_offset, size);
162
163        cache->offset = offset;
164        cache->level  = size;
165        buffer_read   = cache->size - cache->level;
166        buffer_offset = size;
167
168        /*
169         * Do not read past the end of the file.
170         */
171        if ((offset + buffer_offset + buffer_read) > cache->file_size)
172          buffer_read = cache->file_size - (offset + buffer_offset);
173      }
174    }
175
176    if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
177      printf ("rtl: cache: %2d: seek: offset=%" PRIdMAX "buffer_offset=%zu"
178              "read=%zu cache=[%" PRIdMAX ",%" PRIdMAX "] dist=%" PRIdMAX "\n",
179              fd, offset + buffer_offset, buffer_offset, buffer_read,
180              offset, offset + buffer_read,
181              (cache->file_size - offset));
182
183    if (lseek (fd, offset + buffer_offset, SEEK_SET) < 0)
184    {
185      rtems_rtl_set_error (errno, "file seek failed");
186      return false;
187    }
188
189    /*
190     * Loop reading the data from the file until either an error or 0 is
191     * returned and if data has been read check if the amount is what we
192     * want. If not it is an error. A POSIX read can read data in fragments.
193     */
194
195    cache->level = buffer_offset + buffer_read;
196
197    while (buffer_read)
198    {
199      int r = read (fd, cache->buffer + buffer_offset, buffer_read);
200      if (r < 0)
201      {
202        rtems_rtl_set_error (errno, "file read failed");
203        return false;
204      }
205      if ((r == 0) && buffer_read)
206      {
207        if (rtems_rtl_trace (RTEMS_RTL_TRACE_CACHE))
208          printf ("rtl: cache: %2d: read: past end by=%d\n", fd, (int) buffer_read);
209        cache->level = cache->level - buffer_read;
210        buffer_read = 0;
211      }
212      else
213      {
214        buffer_read -= r;
215        buffer_offset += r;
216      }
217    }
218
219    cache->offset = offset;
220
221    if (cache->fd != fd)
222    {
223      cache->fd = fd;
224
225      if (fstat (cache->fd, &sb) < 0)
226      {
227        rtems_rtl_set_error (errno, "file stat failed");
228        return false;
229      }
230
231      cache->file_size = sb.st_size;
232    }
233  }
234
235  return false;
236}
237
238bool
239rtems_rtl_obj_cache_read_byval (rtems_rtl_obj_cache_t* cache,
240                                int                    fd,
241                                off_t                  offset,
242                                void*                  buffer,
243                                size_t                 length)
244{
245  void*  cbuffer = 0;
246  size_t len = length;
247  bool   ok = rtems_rtl_obj_cache_read (cache, fd, offset, &cbuffer, &len);
248  if (ok && (len != length))
249    ok = false;
250  if (ok)
251    memcpy (buffer, cbuffer, length);
252  return ok;
253}
Note: See TracBrowser for help on using the repository browser.