1 /*!
2 * \file src/free_atexit.c
3 *
4 * \brief .
5 *
6 * <hr>
7 *
8 * <h1><b>Copyright.</b></h1>\n
9 *
10 * Copyright (C) 2010 PCB Contributors (see ChangeLog for details)
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 *
26 * Contact addresses for paper mail and Email:
27 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
28 * haceaton@aplcomm.jhuapl.edu
29 */
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 /*!
35 * \brief We need one ID per context - short int with 64k IDs should be
36 * enough.
37 */
38 typedef unsigned int leaky_idx_t;
39
40
41 /*!
42 * \brief .
43 *
44 * This structure should be as big as void *, which should be the
45 * natural bit-width of the architecture.\n
46 * We allocate extra admin space to be as big as this union, to preserve
47 * alignment of pointers returned by malloc().\n
48 *
49 * \note In the special corner case when leaky_idx_t is wider than
50 * void * but not multiple of it, the alignment will be messed up,
51 * potentially causing slower memory access.
52 */
53 typedef union {
54 leaky_idx_t idx;
55 void *ptr;
56 } leaky_admin_t;
57
58 static void **free_list = NULL;
59 static leaky_idx_t free_size = 0;
60
61
62 /*!
63 * \brief Allocate memory, remember the pointer and free it after exit
64 * from the application.
65 */
leaky_malloc(size_t size)66 void *leaky_malloc (size_t size)
67 {
68 void *new_memory = malloc(size + sizeof(leaky_admin_t));
69
70 free_list = (void **)realloc (free_list, (free_size + 1) * sizeof(void *));
71 free_list[free_size] = new_memory;
72 *(leaky_idx_t *)new_memory = free_size;
73
74 free_size++;
75 return new_memory + sizeof(leaky_admin_t);
76 }
77
78 /*!
79 * \brief Same as leaky_malloc but this one wraps calloc().
80 */
leaky_calloc(size_t nmemb,size_t size)81 void *leaky_calloc (size_t nmemb, size_t size)
82 {
83 size_t size_ = size * nmemb;
84 void *new_memory = leaky_malloc (size_);
85
86 memset (new_memory, 0, size_);
87 return new_memory;
88 }
89
90 /*!
91 * \brief Reallocate memory, remember the new pointer and free it after
92 * exit from the application.
93 */
leaky_realloc(void * old_memory,size_t size)94 void *leaky_realloc (void* old_memory, size_t size)
95 {
96 void *new_memory;
97 leaky_idx_t i;
98
99 if (old_memory == NULL)
100 return leaky_malloc (size);
101
102 old_memory -= sizeof(leaky_admin_t);
103
104 i = *(leaky_idx_t *)old_memory;
105
106 new_memory = realloc (old_memory, size + sizeof(leaky_admin_t));
107 free_list[i] = new_memory;
108
109 return new_memory + sizeof(leaky_admin_t);
110 }
111
112 /*!
113 * \brief strdup() using leaky_malloc().
114 */
115 char *
leaky_strdup(const char * src)116 leaky_strdup (const char *src)
117 {
118 int len = strlen (src)+1;
119 char *res = leaky_malloc (len);
120 memcpy (res, src, len);
121 return res;
122 }
123
124 /*!
125 * \brief Free all allocations.
126 */
leaky_uninit(void)127 void leaky_uninit (void)
128 {
129 int i;
130
131 for (i = 0; i < free_size; i++)
132 free (free_list[i]);
133
134 free (free_list);
135 free_size = 0;
136 }
137
138 /*!
139 * \brief Set up atexit() hook.
140 *
141 * Can be avoided if leaky_uninit() is called by hand.
142 */
leaky_init(void)143 void leaky_init (void)
144 {
145 atexit(leaky_uninit);
146 }
147