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 vg_error( "alloc(%u) is not 8 byte aligned\n", size
);
40 size
= vg_align8( size
);
42 if( ((u64
)buffer
) % 8 ){
43 vg_fatal_error( "unaligned buffer (%p)", buffer
);
46 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
48 if( (alloc
->cur
+ size
) > alloc
->size
){
49 vg_fatal_error( "linear allocator overflow (%u + %u > %u)\n",
50 alloc
->cur
, size
, alloc
->size
);
53 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
54 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
55 vg_fatal_error( "Max linear allocations reached" );
59 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
60 data
= malloc( size
);
62 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
63 meta
->type
= k_allocation_type_block
;
66 meta
->name
= constr_name
;
69 data
= buffer
+ alloc
->cur
;
73 for( u32 i
=0; i
<size
; i
++ ){
77 alloc
->allocation_count
++;
78 alloc
->last_alloc
= data
;
79 alloc
->last_alloc_size
= size
;
82 if( ((u64
)data
) % 8 ){
83 vg_fatal_error( "unaligned" );
89 /* resize latest block of memory from linear */
90 __attribute__((warn_unused_result
))
91 void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
93 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
96 vg_error( "alloc(%u) is not 8 byte aligned\n", newsize
);
98 newsize
= vg_align8( newsize
);
101 if( alloc
->last_alloc
!= data
)
102 vg_fatal_error( "This block has been fixed!" );
104 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
105 vg_fatal_error( "Cannot resize, overflow" );
107 alloc
->cur
-= alloc
->last_alloc_size
;
108 alloc
->cur
+= newsize
;
109 alloc
->last_alloc_size
= newsize
;
111 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
112 data
= realloc( data
, newsize
);
114 vg_fatal_error( "realloc failed" );
116 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
117 alloc
->last_alloc
= data
;
125 /* its possible to delete just the last item */
126 void vg_linear_del( void *buffer
, void *data
)
128 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
130 if( alloc
->last_alloc
!= data
){
131 vg_fatal_error( "This block has been fixed! Last alloc: %p, this: %p\n",
132 alloc
->last_alloc
, data
);
135 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
136 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
137 if( meta
->type
== k_allocation_type_linear
)
138 vg_fatal_error( "Cannot free a linear allocator in this conext" );
143 alloc
->allocation_count
--;
144 alloc
->cur
-= alloc
->last_alloc_size
;
145 alloc
->last_alloc
= NULL
;
146 alloc
->last_alloc_size
= 0;
149 /* extend latest block of memory from linear */
150 __attribute__((warn_unused_result
))
151 void *_vg_linear_extend( void *buffer
, void *data
, u32 extra
,
152 const char *constr_name
)
155 return _vg_linear_alloc( buffer
, vg_align8(extra
), constr_name
);
157 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
159 if( alloc
->last_alloc
!= data
)
160 vg_fatal_error( "This block has been fixed!" );
162 u32 new_size
= alloc
->last_alloc_size
+ extra
;
163 return vg_linear_resize( buffer
, data
, vg_align8(new_size
) );
166 /* get the current usage of allocator */
167 u32
vg_linear_get_cur( void *buffer
)
169 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
173 /* get the capacity of allocator. */
174 u32
vg_linear_get_capacity( void *buffer
)
176 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
180 /* get the remaining size of the allocator */
181 u32
vg_linear_remaining( void *buffer
)
183 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
184 return alloc
->size
- alloc
->cur
;
187 /* yeet all memory from linear allocator */
188 void vg_linear_clear( void *buffer
)
190 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
192 /* libc mode we recursively free any allocations made */
193 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
194 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
195 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
197 if( meta
->type
== k_allocation_type_block
){
201 vg_linear_clear( meta
->data
);
202 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
204 free( sub
->alloc_table
);
210 alloc
->last_alloc
= NULL
;
211 alloc
->last_alloc_size
= 0;
212 alloc
->allocation_count
= 0;
216 /* allocate a FIXED SIZE linear allocator
218 * FIXME: there was a bug in vg's code that caused a race condition between
219 * two system allocations. make this IMPOSSIBLE by requiring a lock
220 * on the allocater to be passed between threads.
222 * luckily that bug only exists when using development tools, but still!
224 * this should then only be checked and turned on in debugging.
227 void *_vg_create_linear_allocator( void *lin_alloc
, u32 size
,
228 u16 flags
, const char *constr_name
)
230 if( sizeof( vg_linear_allocator
) != 32 )
231 vg_fatal_error( "Programming error" );
233 vg_linear_allocator
*header
;
234 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
236 /* Creating it inside an existing one */
238 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
240 if( alloc
->cur
+ block_size
> alloc
->size
)
241 vg_fatal_error( "Out of memory" );
243 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
244 vg_fatal_error( "Max allocations in linear allocator" );
246 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
247 vg_fatal_error( "Cannot declare realtime allocator inside systems"
250 if( vg_mem
.use_libc_malloc
){
251 vg_allocation_meta
*meta
=
252 &alloc
->alloc_table
[ alloc
->allocation_count
];
254 if( flags
& VG_MEMORY_REALTIME
)
255 header
= malloc( block_size
);
257 header
= malloc( sizeof(vg_linear_allocator
) );
259 meta
->data
= header
+1;
260 meta
->type
= k_allocation_type_linear
;
262 meta
->name
= constr_name
;
265 header
= lin_alloc
+ alloc
->cur
;
268 alloc
->cur
+= block_size
;
269 alloc
->last_alloc
= header
;
270 alloc
->last_alloc_size
= block_size
;
271 alloc
->allocation_count
++;
274 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
275 header
= malloc( sizeof(vg_linear_allocator
) );
277 header
= malloc( block_size
);
280 header
->allocation_count
= 0;
282 header
->last_alloc
= NULL
;
283 header
->last_alloc_size
= 0;
285 header
->flags
= flags
;
287 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) ){
288 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
289 header
->alloc_table
= malloc( table_size
);
292 header
->alloc_table
= NULL
;
297 /* request all the memory we need in advance */
298 void vg_set_mem_quota( u32 size
)
303 void vg_alloc_quota(void)
305 u32 size_scratch
= 10*1024*1024;
306 u32 size
= VG_MAX( vg_mem
.quota
, size_scratch
);
308 vg_mem
.rtmemory
= _vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
,
310 vg_mem
.scratch
= _vg_create_linear_allocator( vg_mem
.rtmemory
,
316 void vg_mem_log( void *lin_alloc
, int depth
, const char *name
)
318 if( vg_mem
.use_libc_malloc
){
319 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
322 f32 p
= ((float)alloc
->cur
/ (float)alloc
->size
) * 100.0f
;
324 for( int i
=0; i
<depth
; i
++ ) printf( " " );
325 printf( "LA(%s): %u bytes, %f%% used\n", name
, s
, p
);
327 if( alloc
->flags
& VG_MEMORY_SYSTEM
){
328 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
329 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
331 if( meta
->type
== k_allocation_type_block
){
332 for( int i
=0; i
<depth
+1; i
++ ) printf( " " );
333 printf( "B(%s): %u bytes\n", meta
->name
, meta
->size
);
336 vg_mem_log( meta
->data
, depth
+1, meta
->name
);
341 for( int i
=0; i
<depth
+1; i
++ ) printf( " " );
342 printf( "<opaque memory> (UNTRACKED)\n" );
346 vg_error( "allocations are not tracked (turn on libc mode)\n" );