1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker * Copyright © 2010 Intel Corporation
3*bbecb9d1SAndroid Build Coastguard Worker *
4*bbecb9d1SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*bbecb9d1SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*bbecb9d1SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*bbecb9d1SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*bbecb9d1SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*bbecb9d1SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*bbecb9d1SAndroid Build Coastguard Worker *
11*bbecb9d1SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*bbecb9d1SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*bbecb9d1SAndroid Build Coastguard Worker * Software.
14*bbecb9d1SAndroid Build Coastguard Worker *
15*bbecb9d1SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*bbecb9d1SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*bbecb9d1SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*bbecb9d1SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*bbecb9d1SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*bbecb9d1SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*bbecb9d1SAndroid Build Coastguard Worker * DEALINGS IN THE SOFTWARE.
22*bbecb9d1SAndroid Build Coastguard Worker */
23*bbecb9d1SAndroid Build Coastguard Worker
24*bbecb9d1SAndroid Build Coastguard Worker #include <assert.h>
25*bbecb9d1SAndroid Build Coastguard Worker #include <stdlib.h>
26*bbecb9d1SAndroid Build Coastguard Worker #include <stdarg.h>
27*bbecb9d1SAndroid Build Coastguard Worker #include <stdio.h>
28*bbecb9d1SAndroid Build Coastguard Worker #include <string.h>
29*bbecb9d1SAndroid Build Coastguard Worker #include <stdint.h>
30*bbecb9d1SAndroid Build Coastguard Worker
31*bbecb9d1SAndroid Build Coastguard Worker #include "util/macros.h"
32*bbecb9d1SAndroid Build Coastguard Worker #include "util/u_math.h"
33*bbecb9d1SAndroid Build Coastguard Worker
34*bbecb9d1SAndroid Build Coastguard Worker /* Some versions of MinGW are missing _vscprintf's declaration, although they
35*bbecb9d1SAndroid Build Coastguard Worker * still provide the symbol in the import library. */
36*bbecb9d1SAndroid Build Coastguard Worker #ifdef __MINGW32__
37*bbecb9d1SAndroid Build Coastguard Worker _CRTIMP int _vscprintf(const char *format, va_list argptr);
38*bbecb9d1SAndroid Build Coastguard Worker #endif
39*bbecb9d1SAndroid Build Coastguard Worker
40*bbecb9d1SAndroid Build Coastguard Worker #include "ralloc.h"
41*bbecb9d1SAndroid Build Coastguard Worker
42*bbecb9d1SAndroid Build Coastguard Worker #ifndef va_copy
43*bbecb9d1SAndroid Build Coastguard Worker #ifdef __va_copy
44*bbecb9d1SAndroid Build Coastguard Worker #define va_copy(dest, src) __va_copy((dest), (src))
45*bbecb9d1SAndroid Build Coastguard Worker #else
46*bbecb9d1SAndroid Build Coastguard Worker #define va_copy(dest, src) (dest) = (src)
47*bbecb9d1SAndroid Build Coastguard Worker #endif
48*bbecb9d1SAndroid Build Coastguard Worker #endif
49*bbecb9d1SAndroid Build Coastguard Worker
50*bbecb9d1SAndroid Build Coastguard Worker #define CANARY 0x5A1106
51*bbecb9d1SAndroid Build Coastguard Worker
52*bbecb9d1SAndroid Build Coastguard Worker /* Align the header's size so that ralloc() allocations will return with the
53*bbecb9d1SAndroid Build Coastguard Worker * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
54*bbecb9d1SAndroid Build Coastguard Worker * 64-bit), avoiding performance penalities on x86 and alignment faults on
55*bbecb9d1SAndroid Build Coastguard Worker * ARM.
56*bbecb9d1SAndroid Build Coastguard Worker */
57*bbecb9d1SAndroid Build Coastguard Worker struct
58*bbecb9d1SAndroid Build Coastguard Worker #ifdef _MSC_VER
59*bbecb9d1SAndroid Build Coastguard Worker #if _WIN64
60*bbecb9d1SAndroid Build Coastguard Worker __declspec(align(16))
61*bbecb9d1SAndroid Build Coastguard Worker #else
62*bbecb9d1SAndroid Build Coastguard Worker __declspec(align(8))
63*bbecb9d1SAndroid Build Coastguard Worker #endif
64*bbecb9d1SAndroid Build Coastguard Worker #elif defined(__LP64__)
65*bbecb9d1SAndroid Build Coastguard Worker __attribute__((aligned(16)))
66*bbecb9d1SAndroid Build Coastguard Worker #else
67*bbecb9d1SAndroid Build Coastguard Worker __attribute__((aligned(8)))
68*bbecb9d1SAndroid Build Coastguard Worker #endif
69*bbecb9d1SAndroid Build Coastguard Worker ralloc_header
70*bbecb9d1SAndroid Build Coastguard Worker {
71*bbecb9d1SAndroid Build Coastguard Worker #ifndef NDEBUG
72*bbecb9d1SAndroid Build Coastguard Worker /* A canary value used to determine whether a pointer is ralloc'd. */
73*bbecb9d1SAndroid Build Coastguard Worker unsigned canary;
74*bbecb9d1SAndroid Build Coastguard Worker #endif
75*bbecb9d1SAndroid Build Coastguard Worker
76*bbecb9d1SAndroid Build Coastguard Worker struct ralloc_header *parent;
77*bbecb9d1SAndroid Build Coastguard Worker
78*bbecb9d1SAndroid Build Coastguard Worker /* The first child (head of a linked list) */
79*bbecb9d1SAndroid Build Coastguard Worker struct ralloc_header *child;
80*bbecb9d1SAndroid Build Coastguard Worker
81*bbecb9d1SAndroid Build Coastguard Worker /* Linked list of siblings */
82*bbecb9d1SAndroid Build Coastguard Worker struct ralloc_header *prev;
83*bbecb9d1SAndroid Build Coastguard Worker struct ralloc_header *next;
84*bbecb9d1SAndroid Build Coastguard Worker
85*bbecb9d1SAndroid Build Coastguard Worker void (*destructor)(void *);
86*bbecb9d1SAndroid Build Coastguard Worker };
87*bbecb9d1SAndroid Build Coastguard Worker
88*bbecb9d1SAndroid Build Coastguard Worker typedef struct ralloc_header ralloc_header;
89*bbecb9d1SAndroid Build Coastguard Worker
90*bbecb9d1SAndroid Build Coastguard Worker static void unlink_block(ralloc_header *info);
91*bbecb9d1SAndroid Build Coastguard Worker static void unsafe_free(ralloc_header *info);
92*bbecb9d1SAndroid Build Coastguard Worker
93*bbecb9d1SAndroid Build Coastguard Worker static ralloc_header *
get_header(const void * ptr)94*bbecb9d1SAndroid Build Coastguard Worker get_header(const void *ptr)
95*bbecb9d1SAndroid Build Coastguard Worker {
96*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info = (ralloc_header *) (((char *) ptr) -
97*bbecb9d1SAndroid Build Coastguard Worker sizeof(ralloc_header));
98*bbecb9d1SAndroid Build Coastguard Worker assert(info->canary == CANARY);
99*bbecb9d1SAndroid Build Coastguard Worker return info;
100*bbecb9d1SAndroid Build Coastguard Worker }
101*bbecb9d1SAndroid Build Coastguard Worker
102*bbecb9d1SAndroid Build Coastguard Worker #define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
103*bbecb9d1SAndroid Build Coastguard Worker
104*bbecb9d1SAndroid Build Coastguard Worker static void
add_child(ralloc_header * parent,ralloc_header * info)105*bbecb9d1SAndroid Build Coastguard Worker add_child(ralloc_header *parent, ralloc_header *info)
106*bbecb9d1SAndroid Build Coastguard Worker {
107*bbecb9d1SAndroid Build Coastguard Worker if (parent != NULL) {
108*bbecb9d1SAndroid Build Coastguard Worker info->parent = parent;
109*bbecb9d1SAndroid Build Coastguard Worker info->next = parent->child;
110*bbecb9d1SAndroid Build Coastguard Worker parent->child = info;
111*bbecb9d1SAndroid Build Coastguard Worker
112*bbecb9d1SAndroid Build Coastguard Worker if (info->next != NULL)
113*bbecb9d1SAndroid Build Coastguard Worker info->next->prev = info;
114*bbecb9d1SAndroid Build Coastguard Worker }
115*bbecb9d1SAndroid Build Coastguard Worker }
116*bbecb9d1SAndroid Build Coastguard Worker
117*bbecb9d1SAndroid Build Coastguard Worker void *
ralloc_context(const void * ctx)118*bbecb9d1SAndroid Build Coastguard Worker ralloc_context(const void *ctx)
119*bbecb9d1SAndroid Build Coastguard Worker {
120*bbecb9d1SAndroid Build Coastguard Worker return ralloc_size(ctx, 0);
121*bbecb9d1SAndroid Build Coastguard Worker }
122*bbecb9d1SAndroid Build Coastguard Worker
123*bbecb9d1SAndroid Build Coastguard Worker void *
ralloc_size(const void * ctx,size_t size)124*bbecb9d1SAndroid Build Coastguard Worker ralloc_size(const void *ctx, size_t size)
125*bbecb9d1SAndroid Build Coastguard Worker {
126*bbecb9d1SAndroid Build Coastguard Worker /* Some malloc allocation doesn't always align to 16 bytes even on 64 bits
127*bbecb9d1SAndroid Build Coastguard Worker * system, from Android bionic/tests/malloc_test.cpp:
128*bbecb9d1SAndroid Build Coastguard Worker * - Allocations of a size that rounds up to a multiple of 16 bytes
129*bbecb9d1SAndroid Build Coastguard Worker * must have at least 16 byte alignment.
130*bbecb9d1SAndroid Build Coastguard Worker * - Allocations of a size that rounds up to a multiple of 8 bytes and
131*bbecb9d1SAndroid Build Coastguard Worker * not 16 bytes, are only required to have at least 8 byte alignment.
132*bbecb9d1SAndroid Build Coastguard Worker */
133*bbecb9d1SAndroid Build Coastguard Worker void *block = malloc(align64(size + sizeof(ralloc_header),
134*bbecb9d1SAndroid Build Coastguard Worker alignof(ralloc_header)));
135*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info;
136*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *parent;
137*bbecb9d1SAndroid Build Coastguard Worker
138*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(block == NULL))
139*bbecb9d1SAndroid Build Coastguard Worker return NULL;
140*bbecb9d1SAndroid Build Coastguard Worker
141*bbecb9d1SAndroid Build Coastguard Worker info = (ralloc_header *) block;
142*bbecb9d1SAndroid Build Coastguard Worker /* measurements have shown that calloc is slower (because of
143*bbecb9d1SAndroid Build Coastguard Worker * the multiplication overflow checking?), so clear things
144*bbecb9d1SAndroid Build Coastguard Worker * manually
145*bbecb9d1SAndroid Build Coastguard Worker */
146*bbecb9d1SAndroid Build Coastguard Worker info->parent = NULL;
147*bbecb9d1SAndroid Build Coastguard Worker info->child = NULL;
148*bbecb9d1SAndroid Build Coastguard Worker info->prev = NULL;
149*bbecb9d1SAndroid Build Coastguard Worker info->next = NULL;
150*bbecb9d1SAndroid Build Coastguard Worker info->destructor = NULL;
151*bbecb9d1SAndroid Build Coastguard Worker
152*bbecb9d1SAndroid Build Coastguard Worker parent = ctx != NULL ? get_header(ctx) : NULL;
153*bbecb9d1SAndroid Build Coastguard Worker
154*bbecb9d1SAndroid Build Coastguard Worker add_child(parent, info);
155*bbecb9d1SAndroid Build Coastguard Worker
156*bbecb9d1SAndroid Build Coastguard Worker #ifndef NDEBUG
157*bbecb9d1SAndroid Build Coastguard Worker info->canary = CANARY;
158*bbecb9d1SAndroid Build Coastguard Worker #endif
159*bbecb9d1SAndroid Build Coastguard Worker
160*bbecb9d1SAndroid Build Coastguard Worker return PTR_FROM_HEADER(info);
161*bbecb9d1SAndroid Build Coastguard Worker }
162*bbecb9d1SAndroid Build Coastguard Worker
163*bbecb9d1SAndroid Build Coastguard Worker void *
rzalloc_size(const void * ctx,size_t size)164*bbecb9d1SAndroid Build Coastguard Worker rzalloc_size(const void *ctx, size_t size)
165*bbecb9d1SAndroid Build Coastguard Worker {
166*bbecb9d1SAndroid Build Coastguard Worker void *ptr = ralloc_size(ctx, size);
167*bbecb9d1SAndroid Build Coastguard Worker
168*bbecb9d1SAndroid Build Coastguard Worker if (likely(ptr))
169*bbecb9d1SAndroid Build Coastguard Worker memset(ptr, 0, size);
170*bbecb9d1SAndroid Build Coastguard Worker
171*bbecb9d1SAndroid Build Coastguard Worker return ptr;
172*bbecb9d1SAndroid Build Coastguard Worker }
173*bbecb9d1SAndroid Build Coastguard Worker
174*bbecb9d1SAndroid Build Coastguard Worker /* helper function - assumes ptr != NULL */
175*bbecb9d1SAndroid Build Coastguard Worker static void *
resize(void * ptr,size_t size)176*bbecb9d1SAndroid Build Coastguard Worker resize(void *ptr, size_t size)
177*bbecb9d1SAndroid Build Coastguard Worker {
178*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *child, *old, *info;
179*bbecb9d1SAndroid Build Coastguard Worker
180*bbecb9d1SAndroid Build Coastguard Worker old = get_header(ptr);
181*bbecb9d1SAndroid Build Coastguard Worker info = realloc(old, align64(size + sizeof(ralloc_header),
182*bbecb9d1SAndroid Build Coastguard Worker alignof(ralloc_header)));
183*bbecb9d1SAndroid Build Coastguard Worker
184*bbecb9d1SAndroid Build Coastguard Worker if (info == NULL)
185*bbecb9d1SAndroid Build Coastguard Worker return NULL;
186*bbecb9d1SAndroid Build Coastguard Worker
187*bbecb9d1SAndroid Build Coastguard Worker /* Update parent and sibling's links to the reallocated node. */
188*bbecb9d1SAndroid Build Coastguard Worker if (info != old && info->parent != NULL) {
189*bbecb9d1SAndroid Build Coastguard Worker if (info->parent->child == old)
190*bbecb9d1SAndroid Build Coastguard Worker info->parent->child = info;
191*bbecb9d1SAndroid Build Coastguard Worker
192*bbecb9d1SAndroid Build Coastguard Worker if (info->prev != NULL)
193*bbecb9d1SAndroid Build Coastguard Worker info->prev->next = info;
194*bbecb9d1SAndroid Build Coastguard Worker
195*bbecb9d1SAndroid Build Coastguard Worker if (info->next != NULL)
196*bbecb9d1SAndroid Build Coastguard Worker info->next->prev = info;
197*bbecb9d1SAndroid Build Coastguard Worker }
198*bbecb9d1SAndroid Build Coastguard Worker
199*bbecb9d1SAndroid Build Coastguard Worker /* Update child->parent links for all children */
200*bbecb9d1SAndroid Build Coastguard Worker for (child = info->child; child != NULL; child = child->next)
201*bbecb9d1SAndroid Build Coastguard Worker child->parent = info;
202*bbecb9d1SAndroid Build Coastguard Worker
203*bbecb9d1SAndroid Build Coastguard Worker return PTR_FROM_HEADER(info);
204*bbecb9d1SAndroid Build Coastguard Worker }
205*bbecb9d1SAndroid Build Coastguard Worker
206*bbecb9d1SAndroid Build Coastguard Worker void *
reralloc_size(const void * ctx,void * ptr,size_t size)207*bbecb9d1SAndroid Build Coastguard Worker reralloc_size(const void *ctx, void *ptr, size_t size)
208*bbecb9d1SAndroid Build Coastguard Worker {
209*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
210*bbecb9d1SAndroid Build Coastguard Worker return ralloc_size(ctx, size);
211*bbecb9d1SAndroid Build Coastguard Worker
212*bbecb9d1SAndroid Build Coastguard Worker assert(ralloc_parent(ptr) == ctx);
213*bbecb9d1SAndroid Build Coastguard Worker return resize(ptr, size);
214*bbecb9d1SAndroid Build Coastguard Worker }
215*bbecb9d1SAndroid Build Coastguard Worker
216*bbecb9d1SAndroid Build Coastguard Worker void *
rerzalloc_size(const void * ctx,void * ptr,size_t old_size,size_t new_size)217*bbecb9d1SAndroid Build Coastguard Worker rerzalloc_size(const void *ctx, void *ptr, size_t old_size, size_t new_size)
218*bbecb9d1SAndroid Build Coastguard Worker {
219*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
220*bbecb9d1SAndroid Build Coastguard Worker return rzalloc_size(ctx, new_size);
221*bbecb9d1SAndroid Build Coastguard Worker
222*bbecb9d1SAndroid Build Coastguard Worker assert(ralloc_parent(ptr) == ctx);
223*bbecb9d1SAndroid Build Coastguard Worker ptr = resize(ptr, new_size);
224*bbecb9d1SAndroid Build Coastguard Worker
225*bbecb9d1SAndroid Build Coastguard Worker if (new_size > old_size)
226*bbecb9d1SAndroid Build Coastguard Worker memset((char *)ptr + old_size, 0, new_size - old_size);
227*bbecb9d1SAndroid Build Coastguard Worker
228*bbecb9d1SAndroid Build Coastguard Worker return ptr;
229*bbecb9d1SAndroid Build Coastguard Worker }
230*bbecb9d1SAndroid Build Coastguard Worker
231*bbecb9d1SAndroid Build Coastguard Worker void *
ralloc_array_size(const void * ctx,size_t size,unsigned count)232*bbecb9d1SAndroid Build Coastguard Worker ralloc_array_size(const void *ctx, size_t size, unsigned count)
233*bbecb9d1SAndroid Build Coastguard Worker {
234*bbecb9d1SAndroid Build Coastguard Worker if (count > SIZE_MAX/size)
235*bbecb9d1SAndroid Build Coastguard Worker return NULL;
236*bbecb9d1SAndroid Build Coastguard Worker
237*bbecb9d1SAndroid Build Coastguard Worker return ralloc_size(ctx, size * count);
238*bbecb9d1SAndroid Build Coastguard Worker }
239*bbecb9d1SAndroid Build Coastguard Worker
240*bbecb9d1SAndroid Build Coastguard Worker void *
rzalloc_array_size(const void * ctx,size_t size,unsigned count)241*bbecb9d1SAndroid Build Coastguard Worker rzalloc_array_size(const void *ctx, size_t size, unsigned count)
242*bbecb9d1SAndroid Build Coastguard Worker {
243*bbecb9d1SAndroid Build Coastguard Worker if (count > SIZE_MAX/size)
244*bbecb9d1SAndroid Build Coastguard Worker return NULL;
245*bbecb9d1SAndroid Build Coastguard Worker
246*bbecb9d1SAndroid Build Coastguard Worker return rzalloc_size(ctx, size * count);
247*bbecb9d1SAndroid Build Coastguard Worker }
248*bbecb9d1SAndroid Build Coastguard Worker
249*bbecb9d1SAndroid Build Coastguard Worker void *
reralloc_array_size(const void * ctx,void * ptr,size_t size,unsigned count)250*bbecb9d1SAndroid Build Coastguard Worker reralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
251*bbecb9d1SAndroid Build Coastguard Worker {
252*bbecb9d1SAndroid Build Coastguard Worker if (count > SIZE_MAX/size)
253*bbecb9d1SAndroid Build Coastguard Worker return NULL;
254*bbecb9d1SAndroid Build Coastguard Worker
255*bbecb9d1SAndroid Build Coastguard Worker return reralloc_size(ctx, ptr, size * count);
256*bbecb9d1SAndroid Build Coastguard Worker }
257*bbecb9d1SAndroid Build Coastguard Worker
258*bbecb9d1SAndroid Build Coastguard Worker void *
rerzalloc_array_size(const void * ctx,void * ptr,size_t size,unsigned old_count,unsigned new_count)259*bbecb9d1SAndroid Build Coastguard Worker rerzalloc_array_size(const void *ctx, void *ptr, size_t size,
260*bbecb9d1SAndroid Build Coastguard Worker unsigned old_count, unsigned new_count)
261*bbecb9d1SAndroid Build Coastguard Worker {
262*bbecb9d1SAndroid Build Coastguard Worker if (new_count > SIZE_MAX/size)
263*bbecb9d1SAndroid Build Coastguard Worker return NULL;
264*bbecb9d1SAndroid Build Coastguard Worker
265*bbecb9d1SAndroid Build Coastguard Worker return rerzalloc_size(ctx, ptr, size * old_count, size * new_count);
266*bbecb9d1SAndroid Build Coastguard Worker }
267*bbecb9d1SAndroid Build Coastguard Worker
268*bbecb9d1SAndroid Build Coastguard Worker void
ralloc_free(void * ptr)269*bbecb9d1SAndroid Build Coastguard Worker ralloc_free(void *ptr)
270*bbecb9d1SAndroid Build Coastguard Worker {
271*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info;
272*bbecb9d1SAndroid Build Coastguard Worker
273*bbecb9d1SAndroid Build Coastguard Worker if (ptr == NULL)
274*bbecb9d1SAndroid Build Coastguard Worker return;
275*bbecb9d1SAndroid Build Coastguard Worker
276*bbecb9d1SAndroid Build Coastguard Worker info = get_header(ptr);
277*bbecb9d1SAndroid Build Coastguard Worker unlink_block(info);
278*bbecb9d1SAndroid Build Coastguard Worker unsafe_free(info);
279*bbecb9d1SAndroid Build Coastguard Worker }
280*bbecb9d1SAndroid Build Coastguard Worker
281*bbecb9d1SAndroid Build Coastguard Worker static void
unlink_block(ralloc_header * info)282*bbecb9d1SAndroid Build Coastguard Worker unlink_block(ralloc_header *info)
283*bbecb9d1SAndroid Build Coastguard Worker {
284*bbecb9d1SAndroid Build Coastguard Worker /* Unlink from parent & siblings */
285*bbecb9d1SAndroid Build Coastguard Worker if (info->parent != NULL) {
286*bbecb9d1SAndroid Build Coastguard Worker if (info->parent->child == info)
287*bbecb9d1SAndroid Build Coastguard Worker info->parent->child = info->next;
288*bbecb9d1SAndroid Build Coastguard Worker
289*bbecb9d1SAndroid Build Coastguard Worker if (info->prev != NULL)
290*bbecb9d1SAndroid Build Coastguard Worker info->prev->next = info->next;
291*bbecb9d1SAndroid Build Coastguard Worker
292*bbecb9d1SAndroid Build Coastguard Worker if (info->next != NULL)
293*bbecb9d1SAndroid Build Coastguard Worker info->next->prev = info->prev;
294*bbecb9d1SAndroid Build Coastguard Worker }
295*bbecb9d1SAndroid Build Coastguard Worker info->parent = NULL;
296*bbecb9d1SAndroid Build Coastguard Worker info->prev = NULL;
297*bbecb9d1SAndroid Build Coastguard Worker info->next = NULL;
298*bbecb9d1SAndroid Build Coastguard Worker }
299*bbecb9d1SAndroid Build Coastguard Worker
300*bbecb9d1SAndroid Build Coastguard Worker static void
unsafe_free(ralloc_header * info)301*bbecb9d1SAndroid Build Coastguard Worker unsafe_free(ralloc_header *info)
302*bbecb9d1SAndroid Build Coastguard Worker {
303*bbecb9d1SAndroid Build Coastguard Worker /* Recursively free any children...don't waste time unlinking them. */
304*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *temp;
305*bbecb9d1SAndroid Build Coastguard Worker while (info->child != NULL) {
306*bbecb9d1SAndroid Build Coastguard Worker temp = info->child;
307*bbecb9d1SAndroid Build Coastguard Worker info->child = temp->next;
308*bbecb9d1SAndroid Build Coastguard Worker unsafe_free(temp);
309*bbecb9d1SAndroid Build Coastguard Worker }
310*bbecb9d1SAndroid Build Coastguard Worker
311*bbecb9d1SAndroid Build Coastguard Worker /* Free the block itself. Call the destructor first, if any. */
312*bbecb9d1SAndroid Build Coastguard Worker if (info->destructor != NULL)
313*bbecb9d1SAndroid Build Coastguard Worker info->destructor(PTR_FROM_HEADER(info));
314*bbecb9d1SAndroid Build Coastguard Worker
315*bbecb9d1SAndroid Build Coastguard Worker free(info);
316*bbecb9d1SAndroid Build Coastguard Worker }
317*bbecb9d1SAndroid Build Coastguard Worker
318*bbecb9d1SAndroid Build Coastguard Worker void
ralloc_steal(const void * new_ctx,void * ptr)319*bbecb9d1SAndroid Build Coastguard Worker ralloc_steal(const void *new_ctx, void *ptr)
320*bbecb9d1SAndroid Build Coastguard Worker {
321*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info, *parent;
322*bbecb9d1SAndroid Build Coastguard Worker
323*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
324*bbecb9d1SAndroid Build Coastguard Worker return;
325*bbecb9d1SAndroid Build Coastguard Worker
326*bbecb9d1SAndroid Build Coastguard Worker info = get_header(ptr);
327*bbecb9d1SAndroid Build Coastguard Worker parent = new_ctx ? get_header(new_ctx) : NULL;
328*bbecb9d1SAndroid Build Coastguard Worker
329*bbecb9d1SAndroid Build Coastguard Worker unlink_block(info);
330*bbecb9d1SAndroid Build Coastguard Worker
331*bbecb9d1SAndroid Build Coastguard Worker add_child(parent, info);
332*bbecb9d1SAndroid Build Coastguard Worker }
333*bbecb9d1SAndroid Build Coastguard Worker
334*bbecb9d1SAndroid Build Coastguard Worker void
ralloc_adopt(const void * new_ctx,void * old_ctx)335*bbecb9d1SAndroid Build Coastguard Worker ralloc_adopt(const void *new_ctx, void *old_ctx)
336*bbecb9d1SAndroid Build Coastguard Worker {
337*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *new_info, *old_info, *child;
338*bbecb9d1SAndroid Build Coastguard Worker
339*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(old_ctx == NULL))
340*bbecb9d1SAndroid Build Coastguard Worker return;
341*bbecb9d1SAndroid Build Coastguard Worker
342*bbecb9d1SAndroid Build Coastguard Worker old_info = get_header(old_ctx);
343*bbecb9d1SAndroid Build Coastguard Worker new_info = get_header(new_ctx);
344*bbecb9d1SAndroid Build Coastguard Worker
345*bbecb9d1SAndroid Build Coastguard Worker /* If there are no children, bail. */
346*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(old_info->child == NULL))
347*bbecb9d1SAndroid Build Coastguard Worker return;
348*bbecb9d1SAndroid Build Coastguard Worker
349*bbecb9d1SAndroid Build Coastguard Worker /* Set all the children's parent to new_ctx; get a pointer to the last child. */
350*bbecb9d1SAndroid Build Coastguard Worker for (child = old_info->child; child->next != NULL; child = child->next) {
351*bbecb9d1SAndroid Build Coastguard Worker child->parent = new_info;
352*bbecb9d1SAndroid Build Coastguard Worker }
353*bbecb9d1SAndroid Build Coastguard Worker child->parent = new_info;
354*bbecb9d1SAndroid Build Coastguard Worker
355*bbecb9d1SAndroid Build Coastguard Worker /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
356*bbecb9d1SAndroid Build Coastguard Worker child->next = new_info->child;
357*bbecb9d1SAndroid Build Coastguard Worker if (child->next)
358*bbecb9d1SAndroid Build Coastguard Worker child->next->prev = child;
359*bbecb9d1SAndroid Build Coastguard Worker new_info->child = old_info->child;
360*bbecb9d1SAndroid Build Coastguard Worker old_info->child = NULL;
361*bbecb9d1SAndroid Build Coastguard Worker }
362*bbecb9d1SAndroid Build Coastguard Worker
363*bbecb9d1SAndroid Build Coastguard Worker void *
ralloc_parent(const void * ptr)364*bbecb9d1SAndroid Build Coastguard Worker ralloc_parent(const void *ptr)
365*bbecb9d1SAndroid Build Coastguard Worker {
366*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info;
367*bbecb9d1SAndroid Build Coastguard Worker
368*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
369*bbecb9d1SAndroid Build Coastguard Worker return NULL;
370*bbecb9d1SAndroid Build Coastguard Worker
371*bbecb9d1SAndroid Build Coastguard Worker info = get_header(ptr);
372*bbecb9d1SAndroid Build Coastguard Worker return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
373*bbecb9d1SAndroid Build Coastguard Worker }
374*bbecb9d1SAndroid Build Coastguard Worker
375*bbecb9d1SAndroid Build Coastguard Worker void
ralloc_set_destructor(const void * ptr,void (* destructor)(void *))376*bbecb9d1SAndroid Build Coastguard Worker ralloc_set_destructor(const void *ptr, void(*destructor)(void *))
377*bbecb9d1SAndroid Build Coastguard Worker {
378*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *info = get_header(ptr);
379*bbecb9d1SAndroid Build Coastguard Worker info->destructor = destructor;
380*bbecb9d1SAndroid Build Coastguard Worker }
381*bbecb9d1SAndroid Build Coastguard Worker
382*bbecb9d1SAndroid Build Coastguard Worker char *
ralloc_strdup(const void * ctx,const char * str)383*bbecb9d1SAndroid Build Coastguard Worker ralloc_strdup(const void *ctx, const char *str)
384*bbecb9d1SAndroid Build Coastguard Worker {
385*bbecb9d1SAndroid Build Coastguard Worker size_t n;
386*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
387*bbecb9d1SAndroid Build Coastguard Worker
388*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(str == NULL))
389*bbecb9d1SAndroid Build Coastguard Worker return NULL;
390*bbecb9d1SAndroid Build Coastguard Worker
391*bbecb9d1SAndroid Build Coastguard Worker n = strlen(str);
392*bbecb9d1SAndroid Build Coastguard Worker ptr = ralloc_array(ctx, char, n + 1);
393*bbecb9d1SAndroid Build Coastguard Worker memcpy(ptr, str, n);
394*bbecb9d1SAndroid Build Coastguard Worker ptr[n] = '\0';
395*bbecb9d1SAndroid Build Coastguard Worker return ptr;
396*bbecb9d1SAndroid Build Coastguard Worker }
397*bbecb9d1SAndroid Build Coastguard Worker
398*bbecb9d1SAndroid Build Coastguard Worker char *
ralloc_strndup(const void * ctx,const char * str,size_t max)399*bbecb9d1SAndroid Build Coastguard Worker ralloc_strndup(const void *ctx, const char *str, size_t max)
400*bbecb9d1SAndroid Build Coastguard Worker {
401*bbecb9d1SAndroid Build Coastguard Worker size_t n;
402*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
403*bbecb9d1SAndroid Build Coastguard Worker
404*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(str == NULL))
405*bbecb9d1SAndroid Build Coastguard Worker return NULL;
406*bbecb9d1SAndroid Build Coastguard Worker
407*bbecb9d1SAndroid Build Coastguard Worker n = strnlen(str, max);
408*bbecb9d1SAndroid Build Coastguard Worker ptr = ralloc_array(ctx, char, n + 1);
409*bbecb9d1SAndroid Build Coastguard Worker memcpy(ptr, str, n);
410*bbecb9d1SAndroid Build Coastguard Worker ptr[n] = '\0';
411*bbecb9d1SAndroid Build Coastguard Worker return ptr;
412*bbecb9d1SAndroid Build Coastguard Worker }
413*bbecb9d1SAndroid Build Coastguard Worker
414*bbecb9d1SAndroid Build Coastguard Worker /* helper routine for strcat/strncat - n is the exact amount to copy */
415*bbecb9d1SAndroid Build Coastguard Worker static bool
cat(char ** dest,const char * str,size_t n)416*bbecb9d1SAndroid Build Coastguard Worker cat(char **dest, const char *str, size_t n)
417*bbecb9d1SAndroid Build Coastguard Worker {
418*bbecb9d1SAndroid Build Coastguard Worker char *both;
419*bbecb9d1SAndroid Build Coastguard Worker size_t existing_length;
420*bbecb9d1SAndroid Build Coastguard Worker assert(dest != NULL && *dest != NULL);
421*bbecb9d1SAndroid Build Coastguard Worker
422*bbecb9d1SAndroid Build Coastguard Worker existing_length = strlen(*dest);
423*bbecb9d1SAndroid Build Coastguard Worker both = resize(*dest, existing_length + n + 1);
424*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(both == NULL))
425*bbecb9d1SAndroid Build Coastguard Worker return false;
426*bbecb9d1SAndroid Build Coastguard Worker
427*bbecb9d1SAndroid Build Coastguard Worker memcpy(both + existing_length, str, n);
428*bbecb9d1SAndroid Build Coastguard Worker both[existing_length + n] = '\0';
429*bbecb9d1SAndroid Build Coastguard Worker
430*bbecb9d1SAndroid Build Coastguard Worker *dest = both;
431*bbecb9d1SAndroid Build Coastguard Worker return true;
432*bbecb9d1SAndroid Build Coastguard Worker }
433*bbecb9d1SAndroid Build Coastguard Worker
434*bbecb9d1SAndroid Build Coastguard Worker
435*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_strcat(char ** dest,const char * str)436*bbecb9d1SAndroid Build Coastguard Worker ralloc_strcat(char **dest, const char *str)
437*bbecb9d1SAndroid Build Coastguard Worker {
438*bbecb9d1SAndroid Build Coastguard Worker return cat(dest, str, strlen(str));
439*bbecb9d1SAndroid Build Coastguard Worker }
440*bbecb9d1SAndroid Build Coastguard Worker
441*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_strncat(char ** dest,const char * str,size_t n)442*bbecb9d1SAndroid Build Coastguard Worker ralloc_strncat(char **dest, const char *str, size_t n)
443*bbecb9d1SAndroid Build Coastguard Worker {
444*bbecb9d1SAndroid Build Coastguard Worker return cat(dest, str, strnlen(str, n));
445*bbecb9d1SAndroid Build Coastguard Worker }
446*bbecb9d1SAndroid Build Coastguard Worker
447*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_str_append(char ** dest,const char * str,size_t existing_length,size_t str_size)448*bbecb9d1SAndroid Build Coastguard Worker ralloc_str_append(char **dest, const char *str,
449*bbecb9d1SAndroid Build Coastguard Worker size_t existing_length, size_t str_size)
450*bbecb9d1SAndroid Build Coastguard Worker {
451*bbecb9d1SAndroid Build Coastguard Worker char *both;
452*bbecb9d1SAndroid Build Coastguard Worker assert(dest != NULL && *dest != NULL);
453*bbecb9d1SAndroid Build Coastguard Worker
454*bbecb9d1SAndroid Build Coastguard Worker both = resize(*dest, existing_length + str_size + 1);
455*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(both == NULL))
456*bbecb9d1SAndroid Build Coastguard Worker return false;
457*bbecb9d1SAndroid Build Coastguard Worker
458*bbecb9d1SAndroid Build Coastguard Worker memcpy(both + existing_length, str, str_size);
459*bbecb9d1SAndroid Build Coastguard Worker both[existing_length + str_size] = '\0';
460*bbecb9d1SAndroid Build Coastguard Worker
461*bbecb9d1SAndroid Build Coastguard Worker *dest = both;
462*bbecb9d1SAndroid Build Coastguard Worker
463*bbecb9d1SAndroid Build Coastguard Worker return true;
464*bbecb9d1SAndroid Build Coastguard Worker }
465*bbecb9d1SAndroid Build Coastguard Worker
466*bbecb9d1SAndroid Build Coastguard Worker char *
ralloc_asprintf(const void * ctx,const char * fmt,...)467*bbecb9d1SAndroid Build Coastguard Worker ralloc_asprintf(const void *ctx, const char *fmt, ...)
468*bbecb9d1SAndroid Build Coastguard Worker {
469*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
470*bbecb9d1SAndroid Build Coastguard Worker va_list args;
471*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
472*bbecb9d1SAndroid Build Coastguard Worker ptr = ralloc_vasprintf(ctx, fmt, args);
473*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
474*bbecb9d1SAndroid Build Coastguard Worker return ptr;
475*bbecb9d1SAndroid Build Coastguard Worker }
476*bbecb9d1SAndroid Build Coastguard Worker
477*bbecb9d1SAndroid Build Coastguard Worker /* Return the length of the string that would be generated by a printf-style
478*bbecb9d1SAndroid Build Coastguard Worker * format and argument list, not including the \0 byte.
479*bbecb9d1SAndroid Build Coastguard Worker */
480*bbecb9d1SAndroid Build Coastguard Worker static size_t
printf_length(const char * fmt,va_list untouched_args)481*bbecb9d1SAndroid Build Coastguard Worker printf_length(const char *fmt, va_list untouched_args)
482*bbecb9d1SAndroid Build Coastguard Worker {
483*bbecb9d1SAndroid Build Coastguard Worker int size;
484*bbecb9d1SAndroid Build Coastguard Worker char junk;
485*bbecb9d1SAndroid Build Coastguard Worker
486*bbecb9d1SAndroid Build Coastguard Worker /* Make a copy of the va_list so the original caller can still use it */
487*bbecb9d1SAndroid Build Coastguard Worker va_list args;
488*bbecb9d1SAndroid Build Coastguard Worker va_copy(args, untouched_args);
489*bbecb9d1SAndroid Build Coastguard Worker
490*bbecb9d1SAndroid Build Coastguard Worker #ifdef _WIN32
491*bbecb9d1SAndroid Build Coastguard Worker /* We need to use _vcsprintf to calculate the size as vsnprintf returns -1
492*bbecb9d1SAndroid Build Coastguard Worker * if the number of characters to write is greater than count.
493*bbecb9d1SAndroid Build Coastguard Worker */
494*bbecb9d1SAndroid Build Coastguard Worker size = _vscprintf(fmt, args);
495*bbecb9d1SAndroid Build Coastguard Worker (void)junk;
496*bbecb9d1SAndroid Build Coastguard Worker #else
497*bbecb9d1SAndroid Build Coastguard Worker size = vsnprintf(&junk, 1, fmt, args);
498*bbecb9d1SAndroid Build Coastguard Worker #endif
499*bbecb9d1SAndroid Build Coastguard Worker assert(size >= 0);
500*bbecb9d1SAndroid Build Coastguard Worker
501*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
502*bbecb9d1SAndroid Build Coastguard Worker
503*bbecb9d1SAndroid Build Coastguard Worker return size;
504*bbecb9d1SAndroid Build Coastguard Worker }
505*bbecb9d1SAndroid Build Coastguard Worker
506*bbecb9d1SAndroid Build Coastguard Worker char *
ralloc_vasprintf(const void * ctx,const char * fmt,va_list args)507*bbecb9d1SAndroid Build Coastguard Worker ralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
508*bbecb9d1SAndroid Build Coastguard Worker {
509*bbecb9d1SAndroid Build Coastguard Worker size_t size = printf_length(fmt, args) + 1;
510*bbecb9d1SAndroid Build Coastguard Worker
511*bbecb9d1SAndroid Build Coastguard Worker char *ptr = ralloc_size(ctx, size);
512*bbecb9d1SAndroid Build Coastguard Worker if (ptr != NULL)
513*bbecb9d1SAndroid Build Coastguard Worker vsnprintf(ptr, size, fmt, args);
514*bbecb9d1SAndroid Build Coastguard Worker
515*bbecb9d1SAndroid Build Coastguard Worker return ptr;
516*bbecb9d1SAndroid Build Coastguard Worker }
517*bbecb9d1SAndroid Build Coastguard Worker
518*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_asprintf_append(char ** str,const char * fmt,...)519*bbecb9d1SAndroid Build Coastguard Worker ralloc_asprintf_append(char **str, const char *fmt, ...)
520*bbecb9d1SAndroid Build Coastguard Worker {
521*bbecb9d1SAndroid Build Coastguard Worker bool success;
522*bbecb9d1SAndroid Build Coastguard Worker va_list args;
523*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
524*bbecb9d1SAndroid Build Coastguard Worker success = ralloc_vasprintf_append(str, fmt, args);
525*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
526*bbecb9d1SAndroid Build Coastguard Worker return success;
527*bbecb9d1SAndroid Build Coastguard Worker }
528*bbecb9d1SAndroid Build Coastguard Worker
529*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_vasprintf_append(char ** str,const char * fmt,va_list args)530*bbecb9d1SAndroid Build Coastguard Worker ralloc_vasprintf_append(char **str, const char *fmt, va_list args)
531*bbecb9d1SAndroid Build Coastguard Worker {
532*bbecb9d1SAndroid Build Coastguard Worker size_t existing_length;
533*bbecb9d1SAndroid Build Coastguard Worker assert(str != NULL);
534*bbecb9d1SAndroid Build Coastguard Worker existing_length = *str ? strlen(*str) : 0;
535*bbecb9d1SAndroid Build Coastguard Worker return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
536*bbecb9d1SAndroid Build Coastguard Worker }
537*bbecb9d1SAndroid Build Coastguard Worker
538*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_asprintf_rewrite_tail(char ** str,size_t * start,const char * fmt,...)539*bbecb9d1SAndroid Build Coastguard Worker ralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
540*bbecb9d1SAndroid Build Coastguard Worker {
541*bbecb9d1SAndroid Build Coastguard Worker bool success;
542*bbecb9d1SAndroid Build Coastguard Worker va_list args;
543*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
544*bbecb9d1SAndroid Build Coastguard Worker success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
545*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
546*bbecb9d1SAndroid Build Coastguard Worker return success;
547*bbecb9d1SAndroid Build Coastguard Worker }
548*bbecb9d1SAndroid Build Coastguard Worker
549*bbecb9d1SAndroid Build Coastguard Worker bool
ralloc_vasprintf_rewrite_tail(char ** str,size_t * start,const char * fmt,va_list args)550*bbecb9d1SAndroid Build Coastguard Worker ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
551*bbecb9d1SAndroid Build Coastguard Worker va_list args)
552*bbecb9d1SAndroid Build Coastguard Worker {
553*bbecb9d1SAndroid Build Coastguard Worker size_t new_length;
554*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
555*bbecb9d1SAndroid Build Coastguard Worker
556*bbecb9d1SAndroid Build Coastguard Worker assert(str != NULL);
557*bbecb9d1SAndroid Build Coastguard Worker
558*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(*str == NULL)) {
559*bbecb9d1SAndroid Build Coastguard Worker // Assuming a NULL context is probably bad, but it's expected behavior.
560*bbecb9d1SAndroid Build Coastguard Worker *str = ralloc_vasprintf(NULL, fmt, args);
561*bbecb9d1SAndroid Build Coastguard Worker *start = strlen(*str);
562*bbecb9d1SAndroid Build Coastguard Worker return true;
563*bbecb9d1SAndroid Build Coastguard Worker }
564*bbecb9d1SAndroid Build Coastguard Worker
565*bbecb9d1SAndroid Build Coastguard Worker new_length = printf_length(fmt, args);
566*bbecb9d1SAndroid Build Coastguard Worker
567*bbecb9d1SAndroid Build Coastguard Worker ptr = resize(*str, *start + new_length + 1);
568*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
569*bbecb9d1SAndroid Build Coastguard Worker return false;
570*bbecb9d1SAndroid Build Coastguard Worker
571*bbecb9d1SAndroid Build Coastguard Worker vsnprintf(ptr + *start, new_length + 1, fmt, args);
572*bbecb9d1SAndroid Build Coastguard Worker *str = ptr;
573*bbecb9d1SAndroid Build Coastguard Worker *start += new_length;
574*bbecb9d1SAndroid Build Coastguard Worker return true;
575*bbecb9d1SAndroid Build Coastguard Worker }
576*bbecb9d1SAndroid Build Coastguard Worker
577*bbecb9d1SAndroid Build Coastguard Worker /***************************************************************************
578*bbecb9d1SAndroid Build Coastguard Worker * Linear allocator for short-lived allocations.
579*bbecb9d1SAndroid Build Coastguard Worker ***************************************************************************
580*bbecb9d1SAndroid Build Coastguard Worker *
581*bbecb9d1SAndroid Build Coastguard Worker * The allocator consists of a parent node (2K buffer), which requires
582*bbecb9d1SAndroid Build Coastguard Worker * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
583*bbecb9d1SAndroid Build Coastguard Worker * directly, because the parent doesn't track them. You have to release
584*bbecb9d1SAndroid Build Coastguard Worker * the parent node in order to release all its children.
585*bbecb9d1SAndroid Build Coastguard Worker *
586*bbecb9d1SAndroid Build Coastguard Worker * The allocator uses a fixed-sized buffer with a monotonically increasing
587*bbecb9d1SAndroid Build Coastguard Worker * offset after each allocation. If the buffer is all used, another buffer
588*bbecb9d1SAndroid Build Coastguard Worker * is allocated, sharing the same ralloc parent, so all buffers are at
589*bbecb9d1SAndroid Build Coastguard Worker * the same level in the ralloc hierarchy.
590*bbecb9d1SAndroid Build Coastguard Worker *
591*bbecb9d1SAndroid Build Coastguard Worker * The linear parent node is always the first buffer and keeps track of all
592*bbecb9d1SAndroid Build Coastguard Worker * other buffers.
593*bbecb9d1SAndroid Build Coastguard Worker */
594*bbecb9d1SAndroid Build Coastguard Worker
595*bbecb9d1SAndroid Build Coastguard Worker #define MIN_LINEAR_BUFSIZE 2048
596*bbecb9d1SAndroid Build Coastguard Worker #define SUBALLOC_ALIGNMENT 8
597*bbecb9d1SAndroid Build Coastguard Worker #define LMAGIC 0x87b9c7d3
598*bbecb9d1SAndroid Build Coastguard Worker
599*bbecb9d1SAndroid Build Coastguard Worker struct
600*bbecb9d1SAndroid Build Coastguard Worker #ifdef _MSC_VER
601*bbecb9d1SAndroid Build Coastguard Worker __declspec(align(8))
602*bbecb9d1SAndroid Build Coastguard Worker #elif defined(__LP64__)
603*bbecb9d1SAndroid Build Coastguard Worker __attribute__((aligned(16)))
604*bbecb9d1SAndroid Build Coastguard Worker #else
605*bbecb9d1SAndroid Build Coastguard Worker __attribute__((aligned(8)))
606*bbecb9d1SAndroid Build Coastguard Worker #endif
607*bbecb9d1SAndroid Build Coastguard Worker linear_header {
608*bbecb9d1SAndroid Build Coastguard Worker #ifndef NDEBUG
609*bbecb9d1SAndroid Build Coastguard Worker unsigned magic; /* for debugging */
610*bbecb9d1SAndroid Build Coastguard Worker #endif
611*bbecb9d1SAndroid Build Coastguard Worker unsigned offset; /* points to the first unused byte in the buffer */
612*bbecb9d1SAndroid Build Coastguard Worker unsigned size; /* size of the buffer */
613*bbecb9d1SAndroid Build Coastguard Worker void *ralloc_parent; /* new buffers will use this */
614*bbecb9d1SAndroid Build Coastguard Worker struct linear_header *next; /* next buffer if we have more */
615*bbecb9d1SAndroid Build Coastguard Worker struct linear_header *latest; /* the only buffer that has free space */
616*bbecb9d1SAndroid Build Coastguard Worker
617*bbecb9d1SAndroid Build Coastguard Worker /* After this structure, the buffer begins.
618*bbecb9d1SAndroid Build Coastguard Worker * Each suballocation consists of linear_size_chunk as its header followed
619*bbecb9d1SAndroid Build Coastguard Worker * by the suballocation, so it goes:
620*bbecb9d1SAndroid Build Coastguard Worker *
621*bbecb9d1SAndroid Build Coastguard Worker * - linear_size_chunk
622*bbecb9d1SAndroid Build Coastguard Worker * - allocated space
623*bbecb9d1SAndroid Build Coastguard Worker * - linear_size_chunk
624*bbecb9d1SAndroid Build Coastguard Worker * - allocated space
625*bbecb9d1SAndroid Build Coastguard Worker * etc.
626*bbecb9d1SAndroid Build Coastguard Worker *
627*bbecb9d1SAndroid Build Coastguard Worker * linear_size_chunk is only needed by linear_realloc.
628*bbecb9d1SAndroid Build Coastguard Worker */
629*bbecb9d1SAndroid Build Coastguard Worker };
630*bbecb9d1SAndroid Build Coastguard Worker
631*bbecb9d1SAndroid Build Coastguard Worker struct linear_size_chunk {
632*bbecb9d1SAndroid Build Coastguard Worker unsigned size; /* for realloc */
633*bbecb9d1SAndroid Build Coastguard Worker unsigned _padding;
634*bbecb9d1SAndroid Build Coastguard Worker };
635*bbecb9d1SAndroid Build Coastguard Worker
636*bbecb9d1SAndroid Build Coastguard Worker typedef struct linear_header linear_header;
637*bbecb9d1SAndroid Build Coastguard Worker typedef struct linear_size_chunk linear_size_chunk;
638*bbecb9d1SAndroid Build Coastguard Worker
639*bbecb9d1SAndroid Build Coastguard Worker #define LINEAR_PARENT_TO_HEADER(parent) \
640*bbecb9d1SAndroid Build Coastguard Worker (linear_header*) \
641*bbecb9d1SAndroid Build Coastguard Worker ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
642*bbecb9d1SAndroid Build Coastguard Worker
643*bbecb9d1SAndroid Build Coastguard Worker /* Allocate the linear buffer with its header. */
644*bbecb9d1SAndroid Build Coastguard Worker static linear_header *
create_linear_node(void * ralloc_ctx,unsigned min_size)645*bbecb9d1SAndroid Build Coastguard Worker create_linear_node(void *ralloc_ctx, unsigned min_size)
646*bbecb9d1SAndroid Build Coastguard Worker {
647*bbecb9d1SAndroid Build Coastguard Worker linear_header *node;
648*bbecb9d1SAndroid Build Coastguard Worker
649*bbecb9d1SAndroid Build Coastguard Worker min_size += sizeof(linear_size_chunk);
650*bbecb9d1SAndroid Build Coastguard Worker
651*bbecb9d1SAndroid Build Coastguard Worker if (likely(min_size < MIN_LINEAR_BUFSIZE))
652*bbecb9d1SAndroid Build Coastguard Worker min_size = MIN_LINEAR_BUFSIZE;
653*bbecb9d1SAndroid Build Coastguard Worker
654*bbecb9d1SAndroid Build Coastguard Worker node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
655*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!node))
656*bbecb9d1SAndroid Build Coastguard Worker return NULL;
657*bbecb9d1SAndroid Build Coastguard Worker
658*bbecb9d1SAndroid Build Coastguard Worker #ifndef NDEBUG
659*bbecb9d1SAndroid Build Coastguard Worker node->magic = LMAGIC;
660*bbecb9d1SAndroid Build Coastguard Worker #endif
661*bbecb9d1SAndroid Build Coastguard Worker node->offset = 0;
662*bbecb9d1SAndroid Build Coastguard Worker node->size = min_size;
663*bbecb9d1SAndroid Build Coastguard Worker node->ralloc_parent = ralloc_ctx;
664*bbecb9d1SAndroid Build Coastguard Worker node->next = NULL;
665*bbecb9d1SAndroid Build Coastguard Worker node->latest = node;
666*bbecb9d1SAndroid Build Coastguard Worker return node;
667*bbecb9d1SAndroid Build Coastguard Worker }
668*bbecb9d1SAndroid Build Coastguard Worker
669*bbecb9d1SAndroid Build Coastguard Worker void *
linear_alloc_child(void * parent,unsigned size)670*bbecb9d1SAndroid Build Coastguard Worker linear_alloc_child(void *parent, unsigned size)
671*bbecb9d1SAndroid Build Coastguard Worker {
672*bbecb9d1SAndroid Build Coastguard Worker linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
673*bbecb9d1SAndroid Build Coastguard Worker linear_header *latest = first->latest;
674*bbecb9d1SAndroid Build Coastguard Worker linear_header *new_node;
675*bbecb9d1SAndroid Build Coastguard Worker linear_size_chunk *ptr;
676*bbecb9d1SAndroid Build Coastguard Worker unsigned full_size;
677*bbecb9d1SAndroid Build Coastguard Worker
678*bbecb9d1SAndroid Build Coastguard Worker assert(first->magic == LMAGIC);
679*bbecb9d1SAndroid Build Coastguard Worker assert(!latest->next);
680*bbecb9d1SAndroid Build Coastguard Worker
681*bbecb9d1SAndroid Build Coastguard Worker size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
682*bbecb9d1SAndroid Build Coastguard Worker full_size = sizeof(linear_size_chunk) + size;
683*bbecb9d1SAndroid Build Coastguard Worker
684*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(latest->offset + full_size > latest->size)) {
685*bbecb9d1SAndroid Build Coastguard Worker /* allocate a new node */
686*bbecb9d1SAndroid Build Coastguard Worker new_node = create_linear_node(latest->ralloc_parent, size);
687*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!new_node))
688*bbecb9d1SAndroid Build Coastguard Worker return NULL;
689*bbecb9d1SAndroid Build Coastguard Worker
690*bbecb9d1SAndroid Build Coastguard Worker first->latest = new_node;
691*bbecb9d1SAndroid Build Coastguard Worker latest->latest = new_node;
692*bbecb9d1SAndroid Build Coastguard Worker latest->next = new_node;
693*bbecb9d1SAndroid Build Coastguard Worker latest = new_node;
694*bbecb9d1SAndroid Build Coastguard Worker }
695*bbecb9d1SAndroid Build Coastguard Worker
696*bbecb9d1SAndroid Build Coastguard Worker ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
697*bbecb9d1SAndroid Build Coastguard Worker ptr->size = size;
698*bbecb9d1SAndroid Build Coastguard Worker latest->offset += full_size;
699*bbecb9d1SAndroid Build Coastguard Worker
700*bbecb9d1SAndroid Build Coastguard Worker assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
701*bbecb9d1SAndroid Build Coastguard Worker return &ptr[1];
702*bbecb9d1SAndroid Build Coastguard Worker }
703*bbecb9d1SAndroid Build Coastguard Worker
704*bbecb9d1SAndroid Build Coastguard Worker void *
linear_alloc_parent(void * ralloc_ctx,unsigned size)705*bbecb9d1SAndroid Build Coastguard Worker linear_alloc_parent(void *ralloc_ctx, unsigned size)
706*bbecb9d1SAndroid Build Coastguard Worker {
707*bbecb9d1SAndroid Build Coastguard Worker linear_header *node;
708*bbecb9d1SAndroid Build Coastguard Worker
709*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!ralloc_ctx))
710*bbecb9d1SAndroid Build Coastguard Worker return NULL;
711*bbecb9d1SAndroid Build Coastguard Worker
712*bbecb9d1SAndroid Build Coastguard Worker size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
713*bbecb9d1SAndroid Build Coastguard Worker
714*bbecb9d1SAndroid Build Coastguard Worker node = create_linear_node(ralloc_ctx, size);
715*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!node))
716*bbecb9d1SAndroid Build Coastguard Worker return NULL;
717*bbecb9d1SAndroid Build Coastguard Worker
718*bbecb9d1SAndroid Build Coastguard Worker return linear_alloc_child((char*)node +
719*bbecb9d1SAndroid Build Coastguard Worker sizeof(linear_header) +
720*bbecb9d1SAndroid Build Coastguard Worker sizeof(linear_size_chunk), size);
721*bbecb9d1SAndroid Build Coastguard Worker }
722*bbecb9d1SAndroid Build Coastguard Worker
723*bbecb9d1SAndroid Build Coastguard Worker void *
linear_zalloc_child(void * parent,unsigned size)724*bbecb9d1SAndroid Build Coastguard Worker linear_zalloc_child(void *parent, unsigned size)
725*bbecb9d1SAndroid Build Coastguard Worker {
726*bbecb9d1SAndroid Build Coastguard Worker void *ptr = linear_alloc_child(parent, size);
727*bbecb9d1SAndroid Build Coastguard Worker
728*bbecb9d1SAndroid Build Coastguard Worker if (likely(ptr))
729*bbecb9d1SAndroid Build Coastguard Worker memset(ptr, 0, size);
730*bbecb9d1SAndroid Build Coastguard Worker return ptr;
731*bbecb9d1SAndroid Build Coastguard Worker }
732*bbecb9d1SAndroid Build Coastguard Worker
733*bbecb9d1SAndroid Build Coastguard Worker void *
linear_zalloc_parent(void * parent,unsigned size)734*bbecb9d1SAndroid Build Coastguard Worker linear_zalloc_parent(void *parent, unsigned size)
735*bbecb9d1SAndroid Build Coastguard Worker {
736*bbecb9d1SAndroid Build Coastguard Worker void *ptr = linear_alloc_parent(parent, size);
737*bbecb9d1SAndroid Build Coastguard Worker
738*bbecb9d1SAndroid Build Coastguard Worker if (likely(ptr))
739*bbecb9d1SAndroid Build Coastguard Worker memset(ptr, 0, size);
740*bbecb9d1SAndroid Build Coastguard Worker return ptr;
741*bbecb9d1SAndroid Build Coastguard Worker }
742*bbecb9d1SAndroid Build Coastguard Worker
743*bbecb9d1SAndroid Build Coastguard Worker void
linear_free_parent(void * ptr)744*bbecb9d1SAndroid Build Coastguard Worker linear_free_parent(void *ptr)
745*bbecb9d1SAndroid Build Coastguard Worker {
746*bbecb9d1SAndroid Build Coastguard Worker linear_header *node;
747*bbecb9d1SAndroid Build Coastguard Worker
748*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!ptr))
749*bbecb9d1SAndroid Build Coastguard Worker return;
750*bbecb9d1SAndroid Build Coastguard Worker
751*bbecb9d1SAndroid Build Coastguard Worker node = LINEAR_PARENT_TO_HEADER(ptr);
752*bbecb9d1SAndroid Build Coastguard Worker assert(node->magic == LMAGIC);
753*bbecb9d1SAndroid Build Coastguard Worker
754*bbecb9d1SAndroid Build Coastguard Worker while (node) {
755*bbecb9d1SAndroid Build Coastguard Worker void *ptr = node;
756*bbecb9d1SAndroid Build Coastguard Worker
757*bbecb9d1SAndroid Build Coastguard Worker node = node->next;
758*bbecb9d1SAndroid Build Coastguard Worker ralloc_free(ptr);
759*bbecb9d1SAndroid Build Coastguard Worker }
760*bbecb9d1SAndroid Build Coastguard Worker }
761*bbecb9d1SAndroid Build Coastguard Worker
762*bbecb9d1SAndroid Build Coastguard Worker void
ralloc_steal_linear_parent(void * new_ralloc_ctx,void * ptr)763*bbecb9d1SAndroid Build Coastguard Worker ralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
764*bbecb9d1SAndroid Build Coastguard Worker {
765*bbecb9d1SAndroid Build Coastguard Worker linear_header *node;
766*bbecb9d1SAndroid Build Coastguard Worker
767*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!ptr))
768*bbecb9d1SAndroid Build Coastguard Worker return;
769*bbecb9d1SAndroid Build Coastguard Worker
770*bbecb9d1SAndroid Build Coastguard Worker node = LINEAR_PARENT_TO_HEADER(ptr);
771*bbecb9d1SAndroid Build Coastguard Worker assert(node->magic == LMAGIC);
772*bbecb9d1SAndroid Build Coastguard Worker
773*bbecb9d1SAndroid Build Coastguard Worker while (node) {
774*bbecb9d1SAndroid Build Coastguard Worker ralloc_steal(new_ralloc_ctx, node);
775*bbecb9d1SAndroid Build Coastguard Worker node->ralloc_parent = new_ralloc_ctx;
776*bbecb9d1SAndroid Build Coastguard Worker node = node->next;
777*bbecb9d1SAndroid Build Coastguard Worker }
778*bbecb9d1SAndroid Build Coastguard Worker }
779*bbecb9d1SAndroid Build Coastguard Worker
780*bbecb9d1SAndroid Build Coastguard Worker void *
ralloc_parent_of_linear_parent(void * ptr)781*bbecb9d1SAndroid Build Coastguard Worker ralloc_parent_of_linear_parent(void *ptr)
782*bbecb9d1SAndroid Build Coastguard Worker {
783*bbecb9d1SAndroid Build Coastguard Worker linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
784*bbecb9d1SAndroid Build Coastguard Worker assert(node->magic == LMAGIC);
785*bbecb9d1SAndroid Build Coastguard Worker return node->ralloc_parent;
786*bbecb9d1SAndroid Build Coastguard Worker }
787*bbecb9d1SAndroid Build Coastguard Worker
788*bbecb9d1SAndroid Build Coastguard Worker void *
linear_realloc(void * parent,void * old,unsigned new_size)789*bbecb9d1SAndroid Build Coastguard Worker linear_realloc(void *parent, void *old, unsigned new_size)
790*bbecb9d1SAndroid Build Coastguard Worker {
791*bbecb9d1SAndroid Build Coastguard Worker unsigned old_size = 0;
792*bbecb9d1SAndroid Build Coastguard Worker ralloc_header *new_ptr;
793*bbecb9d1SAndroid Build Coastguard Worker
794*bbecb9d1SAndroid Build Coastguard Worker new_ptr = linear_alloc_child(parent, new_size);
795*bbecb9d1SAndroid Build Coastguard Worker
796*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!old))
797*bbecb9d1SAndroid Build Coastguard Worker return new_ptr;
798*bbecb9d1SAndroid Build Coastguard Worker
799*bbecb9d1SAndroid Build Coastguard Worker old_size = ((linear_size_chunk*)old)[-1].size;
800*bbecb9d1SAndroid Build Coastguard Worker
801*bbecb9d1SAndroid Build Coastguard Worker if (likely(new_ptr && old_size))
802*bbecb9d1SAndroid Build Coastguard Worker memcpy(new_ptr, old, MIN2(old_size, new_size));
803*bbecb9d1SAndroid Build Coastguard Worker
804*bbecb9d1SAndroid Build Coastguard Worker return new_ptr;
805*bbecb9d1SAndroid Build Coastguard Worker }
806*bbecb9d1SAndroid Build Coastguard Worker
807*bbecb9d1SAndroid Build Coastguard Worker /* All code below is pretty much copied from ralloc and only the alloc
808*bbecb9d1SAndroid Build Coastguard Worker * calls are different.
809*bbecb9d1SAndroid Build Coastguard Worker */
810*bbecb9d1SAndroid Build Coastguard Worker
811*bbecb9d1SAndroid Build Coastguard Worker char *
linear_strdup(void * parent,const char * str)812*bbecb9d1SAndroid Build Coastguard Worker linear_strdup(void *parent, const char *str)
813*bbecb9d1SAndroid Build Coastguard Worker {
814*bbecb9d1SAndroid Build Coastguard Worker unsigned n;
815*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
816*bbecb9d1SAndroid Build Coastguard Worker
817*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!str))
818*bbecb9d1SAndroid Build Coastguard Worker return NULL;
819*bbecb9d1SAndroid Build Coastguard Worker
820*bbecb9d1SAndroid Build Coastguard Worker n = strlen(str);
821*bbecb9d1SAndroid Build Coastguard Worker ptr = linear_alloc_child(parent, n + 1);
822*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(!ptr))
823*bbecb9d1SAndroid Build Coastguard Worker return NULL;
824*bbecb9d1SAndroid Build Coastguard Worker
825*bbecb9d1SAndroid Build Coastguard Worker memcpy(ptr, str, n);
826*bbecb9d1SAndroid Build Coastguard Worker ptr[n] = '\0';
827*bbecb9d1SAndroid Build Coastguard Worker return ptr;
828*bbecb9d1SAndroid Build Coastguard Worker }
829*bbecb9d1SAndroid Build Coastguard Worker
830*bbecb9d1SAndroid Build Coastguard Worker char *
linear_asprintf(void * parent,const char * fmt,...)831*bbecb9d1SAndroid Build Coastguard Worker linear_asprintf(void *parent, const char *fmt, ...)
832*bbecb9d1SAndroid Build Coastguard Worker {
833*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
834*bbecb9d1SAndroid Build Coastguard Worker va_list args;
835*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
836*bbecb9d1SAndroid Build Coastguard Worker ptr = linear_vasprintf(parent, fmt, args);
837*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
838*bbecb9d1SAndroid Build Coastguard Worker return ptr;
839*bbecb9d1SAndroid Build Coastguard Worker }
840*bbecb9d1SAndroid Build Coastguard Worker
841*bbecb9d1SAndroid Build Coastguard Worker char *
linear_vasprintf(void * parent,const char * fmt,va_list args)842*bbecb9d1SAndroid Build Coastguard Worker linear_vasprintf(void *parent, const char *fmt, va_list args)
843*bbecb9d1SAndroid Build Coastguard Worker {
844*bbecb9d1SAndroid Build Coastguard Worker unsigned size = printf_length(fmt, args) + 1;
845*bbecb9d1SAndroid Build Coastguard Worker
846*bbecb9d1SAndroid Build Coastguard Worker char *ptr = linear_alloc_child(parent, size);
847*bbecb9d1SAndroid Build Coastguard Worker if (ptr != NULL)
848*bbecb9d1SAndroid Build Coastguard Worker vsnprintf(ptr, size, fmt, args);
849*bbecb9d1SAndroid Build Coastguard Worker
850*bbecb9d1SAndroid Build Coastguard Worker return ptr;
851*bbecb9d1SAndroid Build Coastguard Worker }
852*bbecb9d1SAndroid Build Coastguard Worker
853*bbecb9d1SAndroid Build Coastguard Worker bool
linear_asprintf_append(void * parent,char ** str,const char * fmt,...)854*bbecb9d1SAndroid Build Coastguard Worker linear_asprintf_append(void *parent, char **str, const char *fmt, ...)
855*bbecb9d1SAndroid Build Coastguard Worker {
856*bbecb9d1SAndroid Build Coastguard Worker bool success;
857*bbecb9d1SAndroid Build Coastguard Worker va_list args;
858*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
859*bbecb9d1SAndroid Build Coastguard Worker success = linear_vasprintf_append(parent, str, fmt, args);
860*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
861*bbecb9d1SAndroid Build Coastguard Worker return success;
862*bbecb9d1SAndroid Build Coastguard Worker }
863*bbecb9d1SAndroid Build Coastguard Worker
864*bbecb9d1SAndroid Build Coastguard Worker bool
linear_vasprintf_append(void * parent,char ** str,const char * fmt,va_list args)865*bbecb9d1SAndroid Build Coastguard Worker linear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
866*bbecb9d1SAndroid Build Coastguard Worker {
867*bbecb9d1SAndroid Build Coastguard Worker size_t existing_length;
868*bbecb9d1SAndroid Build Coastguard Worker assert(str != NULL);
869*bbecb9d1SAndroid Build Coastguard Worker existing_length = *str ? strlen(*str) : 0;
870*bbecb9d1SAndroid Build Coastguard Worker return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
871*bbecb9d1SAndroid Build Coastguard Worker }
872*bbecb9d1SAndroid Build Coastguard Worker
873*bbecb9d1SAndroid Build Coastguard Worker bool
linear_asprintf_rewrite_tail(void * parent,char ** str,size_t * start,const char * fmt,...)874*bbecb9d1SAndroid Build Coastguard Worker linear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
875*bbecb9d1SAndroid Build Coastguard Worker const char *fmt, ...)
876*bbecb9d1SAndroid Build Coastguard Worker {
877*bbecb9d1SAndroid Build Coastguard Worker bool success;
878*bbecb9d1SAndroid Build Coastguard Worker va_list args;
879*bbecb9d1SAndroid Build Coastguard Worker va_start(args, fmt);
880*bbecb9d1SAndroid Build Coastguard Worker success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
881*bbecb9d1SAndroid Build Coastguard Worker va_end(args);
882*bbecb9d1SAndroid Build Coastguard Worker return success;
883*bbecb9d1SAndroid Build Coastguard Worker }
884*bbecb9d1SAndroid Build Coastguard Worker
885*bbecb9d1SAndroid Build Coastguard Worker bool
linear_vasprintf_rewrite_tail(void * parent,char ** str,size_t * start,const char * fmt,va_list args)886*bbecb9d1SAndroid Build Coastguard Worker linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
887*bbecb9d1SAndroid Build Coastguard Worker const char *fmt, va_list args)
888*bbecb9d1SAndroid Build Coastguard Worker {
889*bbecb9d1SAndroid Build Coastguard Worker size_t new_length;
890*bbecb9d1SAndroid Build Coastguard Worker char *ptr;
891*bbecb9d1SAndroid Build Coastguard Worker
892*bbecb9d1SAndroid Build Coastguard Worker assert(str != NULL);
893*bbecb9d1SAndroid Build Coastguard Worker
894*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(*str == NULL)) {
895*bbecb9d1SAndroid Build Coastguard Worker *str = linear_vasprintf(parent, fmt, args);
896*bbecb9d1SAndroid Build Coastguard Worker *start = strlen(*str);
897*bbecb9d1SAndroid Build Coastguard Worker return true;
898*bbecb9d1SAndroid Build Coastguard Worker }
899*bbecb9d1SAndroid Build Coastguard Worker
900*bbecb9d1SAndroid Build Coastguard Worker new_length = printf_length(fmt, args);
901*bbecb9d1SAndroid Build Coastguard Worker
902*bbecb9d1SAndroid Build Coastguard Worker ptr = linear_realloc(parent, *str, *start + new_length + 1);
903*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ptr == NULL))
904*bbecb9d1SAndroid Build Coastguard Worker return false;
905*bbecb9d1SAndroid Build Coastguard Worker
906*bbecb9d1SAndroid Build Coastguard Worker vsnprintf(ptr + *start, new_length + 1, fmt, args);
907*bbecb9d1SAndroid Build Coastguard Worker *str = ptr;
908*bbecb9d1SAndroid Build Coastguard Worker *start += new_length;
909*bbecb9d1SAndroid Build Coastguard Worker return true;
910*bbecb9d1SAndroid Build Coastguard Worker }
911*bbecb9d1SAndroid Build Coastguard Worker
912*bbecb9d1SAndroid Build Coastguard Worker /* helper routine for strcat/strncat - n is the exact amount to copy */
913*bbecb9d1SAndroid Build Coastguard Worker static bool
linear_cat(void * parent,char ** dest,const char * str,unsigned n)914*bbecb9d1SAndroid Build Coastguard Worker linear_cat(void *parent, char **dest, const char *str, unsigned n)
915*bbecb9d1SAndroid Build Coastguard Worker {
916*bbecb9d1SAndroid Build Coastguard Worker char *both;
917*bbecb9d1SAndroid Build Coastguard Worker unsigned existing_length;
918*bbecb9d1SAndroid Build Coastguard Worker assert(dest != NULL && *dest != NULL);
919*bbecb9d1SAndroid Build Coastguard Worker
920*bbecb9d1SAndroid Build Coastguard Worker existing_length = strlen(*dest);
921*bbecb9d1SAndroid Build Coastguard Worker both = linear_realloc(parent, *dest, existing_length + n + 1);
922*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(both == NULL))
923*bbecb9d1SAndroid Build Coastguard Worker return false;
924*bbecb9d1SAndroid Build Coastguard Worker
925*bbecb9d1SAndroid Build Coastguard Worker memcpy(both + existing_length, str, n);
926*bbecb9d1SAndroid Build Coastguard Worker both[existing_length + n] = '\0';
927*bbecb9d1SAndroid Build Coastguard Worker
928*bbecb9d1SAndroid Build Coastguard Worker *dest = both;
929*bbecb9d1SAndroid Build Coastguard Worker return true;
930*bbecb9d1SAndroid Build Coastguard Worker }
931*bbecb9d1SAndroid Build Coastguard Worker
932*bbecb9d1SAndroid Build Coastguard Worker bool
linear_strcat(void * parent,char ** dest,const char * str)933*bbecb9d1SAndroid Build Coastguard Worker linear_strcat(void *parent, char **dest, const char *str)
934*bbecb9d1SAndroid Build Coastguard Worker {
935*bbecb9d1SAndroid Build Coastguard Worker return linear_cat(parent, dest, str, strlen(str));
936*bbecb9d1SAndroid Build Coastguard Worker }
937