source: rtems/cpukit/score/src/heapwalk.c

Last change on this file was ab02824, checked in by Joel Sherrill <joel@…>, on 02/16/22 at 21:09:06

score/src/[a-m]*.c: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreHeap
7 *
8 * @brief This source file contains the implementation of
9 *   _Heap_Walk().
10 */
11
12/*
13 *  COPYRIGHT ( c ) 1989-2007.
14 *  On-Line Applications Research Corporation ( OAR ).
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include <rtems/score/address.h>
43#include <rtems/score/sysstate.h>
44#include <rtems/score/heapimpl.h>
45#include <rtems/score/interr.h>
46#include <rtems/bspIo.h>
47
48typedef void (*Heap_Walk_printer)(int, bool, const char*, ...);
49
50static void _Heap_Walk_print_nothing(
51  int source,
52  bool error,
53  const char *fmt,
54  ...
55)
56{
57  /* Do nothing */
58}
59
60static void _Heap_Walk_print( int source, bool error, const char *fmt, ... )
61{
62  va_list ap;
63
64  if ( error ) {
65    printk( "FAIL[%d]: ", source );
66  } else {
67    printk( "PASS[%d]: ", source );
68  }
69
70  va_start( ap, fmt );
71  vprintk( fmt, ap );
72  va_end( ap );
73}
74
75static bool _Heap_Walk_check_free_list(
76  int source,
77  Heap_Walk_printer printer,
78  Heap_Control *heap
79)
80{
81  uintptr_t const page_size = heap->page_size;
82  const Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );
83  const Heap_Block *const first_free_block = _Heap_Free_list_first( heap );
84  const Heap_Block *prev_block = free_list_tail;
85  const Heap_Block *free_block = first_free_block;
86
87  while ( free_block != free_list_tail ) {
88    if ( !_Heap_Is_block_in_heap( heap, free_block ) ) {
89      (*printer)(
90        source,
91        true,
92        "free block 0x%08x: not in heap\n",
93        free_block
94      );
95
96      return false;
97    }
98
99    if (
100      !_Heap_Is_aligned( _Heap_Alloc_area_of_block( free_block ), page_size )
101    ) {
102      (*printer)(
103        source,
104        true,
105        "free block 0x%08x: alloc area not page aligned\n",
106        free_block
107      );
108
109      return false;
110    }
111
112    if ( _Heap_Is_used( free_block ) ) {
113      (*printer)(
114        source,
115        true,
116        "free block 0x%08x: is used\n",
117        free_block
118      );
119
120      return false;
121    }
122
123    if ( free_block->prev != prev_block ) {
124      (*printer)(
125        source,
126        true,
127        "free block 0x%08x: invalid previous block 0x%08x\n",
128        free_block,
129        free_block->prev
130      );
131
132      return false;
133    }
134
135    prev_block = free_block;
136    free_block = free_block->next;
137  }
138
139  return true;
140}
141
142static bool _Heap_Walk_is_in_free_list(
143  Heap_Control *heap,
144  Heap_Block *block
145)
146{
147  const Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );
148  const Heap_Block *free_block = _Heap_Free_list_first( heap );
149
150  while ( free_block != free_list_tail ) {
151    if ( free_block == block ) {
152      return true;
153    }
154    free_block = free_block->next;
155  }
156
157  return false;
158}
159
160static bool _Heap_Walk_check_control(
161  int source,
162  Heap_Walk_printer printer,
163  Heap_Control *heap
164)
165{
166  uintptr_t const page_size = heap->page_size;
167  uintptr_t const min_block_size = heap->min_block_size;
168  Heap_Block *const first_free_block = _Heap_Free_list_first( heap );
169  Heap_Block *const last_free_block = _Heap_Free_list_last( heap );
170  Heap_Block *const first_block = heap->first_block;
171  Heap_Block *const last_block = heap->last_block;
172
173  (*printer)(
174    source,
175    false,
176    "page size %u, min block size %u\n"
177      "\tarea begin 0x%08x, area end 0x%08x\n"
178      "\tfirst block 0x%08x, last block 0x%08x\n"
179      "\tfirst free 0x%08x, last free 0x%08x\n",
180    page_size, min_block_size,
181    heap->area_begin, heap->area_end,
182    first_block, last_block,
183    first_free_block, last_free_block
184  );
185
186  if ( page_size == 0 ) {
187    (*printer)( source, true, "page size is zero\n" );
188
189    return false;
190  }
191
192  if ( !_Addresses_Is_aligned( (void *) page_size ) ) {
193    (*printer)(
194      source,
195      true,
196      "page size %u not CPU aligned\n",
197      page_size
198    );
199
200    return false;
201  }
202
203  if ( !_Heap_Is_aligned( min_block_size, page_size ) ) {
204    (*printer)(
205      source,
206      true,
207      "min block size %u not page aligned\n",
208      min_block_size
209    );
210
211    return false;
212  }
213
214  if (
215    !_Heap_Is_aligned( _Heap_Alloc_area_of_block( first_block ), page_size )
216  ) {
217    (*printer)(
218      source,
219      true,
220      "first block 0x%08x: alloc area not page aligned\n",
221      first_block
222    );
223
224    return false;
225  }
226
227  if ( !_Heap_Is_prev_used( first_block ) ) {
228    (*printer)(
229      source,
230      true,
231      "first block: HEAP_PREV_BLOCK_USED is cleared\n"
232    );
233
234    return false;
235  }
236
237  if ( _Heap_Is_free( last_block ) ) {
238    (*printer)(
239      source,
240      true,
241      "last block: is free\n"
242    );
243
244    return false;
245  }
246
247  if (
248    _Heap_Block_at( last_block, _Heap_Block_size( last_block ) ) != first_block
249  ) {
250    (*printer)(
251      source,
252      true,
253      "last block: next block is not the first block\n"
254    );
255
256    return false;
257  }
258
259  return _Heap_Walk_check_free_list( source, printer, heap );
260}
261
262static bool _Heap_Walk_check_free_block(
263  int source,
264  Heap_Walk_printer printer,
265  Heap_Control *heap,
266  Heap_Block *block
267)
268{
269  Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );
270  Heap_Block *const free_list_head = _Heap_Free_list_head( heap );
271  Heap_Block *const first_free_block = _Heap_Free_list_first( heap );
272  Heap_Block *const last_free_block = _Heap_Free_list_last( heap );
273  bool const prev_used = _Heap_Is_prev_used( block );
274  uintptr_t const block_size = _Heap_Block_size( block );
275  Heap_Block *const next_block = _Heap_Block_at( block, block_size );
276
277  (*printer)(
278    source,
279    false,
280    "block 0x%08x: size %u, prev 0x%08x%s, next 0x%08x%s\n",
281    block,
282    block_size,
283    block->prev,
284    block->prev == first_free_block ?
285      " (= first free)"
286        : (block->prev == free_list_head ? " (= head)" : ""),
287    block->next,
288    block->next == last_free_block ?
289      " (= last free)"
290        : (block->next == free_list_tail ? " (= tail)" : "")
291  );
292
293  if ( block_size != next_block->prev_size ) {
294    (*printer)(
295      source,
296      true,
297      "block 0x%08x: size %u != size %u (in next block 0x%08x)\n",
298      block,
299      block_size,
300      next_block->prev_size,
301      next_block
302    );
303
304    return false;
305  }
306
307  if ( !prev_used ) {
308    (*printer)(
309      source,
310      true,
311      "block 0x%08x: two consecutive blocks are free\n",
312      block
313    );
314
315    return false;
316  }
317
318  if ( !_Heap_Walk_is_in_free_list( heap, block ) ) {
319    (*printer)(
320      source,
321      true,
322      "block 0x%08x: free block not in free list\n",
323      block
324    );
325
326    return false;
327  }
328
329  return true;
330}
331
332bool _Heap_Walk(
333  Heap_Control *heap,
334  int source,
335  bool dump
336)
337{
338  uintptr_t const page_size = heap->page_size;
339  uintptr_t const min_block_size = heap->min_block_size;
340  Heap_Block *const first_block = heap->first_block;
341  Heap_Block *const last_block = heap->last_block;
342  Heap_Block *block = first_block;
343  Heap_Walk_printer printer = dump ?
344    _Heap_Walk_print : _Heap_Walk_print_nothing;
345
346  if ( !_System_state_Is_up( _System_state_Get() ) ) {
347    return true;
348  }
349
350  if ( !_Heap_Walk_check_control( source, printer, heap ) ) {
351    return false;
352  }
353
354  do {
355    uintptr_t const block_begin = (uintptr_t) block;
356    uintptr_t const block_size = _Heap_Block_size( block );
357    bool const prev_used = _Heap_Is_prev_used( block );
358    Heap_Block *const next_block = _Heap_Block_at( block, block_size );
359    uintptr_t const next_block_begin = (uintptr_t) next_block;
360    bool const is_not_last_block = block != last_block;
361
362    if ( !_Heap_Is_block_in_heap( heap, next_block ) ) {
363      (*printer)(
364        source,
365        true,
366        "block 0x%08x: next block 0x%08x not in heap\n",
367        block,
368        next_block
369      );
370
371      return false;
372    }
373
374    if ( !_Heap_Is_aligned( block_size, page_size ) && is_not_last_block ) {
375      (*printer)(
376        source,
377        true,
378        "block 0x%08x: block size %u not page aligned\n",
379        block,
380        block_size
381      );
382
383      return false;
384    }
385
386    if ( block_size < min_block_size && is_not_last_block ) {
387      (*printer)(
388        source,
389        true,
390        "block 0x%08x: size %u < min block size %u\n",
391        block,
392        block_size,
393        min_block_size
394      );
395
396      return false;
397    }
398
399    if ( next_block_begin <= block_begin && is_not_last_block ) {
400      (*printer)(
401        source,
402        true,
403        "block 0x%08x: next block 0x%08x is not a successor\n",
404        block,
405        next_block
406      );
407
408      return false;
409    }
410
411    if ( !_Heap_Is_prev_used( next_block ) ) {
412      if ( !_Heap_Walk_check_free_block( source, printer, heap, block ) ) {
413        return false;
414      }
415    } else if (prev_used) {
416      (*printer)(
417        source,
418        false,
419        "block 0x%08x: size %u\n",
420        block,
421        block_size
422      );
423    } else {
424      (*printer)(
425        source,
426        false,
427        "block 0x%08x: size %u, prev_size %u\n",
428        block,
429        block_size,
430        block->prev_size
431      );
432    }
433
434    block = next_block;
435  } while ( block != first_block );
436
437  return true;
438}
Note: See TracBrowser for help on using the repository browser.