aboutsummaryrefslogtreecommitdiffstats
path: root/src/free.c
blob: 0e64b516f295facdba6894b283598f4f4c64e8da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
 * @file   free.c
 * @brief  free implementation.
 */

#include "malloc.h"
#include "malloc_internal.h"
#include <sys/mman.h>

static t_chunk *
_s_find_chunk (t_zone *zone, void *ptr)
{
  t_chunk *chunk;

  while (zone)
    {
      chunk = (t_chunk *)((char *)zone + ALIGN (sizeof (t_zone)));
      while (chunk)
        {
          if ((char *)chunk + ALIGN (sizeof (t_chunk)) == ptr)
            return (chunk);
          chunk = chunk->next;
        }
      zone = zone->next;
    }
  return (NULL);
}

static void
_s_unlink_zone (t_zone **zone_list, t_zone *zone)
{
  t_zone *prev;

  if (*zone_list == zone)
    {
      *zone_list = zone->next;
      return;
    }
  prev = *zone_list;
  while (prev && prev->next != zone)
    prev = prev->next;
  if (prev)
    prev->next = zone->next;
}

void
free (void *ptr)
{
  t_chunk *chunk;
  t_zone *zone;

  if (!ptr)
    return;
  chunk = _s_find_chunk (g_heap.large, ptr);
  if (chunk)
    {
      zone = (t_zone *)((char *)chunk - ALIGN (sizeof (t_zone)));
      _s_unlink_zone (&g_heap.large, zone);
      munmap (zone, zone->size);
      return;
    }
  chunk = _s_find_chunk (g_heap.tiny, ptr);
  if (!chunk)
    chunk = _s_find_chunk (g_heap.small, ptr);
  if (chunk)
    chunk->is_free = 1;
}