3 #include "vg_platform.h"
10 struct vg_global_mem vg_mem
;
12 u32
vg_align8( u32 s
)
18 u32
vg_align4( u32 s
)
24 /* Returns allocator structure from data pointer */
25 vg_linear_allocator
*vg_linear_header( void *data
)
27 vg_linear_allocator
*ptr
= data
;
33 /* allocate something from a linear allocator */
34 __attribute__((warn_unused_result
))
35 void *_vg_linear_alloc( void *buffer
, u32 size
, const char *constr_name
)
38 size
= vg_align8( size
);
40 if( ((u64
)buffer
) % 8 )
41 vg_fatal_error( "unaligned buffer (%p)", buffer
);
43 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
45 if( (alloc
->cur
+ size
) > alloc
->size
)
47 vg_fatal_error( "linear allocator overflow (%u + %u > %u)\n",
48 alloc
->cur
, size
, alloc
->size
);
51 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
52 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
53 vg_fatal_error( "Max linear allocations reached" );
57 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
58 data
= malloc( size
);
60 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
61 meta
->type
= k_allocation_type_block
;
64 meta
->name
= constr_name
;
67 data
= buffer
+ alloc
->cur
;
71 for( u32 i
=0; i
<size
; i
++ ){
75 alloc
->allocation_count
++;
76 alloc
->last_alloc
= data
;
77 alloc
->last_alloc_size
= size
;
80 if( ((u64
)data
) % 8 ){
81 vg_fatal_error( "unaligned" );
87 /* resize latest block of memory from linear */
88 __attribute__((warn_unused_result
))
89 void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
91 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
94 vg_error( "alloc(%u) is not 8 byte aligned\n", newsize
);
96 newsize
= vg_align8( newsize
);
99 if( alloc
->last_alloc
!= data
)
100 vg_fatal_error( "This block has been fixed!" );
102 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
103 vg_fatal_error( "Cannot resize, overflow" );
105 alloc
->cur
-= alloc
->last_alloc_size
;
106 alloc
->cur
+= newsize
;
107 alloc
->last_alloc_size
= newsize
;
109 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
110 data
= realloc( data
, newsize
);
112 vg_fatal_error( "realloc failed" );
114 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
115 alloc
->last_alloc
= data
;
123 /* its possible to delete just the last item */
124 void vg_linear_del( void *buffer
, void *data
)
126 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
128 if( alloc
->last_alloc
!= data
){
129 vg_fatal_error( "This block has been fixed! Last alloc: %p, this: %p\n",
130 alloc
->last_alloc
, data
);
133 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
134 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
135 if( meta
->type
== k_allocation_type_linear
)
136 vg_fatal_error( "Cannot free a linear allocator in this conext" );
141 alloc
->allocation_count
--;
142 alloc
->cur
-= alloc
->last_alloc_size
;
143 alloc
->last_alloc
= NULL
;
144 alloc
->last_alloc_size
= 0;
147 /* extend latest block of memory from linear */
148 __attribute__((warn_unused_result
))
149 void *_vg_linear_extend( void *buffer
, void *data
, u32 extra
,
150 const char *constr_name
)
153 return _vg_linear_alloc( buffer
, vg_align8(extra
), constr_name
);
155 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
157 if( alloc
->last_alloc
!= data
)
158 vg_fatal_error( "This block has been fixed!" );
160 u32 new_size
= alloc
->last_alloc_size
+ extra
;
161 return vg_linear_resize( buffer
, data
, vg_align8(new_size
) );
164 /* get the current usage of allocator */
165 u32
vg_linear_get_cur( void *buffer
)
167 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
171 /* get the capacity of allocator. */
172 u32
vg_linear_get_capacity( void *buffer
)
174 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
178 /* get the remaining size of the allocator */
179 u32
vg_linear_remaining( void *buffer
)
181 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
182 return alloc
->size
- alloc
->cur
;
185 /* yeet all memory from linear allocator */
186 void vg_linear_clear( void *buffer
)
188 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
190 /* libc mode we recursively free any allocations made */
191 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
192 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
193 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
195 if( meta
->type
== k_allocation_type_block
){
199 vg_linear_clear( meta
->data
);
200 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
202 free( sub
->alloc_table
);
208 alloc
->last_alloc
= NULL
;
209 alloc
->last_alloc_size
= 0;
210 alloc
->allocation_count
= 0;
214 /* allocate a FIXED SIZE linear allocator
216 * FIXME: there was a bug in vg's code that caused a race condition between
217 * two system allocations. make this IMPOSSIBLE by requiring a lock
218 * on the allocater to be passed between threads.
220 * luckily that bug only exists when using development tools, but still!
222 * this should then only be checked and turned on in debugging.
225 void *_vg_create_linear_allocator( void *lin_alloc
, u32 size
,
226 u16 flags
, const char *constr_name
)
228 if( sizeof( vg_linear_allocator
) != 32 )
229 vg_fatal_error( "Programming error" );
231 vg_linear_allocator
*header
;
232 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
234 /* Creating it inside an existing one */
236 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
238 if( alloc
->cur
+ block_size
> alloc
->size
)
239 vg_fatal_error( "Out of memory" );
241 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
242 vg_fatal_error( "Max allocations in linear allocator" );
244 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
245 vg_fatal_error( "Cannot declare realtime allocator inside systems"
248 if( vg_mem
.use_libc_malloc
){
249 vg_allocation_meta
*meta
=
250 &alloc
->alloc_table
[ alloc
->allocation_count
];
252 if( flags
& VG_MEMORY_REALTIME
)
253 header
= malloc( block_size
);
255 header
= malloc( sizeof(vg_linear_allocator
) );
257 meta
->data
= header
+1;
258 meta
->type
= k_allocation_type_linear
;
260 meta
->name
= constr_name
;
263 header
= lin_alloc
+ alloc
->cur
;
266 alloc
->cur
+= block_size
;
267 alloc
->last_alloc
= header
;
268 alloc
->last_alloc_size
= block_size
;
269 alloc
->allocation_count
++;
272 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
273 header
= malloc( sizeof(vg_linear_allocator
) );
275 header
= malloc( block_size
);
278 header
->allocation_count
= 0;
280 header
->last_alloc
= NULL
;
281 header
->last_alloc_size
= 0;
283 header
->flags
= flags
;
285 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) ){
286 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
287 header
->alloc_table
= malloc( table_size
);
290 header
->alloc_table
= NULL
;
295 /* request all the memory we need in advance */
296 void vg_set_mem_quota( u32 size
)
301 void vg_alloc_quota(void)
303 u32 size_scratch
= 10*1024*1024;
304 u32 size
= VG_MAX( vg_mem
.quota
, size_scratch
);
306 vg_mem
.rtmemory
= _vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
,
308 vg_mem
.scratch
= _vg_create_linear_allocator( vg_mem
.rtmemory
,
314 void vg_mem_log( void *lin_alloc
, int depth
, const char *name
)
316 if( vg_mem
.use_libc_malloc
){
317 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
320 f32 p
= ((float)alloc
->cur
/ (float)alloc
->size
) * 100.0f
;
322 for( int i
=0; i
<depth
; i
++ ) printf( " " );
323 printf( "LA(%s): %u bytes, %f%% used\n", name
, s
, p
);
325 if( alloc
->flags
& VG_MEMORY_SYSTEM
){
326 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
327 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
329 if( meta
->type
== k_allocation_type_block
){
330 for( int i
=0; i
<depth
+1; i
++ ) printf( " " );
331 printf( "B(%s): %u bytes\n", meta
->name
, meta
->size
);
334 vg_mem_log( meta
->data
, depth
+1, meta
->name
);
339 for( int i
=0; i
<depth
+1; i
++ ) printf( " " );
340 printf( "<opaque memory> (UNTRACKED)\n" );
344 vg_error( "allocations are not tracked (turn on libc mode)\n" );