9
9
10
10
static void * chunk_mem (struct z_heap * h , chunkid_t c )
11
11
{
12
+ if (c == 0 ) {
13
+ return NULL ;
14
+ }
15
+
12
16
chunk_unit_t * buf = chunk_buf (h );
13
17
uint8_t * ret = ((uint8_t * )& buf [c ]) + chunk_header_bytes (h );
14
18
@@ -66,10 +70,37 @@ static void free_list_add(struct z_heap *h, chunkid_t c)
66
70
}
67
71
}
68
72
73
+ /* Splits a chunk "lc" into a left chunk and a right chunk at "rc".
74
+ * Leaves both chunks marked "free"
75
+ */
76
+ static void split_chunks (struct z_heap * h , chunkid_t lc , chunkid_t rc )
77
+ {
78
+ CHECK (rc > lc );
79
+ CHECK (rc - lc < chunk_size (h , lc ));
80
+
81
+ size_t sz0 = chunk_size (h , lc );
82
+ size_t lsz = rc - lc ;
83
+ size_t rsz = sz0 - lsz ;
84
+
85
+ set_chunk_size (h , lc , lsz );
86
+ set_chunk_size (h , rc , rsz );
87
+ set_left_chunk_size (h , rc , lsz );
88
+ set_left_chunk_size (h , right_chunk (h , rc ), rsz );
89
+ }
90
+
91
+ /* Does not modify free list */
92
+ static void merge_chunks (struct z_heap * h , chunkid_t lc , chunkid_t rc )
93
+ {
94
+ size_t newsz = chunk_size (h , lc ) + chunk_size (h , rc );
95
+
96
+ set_chunk_size (h , lc , newsz );
97
+ set_left_chunk_size (h , right_chunk (h , rc ), newsz );
98
+ }
99
+
69
100
/* Allocates (fit check has already been perfomred) from the next
70
101
* chunk at the specified bucket level
71
102
*/
72
- static void * split_alloc (struct z_heap * h , int bidx , size_t sz )
103
+ static chunkid_t split_alloc (struct z_heap * h , int bidx , size_t sz )
73
104
{
74
105
CHECK (h -> buckets [bidx ].next != 0
75
106
&& sz <= chunk_size (h , h -> buckets [bidx ].next ));
@@ -79,32 +110,44 @@ static void *split_alloc(struct z_heap *h, int bidx, size_t sz)
79
110
free_list_remove (h , bidx , c );
80
111
81
112
/* Split off remainder if it's usefully large */
82
- size_t rem = chunk_size (h , c ) - sz ;
113
+ if ((chunk_size (h , c ) - sz ) >= (big_heap (h ) ? 2 : 1 )) {
114
+ split_chunks (h , c , c + sz );
115
+ free_list_add (h , c + sz );
116
+ }
117
+
118
+ set_chunk_used (h , c , true);
119
+ return c ;
120
+ }
83
121
84
- CHECK (rem < h -> len );
122
+ static void free_chunks (struct z_heap * h , chunkid_t c )
123
+ {
124
+ set_chunk_used (h , c , false);
85
125
86
- if ( rem >= min_chunk_size ( h )) {
87
- chunkid_t c2 = c + sz ;
88
- chunkid_t c3 = right_chunk (h , c );
126
+ /* Merge with free right chunk? */
127
+ if (! chunk_used ( h , right_chunk ( h , c ))) {
128
+ int bi = bucket_idx ( h , chunk_size ( h , right_chunk (h , c )) );
89
129
90
- set_chunk_size (h , c , sz );
91
- set_chunk_size (h , c2 , rem );
92
- set_left_chunk_size (h , c2 , sz );
93
- set_left_chunk_size (h , c3 , rem );
94
- free_list_add (h , c2 );
130
+ free_list_remove (h , bi , right_chunk (h , c ));
131
+ merge_chunks (h , c , right_chunk (h , c ));
95
132
}
96
133
97
- set_chunk_used (h , c , true);
134
+ /* Merge with free left chunk? */
135
+ if (!chunk_used (h , left_chunk (h , c ))) {
136
+ int bi = bucket_idx (h , chunk_size (h , left_chunk (h , c )));
137
+
138
+ free_list_remove (h , bi , left_chunk (h , c ));
139
+ merge_chunks (h , left_chunk (h , c ), c );
140
+ c = left_chunk (h , c );
141
+ }
98
142
99
- return chunk_mem (h , c );
143
+ free_list_add (h , c );
100
144
}
101
145
102
146
void sys_heap_free (struct sys_heap * heap , void * mem )
103
147
{
104
148
if (mem == NULL ) {
105
149
return ; /* ISO C free() semantics */
106
150
}
107
-
108
151
struct z_heap * h = heap -> heap ;
109
152
chunkid_t c = ((uint8_t * )mem - chunk_header_bytes (h )
110
153
- (uint8_t * )chunk_buf (h )) / CHUNK_UNIT ;
@@ -115,51 +158,26 @@ void sys_heap_free(struct sys_heap *heap, void *mem)
115
158
*/
116
159
__ASSERT (chunk_used (h , c ),
117
160
"unexpected heap state (double-free?) for memory at %p" , mem );
161
+
118
162
/*
119
163
* It is easy to catch many common memory overflow cases with
120
164
* a quick check on this and next chunk header fields that are
121
165
* immediately before and after the freed memory.
122
166
*/
123
167
__ASSERT (left_chunk (h , right_chunk (h , c )) == c ,
124
- "corrupted heap bounds (buffer overflow?) for memory at %p" , mem );
125
-
126
- /* Merge with right chunk? We can just absorb it. */
127
- if (!chunk_used (h , right_chunk (h , c ))) {
128
- chunkid_t rc = right_chunk (h , c );
129
- size_t newsz = chunk_size (h , c ) + chunk_size (h , rc );
130
-
131
- free_list_remove (h , bucket_idx (h , chunk_size (h , rc )), rc );
132
- set_chunk_size (h , c , newsz );
133
- set_left_chunk_size (h , right_chunk (h , c ), newsz );
134
- }
135
-
136
- /* Merge with left chunk? It absorbs us. */
137
- if (!chunk_used (h , left_chunk (h , c ))) {
138
- chunkid_t lc = left_chunk (h , c );
139
- chunkid_t rc = right_chunk (h , c );
140
- size_t csz = chunk_size (h , c );
141
- size_t merged_sz = csz + chunk_size (h , lc );
142
-
143
- free_list_remove (h , bucket_idx (h , chunk_size (h , lc )), lc );
144
- set_chunk_size (h , lc , merged_sz );
145
- set_left_chunk_size (h , rc , merged_sz );
146
-
147
- c = lc ;
148
- }
168
+ "corrupted heap bounds (buffer overflow?) for memory at %p" ,
169
+ mem );
149
170
150
- set_chunk_used (h , c , false);
151
- free_list_add (h , c );
171
+ free_chunks (h , c );
152
172
}
153
173
154
- void * sys_heap_alloc (struct sys_heap * heap , size_t bytes )
174
+ static chunkid_t alloc_chunks (struct z_heap * h , size_t sz )
155
175
{
156
- struct z_heap * h = heap -> heap ;
157
- size_t sz = bytes_to_chunksz (h , bytes );
158
176
int bi = bucket_idx (h , sz );
159
177
struct z_heap_bucket * b = & h -> buckets [bi ];
160
178
161
- if (bytes == 0 || bi > bucket_idx (h , h -> len )) {
162
- return NULL ;
179
+ if (bi > bucket_idx (h , h -> len )) {
180
+ return 0 ;
163
181
}
164
182
165
183
/* First try a bounded count of items from the minimal bucket
@@ -199,7 +217,18 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
199
217
return split_alloc (h , minbucket , sz );
200
218
}
201
219
202
- return NULL ;
220
+ return 0 ;
221
+ }
222
+
223
+ void * sys_heap_alloc (struct sys_heap * heap , size_t bytes )
224
+ {
225
+ if (bytes == 0 ) {
226
+ return NULL ;
227
+ }
228
+ size_t chunksz = bytes_to_chunksz (heap -> heap , bytes );
229
+ chunkid_t c = alloc_chunks (heap -> heap , chunksz );
230
+
231
+ return chunk_mem (heap -> heap , c );
203
232
}
204
233
205
234
void sys_heap_init (struct sys_heap * heap , void * mem , size_t bytes )
0 commit comments