1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
11 * SquirrelJME allocator.
16 #ifndef SQUIRRELJME_ALLOC_H
17 #define SQUIRRELJME_ALLOC_H
20 #include "sjme/debug.h"
21 #include "sjme/atomic.h"
22 #include "sjme/multithread.h"
26 #ifndef SJME_CXX_IS_EXTERNED
27 #define SJME_CXX_IS_EXTERNED
28 #define SJME_CXX_SQUIRRELJME_ALLOC_H
30 #endif /* #ifdef SJME_CXX_IS_EXTERNED */
31 #endif /* #ifdef __cplusplus */
33 /*--------------------------------------------------------------------------*/
36 * Allocation link chain, each is a chain between each allocation.
40 typedef struct sjme_alloc_link sjme_alloc_link
;
43 * Allocation pool and link space types.
47 typedef enum sjme_alloc_poolSpace
50 SJME_ALLOC_POOL_SPACE_INVALID
,
53 SJME_ALLOC_POOL_SPACE_FREE
,
56 SJME_ALLOC_POOL_SPACE_USED
,
58 /** the number of possible spaces. */
59 SJME_NUM_ALLOC_POOL_SPACE
60 } sjme_alloc_poolSpace
;
67 typedef enum sjme_alloc_linkFlag
69 /** Nested allocation pool. */
70 SJME_ALLOC_LINK_FLAG_NESTED_POOL
= 1,
71 } sjme_alloc_linkFlag
;
74 * Object for referenced counted weak pointer references.
78 typedef struct sjme_alloc_weakBase
* sjme_alloc_weak
;
81 * This is called when a weak reference has been freed or is about to be
84 * @param weak The weak reference being freed.
85 * @param data The data for the free.
86 * @param isBlockFree Was this called because the underlying block was freed?
87 * @return Any resultant error code. If this function
88 * returns @c SJME_ERROR_ENQUEUE_KEEP_WEAK and the weak reference reaches
89 * zero references, then it will not be freed.
92 typedef sjme_errorCode (*sjme_alloc_weakEnqueueFunc
)(
93 sjme_attrInNotNull sjme_alloc_weak weak
,
94 sjme_attrInNullable sjme_pointer data
,
95 sjme_attrInValue sjme_jboolean isBlockFree
);
97 /** Weak reference is valid. */
98 #define SJME_ALLOC_WEAK_VALID UINT32_C(0x58657221)
100 struct sjme_alloc_weakBase
102 /** Is this weak reference valid? */
103 sjme_atomic_sjme_jint valid
;
105 /** The link this points to, @c NULL if freed. */
106 sjme_alloc_link
* link
;
108 /** The count for this weak reference, zero will free this reference. */
109 sjme_atomic_sjme_jint count
;
111 /** The pointer this points to, @c NULL if freed. */
112 sjme_pointer pointer
;
114 /** The data to call for when this is removed. */
115 sjme_alloc_weakEnqueueFunc enqueue
;
117 /** The pointer for enqueue. */
118 sjme_pointer enqueueData
;
121 struct sjme_alloc_link
123 /** The front guard. */
124 sjme_jint guardFront
;
126 /** The pool this is in. */
127 volatile sjme_alloc_pool
* pool
;
129 /** Previous link. */
130 sjme_alloc_link
* prev
;
133 sjme_alloc_link
* next
;
135 /** The space this is in. */
136 sjme_alloc_poolSpace space
;
138 /** The previous free link. */
139 sjme_alloc_link
* freePrev
;
141 /** The next free link. */
142 sjme_alloc_link
* freeNext
;
144 /** The weak reference this is attached to. */
145 sjme_alloc_weak weak
;
147 /** The allocation size of the link, @code{allocSize <= blockSize}. */
150 /** The size of the data area of this block. */
156 #if defined(SJME_CONFIG_DEBUG)
157 /** The file of this allocation. */
158 sjme_lpcstr debugFile
;
160 /** The line of this allocation. */
163 /** The function of this allocation. */
164 sjme_lpcstr debugFunction
;
167 /** The back guard. */
170 /** The memory block. */
171 sjme_jubyte block
[sjme_flexibleArrayCount
];
175 * Calculates the size of the pool link.
177 * @param size The size to use for the pool link.
178 * @return The size of the given pool link.
181 #define SJME_SIZEOF_ALLOC_LINK(size) \
182 (offsetof(sjme_alloc_link, block) + (((size_t)(size)) * \
183 sizeof(sjme_jubyte)))
186 * Structure which stores the pooled memory allocator.
190 struct sjme_alloc_pool
192 /** The front end wrapped type. */
193 sjme_frontEnd frontEnd
;
195 /** The size of the allocation pool. */
198 /** Whole pool spin lock. */
199 sjme_thread_spinLock spinLock
;
201 /** Free and used space information. */
204 /** Space that can be used. */
207 /** Space that is actually reserved due to overhead. */
209 } space
[SJME_NUM_ALLOC_POOL_SPACE
];
211 /** Previous pool in multi-pool chain allocation. */
212 sjme_alloc_pool
* prevPool
;
214 /** Next pool in multi-pool chain allocation. */
215 sjme_alloc_pool
* nextPool
;
217 /** The front chain link. */
218 sjme_alloc_link
* frontLink
;
220 /** The back chain link. */
221 sjme_alloc_link
* backLink
;
223 /** The first free link in the chain. */
224 sjme_alloc_link
* freeFirstLink
;
226 /** The last free link in the chain. */
227 sjme_alloc_link
* freeLastLink
;
229 /** The memory block. */
230 sjme_jubyte block
[sjme_flexibleArrayCount
];
234 * Calculates the size of the allocation pool.
236 * @param size The size to use for the allocation pool.
237 * @return The size of the given allocation pool.
240 #define SJME_SIZEOF_ALLOC_POOL(size) \
241 (sizeof(sjme_alloc_pool) + (((size_t)(size)) * \
242 sizeof(sjme_jubyte)))
245 * Allocates a pool that is based on @c malloc() .
247 * @param outPool The resultant pool.
248 * @param size The requested pool size.
249 * @return Returns an error code.
252 sjme_errorCode
sjme_alloc_poolInitMalloc(
253 sjme_attrOutNotNull sjme_alloc_pool
** outPool
,
254 sjme_attrInPositive sjme_jint size
);
257 * Allocates a pool that is based on a static region of memory.
259 * @param outPool The resultant pool.
260 * @param baseAddr The base address of the block.
261 * @param size The size of the block.
262 * @return Returns an error code.
265 sjme_errorCode
sjme_alloc_poolInitStatic(
266 sjme_attrOutNotNull sjme_alloc_pool
** outPool
,
267 sjme_attrInNotNull sjme_pointer baseAddr
,
268 sjme_attrInPositive sjme_jint size
);
271 * Returns the total space that is available within the pool, includes both
272 * free and used spaces.
274 * @param pool The pool to get the information of.
275 * @param outTotal The total space of the pool, will be @c outReserved plus
276 * the value of @c outUsable .
277 * @param outReserved The total reserved space within the pool.
278 * @param outUsable The total usable space within the pool.
279 * @return Any error or otherwise success.
282 sjme_errorCode
sjme_alloc_poolSpaceTotalSize(
283 sjme_attrInNotNull
const sjme_alloc_pool
* pool
,
284 sjme_attrOutNullable sjme_jint
* outTotal
,
285 sjme_attrOutNullable sjme_jint
* outReserved
,
286 sjme_attrOutNullable sjme_jint
* outUsable
);
289 * Allocates memory within the given pool.
291 * @param pool The pool to allocate within.
292 * @param size The number of bytes to allocate.
293 * @param outAddr The output address.
294 * @return Returns an error code.
297 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc
)(
298 sjme_attrInNotNull
volatile sjme_alloc_pool
* pool
,
299 sjme_attrInPositiveNonZero sjme_jint size
,
300 sjme_attrOutNotNull sjme_pointer
* outAddr
301 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
);
304 * Allocates a weak reference within the given pool.
306 * @param inPool The pool to allocate within.
307 * @param size The number of bytes to allocate.
308 * @param inEnqueue The optional function to call when this reference is
309 * enqueued. If this function returns @c SJME_ERROR_ENQUEUE_KEEP_WEAK and the
310 * weak reference count is zero, then the weak reference will not be freed.
311 * @param inEnqueueData Optional data to pass to @c inEnqueue .
312 * @param outAddr The output address.
313 * @param outWeak The resultant weak reference.
314 * @return Returns an error code.
317 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_weakNew
)(
318 sjme_attrInNotNull
volatile sjme_alloc_pool
* inPool
,
319 sjme_attrInPositiveNonZero sjme_jint size
,
320 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
321 sjme_attrInNullable sjme_pointer inEnqueueData
,
322 sjme_attrOutNotNull sjme_pointer
* outAddr
,
323 sjme_attrOutNotNull sjme_alloc_weak
* outWeak
324 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
);
327 * Allocates a copy of the given data.
329 * @param pool The pool to allocate within.
330 * @param size The allocation size.
331 * @param outAddr The output address.
332 * @param inAddr The input address.
333 * @return Returns an error code.
336 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_copy
)(
337 sjme_attrInNotNull
volatile sjme_alloc_pool
* pool
,
338 sjme_attrInPositiveNonZero sjme_jint size
,
339 sjme_attrOutNotNull sjme_pointer
* outAddr
,
340 sjme_attrInNotNull sjme_pointer inAddr
341 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
);
344 * Allocates a formatted string.
346 * @param inPool The pool to allocate within.
347 * @param outString The output string.
348 * @param format The format string.
350 * @return Any resultant error.
353 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_format
)(
354 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
355 sjme_attrOutNotNull sjme_lpstr
* outString
,
356 SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL SJME_DEBUG_ONLY_COMMA
357 sjme_attrInNotNull sjme_attrFormatArg
const char* format
,
358 ...) SJME_DEBUG_TERNARY(sjme_attrFormatOuter(5, 6),
359 sjme_attrFormatOuter(2, 3));
362 * Reallocates memory, either growing it or shrinking... the pointer will be
363 * adjusted accordingly.
365 * @param inOutAddr The address to reallocate.
366 * @param newSize The new size of the allocation, if @c 0 then the pointer
368 * @return Returns an error code.
371 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_realloc
)(
372 sjme_attrInOutNotNull sjme_pointer
* inOutAddr
,
373 sjme_attrInPositive sjme_jint newSize
374 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
);
377 * Allocates a copy of the given C character sequence.
379 * @param inPool The pool to allocate within.
380 * @param outString The output string copy.
381 * @param stringToCopy The string to copy.
382 * @return Any resultant error, if any.
385 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_strdup
)(
386 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
387 sjme_attrOutNotNull sjme_lpcstr
* outString
,
388 sjme_attrInNotNull sjme_lpcstr stringToCopy
389 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
);
391 #if defined(SJME_CONFIG_DEBUG)
394 * Allocates memory within the given pool.
396 * @param pool The pool to allocate within.
397 * @param size The number of bytes to allocate.
398 * @param outAddr The output address.
399 * @return Returns an error code.
402 #define sjme_alloc(pool, size, outAddr) \
403 sjme_allocR((pool), (size), (outAddr), SJME_DEBUG_FILE_LINE_FUNC)
406 * Allocates a weak reference within the given pool.
408 * @param pool The pool to allocate within.
409 * @param size The number of bytes to allocate.
410 * @param inEnqueue The optional function to call when this reference is
411 * enqueued. If this function returns @c SJME_ERROR_ENQUEUE_KEEP_WEAK and the
412 * weak reference count is zero, then the weak reference will not be freed.
413 * @param inEnqueueData Optional data to pass to @c inEnqueue .
414 * @param outAddr The output address.
415 * @param outWeak The resultant weak reference.
416 * @return Returns an error code.
419 #define sjme_alloc_weakNew(pool, size, inEnqueue, inEnqueueData, \
421 sjme_alloc_weakNewR((pool), (size), (inEnqueue), (inEnqueueData), \
422 (outAddr), (outWeak), SJME_DEBUG_FILE_LINE_FUNC)
425 * Allocates a copy of the given data.
427 * @param pool The pool to allocate within.
428 * @param size The allocation size.
429 * @param outAddr The output address.
430 * @param inAddr The input address.
431 * @return Returns an error code.
434 #define sjme_alloc_copy(pool, size, outAddr, inAddr) \
435 sjme_alloc_copyR((pool), (size), (outAddr), (inAddr), \
436 SJME_DEBUG_FILE_LINE_FUNC)
439 * Allocates a formatted string.
441 * @param inPool The pool to allocate within.
442 * @param outString The output string.
443 * @param format The format string.
445 * @return Any resultant error.
448 #define sjme_alloc_format(inPool, outString, ...) \
449 sjme_alloc_formatR((inPool), (outString), SJME_DEBUG_FILE_LINE_FUNC, \
453 * Reallocates memory, either growing it or shrinking... the pointer will be
454 * adjusted accordingly.
456 * @param inOutAddr The address to reallocate.
457 * @param newSize The new size of the allocation, if @c 0 then the pointer
459 * @return Returns an error code.
462 #define sjme_alloc_realloc(inOutAddr, newSize) \
463 sjme_alloc_reallocR((inOutAddr), (newSize), SJME_DEBUG_FILE_LINE_FUNC)
466 * Allocates a copy of the given C character sequence.
468 * @param inPool The pool to allocate within.
469 * @param outString The output string copy.
470 * @param stringToCopy The string to copy.
471 * @return Any resultant error, if any.
474 #define sjme_alloc_strdup(inPool, outString, stringToCopy) \
475 sjme_alloc_strdupR((inPool), (outString), (stringToCopy), \
476 SJME_DEBUG_FILE_LINE_FUNC)
483 * @param addr The memory to free.
484 * @return Returns @c SJME_JNI_TRUE on success.
487 sjme_errorCode
sjme_alloc_free(
488 sjme_attrInNotNull sjme_pointer addr
);
491 * Returns the link of the given memory block
493 * @param addr The pointer to get the link from.
494 * @param outLink The resultant link.
495 * @return Returns an error code.
498 sjme_errorCode
sjme_alloc_getLink(
499 sjme_attrInNotNull sjme_pointer addr
,
500 sjme_attrOutNotNull sjme_alloc_link
** outLink
);
503 * Deletes a weak reference by un-counting it, if the count reaches zero
504 * then this weak will be freed if that was requested.
506 * @param inOutWeak The weak reference to delete, if the count reaches
507 * zero then the pointer will be set to @c NULL .
508 * @return Any resultant error, if any.
511 sjme_errorCode
sjme_alloc_weakDelete(
512 sjme_attrInOutNotNull sjme_alloc_weak
* inOutWeak
);
515 * Gets the pointer pointed to by the given weak reference, if this returns
516 * the value @c NULL then @c sjme_alloc_weakDelete should be called to
517 * remove any stale weak references.
519 * @param inWeak The weak reference to get from.
520 * @param outPointer The pointer to the referenced memory, if it has been
521 * freed then this will return @c NULL .
522 * @return Any resultant error, if any.
525 sjme_errorCode
sjme_alloc_weakGetPointer(
526 sjme_attrInNotNull sjme_alloc_weak inWeak
,
527 sjme_attrOutNotNull sjme_pointer
* outPointer
);
530 * Creates or returns a weak reference to the given block. If the reference
531 * already exists, then it will be incremented.
533 * @param addr The address to reference.
534 * @param outWeak The resultant weak reference for the type.
535 * @param inEnqueue The optional function to call when this reference is
536 * enqueued. If this function returns @c SJME_ERROR_ENQUEUE_KEEP_WEAK and the
537 * weak reference count is zero, then the weak reference will not be freed.
538 * @param inEnqueueData Optional data to pass to @c inEnqueue .
539 * @return Any resultant error, if any.
542 sjme_errorCode
sjme_alloc_weakRef(
543 sjme_attrInNotNull sjme_pointer addr
,
544 sjme_attrOutNotNull sjme_alloc_weak
* outWeak
,
545 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
546 sjme_attrInNullable sjme_pointer inEnqueueData
);
548 #if defined(SJME_CONFIG_DEBUG)
551 * Dumps the entire pool.
553 * @param inPool The pool to dump.
554 * @return Any resultant error, if any.
557 sjme_errorCode
sjme_alloc_poolDump(
558 sjme_attrInNotNull sjme_alloc_pool
* inPool
);
562 /*--------------------------------------------------------------------------*/
566 #ifdef SJME_CXX_SQUIRRELJME_ALLOC_H
568 #undef SJME_CXX_SQUIRRELJME_ALLOC_H
569 #undef SJME_CXX_IS_EXTERNED
570 #endif /* #ifdef SJME_CXX_SQUIRRELJME_ALLOC_H */
571 #endif /* #ifdef __cplusplus */
573 #endif /* SQUIRRELJME_ALLOC_H */