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 // -------------------------------------------------------------------------*/
13 /* Include Valgrind if it is available? */
14 #if defined(SJME_CONFIG_HAS_VALGRIND)
19 #include "sjme/alloc.h"
20 #include "sjme/debug.h"
21 #include "sjme/atomic.h"
22 #include "sjme/multithread.h"
23 #include "sjme/dylib.h"
25 /** The minimum size permitted for allocation pools. */
26 #define SJME_ALLOC_MIN_SIZE (((SJME_SIZEOF_ALLOC_POOL(0) + \
27 (SJME_SIZEOF_ALLOC_LINK(0) * 3)) | 0x1FF))
29 /** The minimum size for splits. */
30 #define SJME_ALLOC_SPLIT_MIN_SIZE 64
32 /** The front guard value. */
33 #define SJME_ALLOC_GUARD_FRONT INT32_C(0x53716B21)
35 /** The back guard value. */
36 #define SJME_ALLOC_GUARD_BACK INT32_C(0x6C65783F)
38 #if defined(SJME_CONFIG_DEBUG)
40 * Prints information on a given link and returns.
42 * @param pool The pool this is in.
43 * @param atLink The link to print info for.
44 * @param trigger The trigger for the failure.
45 * @return Always @c SJME_JNI_TRUE .
48 static sjme_inline sjme_jboolean
sjme_alloc_corruptFail(
49 volatile sjme_alloc_pool
* pool
,
50 volatile sjme_alloc_link
* atLink
,
53 sjme_message("Corrupted Link %p: %s", atLink
, trigger
);
59 /* Dump everything about the link. */
60 sjme_message("link->guardFront: %08x", atLink
->guardFront
);
61 sjme_message("link->pool: %p (should be %p)", atLink
->pool
, pool
);
62 sjme_message("link->prev: %p", atLink
->prev
);
63 sjme_message("link->next: %p", atLink
->next
);
64 if (atLink
->space
== SJME_ALLOC_POOL_SPACE_USED
)
65 sjme_message("link->space: USED");
66 else if (atLink
->space
== SJME_ALLOC_POOL_SPACE_FREE
)
67 sjme_message("link->space: FREE");
68 else if (atLink
->space
== SJME_NUM_ALLOC_POOL_SPACE
)
69 sjme_message("link->space: NUM");
71 sjme_message("link->space: %d", (int)atLink
->space
);
72 sjme_message("link->weak: %p", atLink
->weak
);
73 sjme_message("link->freePrev: %p", atLink
->freePrev
);
74 sjme_message("link->freeNext: %p", atLink
->freeNext
);
75 sjme_message("link->allocSize: %d", (int)atLink
->allocSize
);
76 sjme_message("link->blockSize: %d", (int)atLink
->blockSize
);
77 sjme_message("link->guardBack: %08x", atLink
->guardBack
);
80 if (sjme_debug_handlers
!= NULL
&& sjme_debug_handlers
->abort
!= NULL
)
81 sjme_debug_handlers
->abort();
83 /* Always indicate failure here. */
88 * Prints information on a given link and returns.
90 * @param pool The pool this is in.
91 * @param atLink The link to print info for.
92 * @param trigger The trigger for the failure.
93 * @return Always @c SJME_JNI_TRUE .
96 #define sjme_alloc_corruptFail(pool, atLink, trigger) SJME_JNI_TRUE
99 static sjme_inline sjme_jboolean
sjme_alloc_checkCorruptionRange(
100 sjme_alloc_pool
* pool
, uintptr_t poolStart
, uintptr_t poolEnd
,
101 sjme_alloc_link
* atLink
)
105 /* Ignore null pointers. */
107 return SJME_JNI_FALSE
;
109 /* Nominal address of the check pointer. */
110 check
= (uintptr_t)atLink
;
112 /* Must be in range! */
113 if (check
< poolStart
|| check
>= poolEnd
)
114 return sjme_alloc_corruptFail(pool
, atLink
,
115 "Out of range link");
117 /* Does not appear corrupt. */
118 return SJME_JNI_FALSE
;
122 * Checks the integrity of the memory pool.
124 * @param pool The pool to check in.
125 * @param atLink The link of the pool.
126 * @return If there is corruption or not.
129 static sjme_jboolean sjme_noOptimize
sjme_alloc_checkCorruption(
130 volatile sjme_alloc_pool
* pool
,
131 volatile sjme_alloc_link
* atLink
)
133 uintptr_t poolStart
, poolEnd
;
136 return SJME_JNI_TRUE
;
138 /* If no link is specified, ignore. */
140 return SJME_JNI_FALSE
;
142 /* Check front and back guards. */
143 if (atLink
->guardFront
!= SJME_ALLOC_GUARD_FRONT
)
144 return sjme_alloc_corruptFail(pool
, atLink
,
145 "Wrong front guard");
146 if (atLink
->guardBack
!= SJME_ALLOC_GUARD_BACK
)
147 return sjme_alloc_corruptFail(pool
, atLink
,
150 /* Link is in the wrong pool. */
151 if (atLink
->pool
!= pool
)
152 return sjme_alloc_corruptFail(pool
, atLink
,
155 /* Allocation size larger than block? */
156 if (atLink
->allocSize
> atLink
->blockSize
)
157 return sjme_alloc_corruptFail(pool
, atLink
,
158 "Allocation size larger than block.");
160 /* Next link is in the wrong location? */
161 if (atLink
->next
!= NULL
&& (uintptr_t)atLink
->next
!=
162 (uintptr_t)&atLink
->block
[atLink
->blockSize
])
163 return sjme_alloc_corruptFail(pool
, atLink
,
164 "Next not at block end");
166 /* Is front/end link? */
167 if (atLink
== pool
->frontLink
|| atLink
== pool
->backLink
)
169 /* Link space incorrect? */
170 if (atLink
->space
!= SJME_NUM_ALLOC_POOL_SPACE
)
171 return sjme_alloc_corruptFail(pool
, atLink
,
172 "Front/Back link not in correct space");
174 /* Size is not zero? */
175 if (atLink
->blockSize
!= 0 || atLink
->allocSize
!= 0)
176 return sjme_alloc_corruptFail(pool
, atLink
,
177 "Front/back link sizes non-zero");
179 /* Does not appear corrupt. */
180 return SJME_JNI_FALSE
;
183 /* Invalid block size? */
184 if (atLink
->blockSize
<= 0)
185 return sjme_alloc_corruptFail(pool
, atLink
,
186 "Zero or negative block size");
188 /* Used for checking the integrity of pointers. */
189 poolStart
= (uintptr_t)pool
;
190 poolEnd
= (uintptr_t)&pool
->block
[pool
->size
];
192 /* Free link only. */
193 if (atLink
->space
== SJME_ALLOC_POOL_SPACE_FREE
)
195 /* Check free links. */
196 if (sjme_alloc_checkCorruptionRange(pool
, poolStart
, poolEnd
,
198 return sjme_alloc_corruptFail(pool
, atLink
,
200 if (sjme_alloc_checkCorruptionRange(pool
, poolStart
, poolEnd
,
202 return sjme_alloc_corruptFail(pool
, atLink
,
206 /* Used link only. */
207 else if (atLink
->space
== SJME_ALLOC_POOL_SPACE_USED
)
209 /* Zero or negative size. */
210 if (atLink
->allocSize
<= 0)
211 return sjme_alloc_corruptFail(pool
, atLink
,
212 "Zero/negative used allocSize");
214 /* Cannot have any free or previous links. */
215 if (atLink
->freePrev
!= NULL
|| atLink
->freeNext
!= NULL
)
216 return sjme_alloc_corruptFail(pool
, atLink
,
217 "Used has free links");
220 /* Link space incorrect? */
222 return sjme_alloc_corruptFail(pool
, atLink
,
225 /* Check common next links. */
226 if (sjme_alloc_checkCorruptionRange(pool
, poolStart
, poolEnd
,
228 return sjme_alloc_corruptFail(pool
, atLink
,
230 if (sjme_alloc_checkCorruptionRange(pool
, poolStart
, poolEnd
,
232 return sjme_alloc_corruptFail(pool
, atLink
,
235 /* Does not appear corrupt. */
236 return SJME_JNI_FALSE
;
239 static sjme_errorCode
sjme_alloc_getLinkOptional(
240 sjme_attrInNotNull sjme_pointer addr
,
241 sjme_attrOutNotNull sjme_alloc_link
** outLink
,
242 sjme_attrInValue sjme_jboolean checkCorruption
)
244 sjme_alloc_link
* link
;
246 if (addr
== NULL
|| outLink
== NULL
)
247 return SJME_ERROR_NULL_ARGUMENTS
;
249 /* Just need to do some reversing math. */
250 link
= (sjme_alloc_link
*)(((uintptr_t)addr
) -
251 offsetof(sjme_alloc_link
, block
));
253 /* Check the integrity of the link. */
255 sjme_alloc_checkCorruption(link
->pool
, link
);
259 return SJME_ERROR_NONE
;
262 sjme_errorCode sjme_noOptimize
sjme_alloc_poolInitMalloc(
263 sjme_attrOutNotNull sjme_alloc_pool
** outPool
,
264 sjme_attrInPositive sjme_jint size
)
269 /* Make sure the size is not wonky. */
270 useSize
= SJME_SIZEOF_ALLOC_POOL(size
);
271 if (outPool
== NULL
|| size
<= SJME_ALLOC_MIN_SIZE
|| useSize
<= 0 ||
273 return SJME_ERROR_INVALID_ARGUMENT
;
275 /* Attempt allocation. */
276 result
= malloc(useSize
);
278 return SJME_ERROR_OUT_OF_MEMORY
;
280 /* Use static pool initializer to set up structures. */
281 return sjme_alloc_poolInitStatic(outPool
, result
, useSize
);
284 sjme_errorCode sjme_noOptimize
sjme_alloc_poolInitStatic(
285 sjme_attrOutNotNull sjme_alloc_pool
** outPool
,
286 sjme_attrInNotNull sjme_pointer baseAddr
,
287 sjme_attrInPositive sjme_jint size
)
289 sjme_alloc_pool
* pool
;
290 sjme_alloc_link
* frontLink
;
291 sjme_alloc_link
* midLink
;
292 sjme_alloc_link
* backLink
;
293 sjme_alloc_link
* specialParent
;
295 if (outPool
== NULL
|| baseAddr
== NULL
)
296 return SJME_ERROR_NULL_ARGUMENTS
;
298 if (size
<= SJME_ALLOC_MIN_SIZE
)
299 return SJME_ERROR_INVALID_ARGUMENT
;
301 /* Initialize memory to nothing. */
302 memset(baseAddr
, 0, size
);
304 /* Setup initial pool structure. */
306 pool
->size
= (size
& (~7)) - SJME_SIZEOF_ALLOC_POOL(0);
308 /* Setup front link. */
309 frontLink
= (sjme_pointer
)&pool
->block
[0];
310 pool
->frontLink
= frontLink
;
312 /* Setup back link. */
313 backLink
= (sjme_pointer
)&pool
->block
[pool
->size
-
314 SJME_SIZEOF_ALLOC_LINK(0)];
315 pool
->backLink
= backLink
;
317 /* Setup middle link, which is between the two. */
318 midLink
= (sjme_pointer
)&frontLink
->block
[0];
319 midLink
->prev
= frontLink
;
320 frontLink
->next
= midLink
;
321 midLink
->next
= backLink
;
322 backLink
->prev
= midLink
;
324 /* Determine size of the middle link, which is free space. */
325 midLink
->blockSize
= (sjme_jint
)((uintptr_t)backLink
-
326 (uintptr_t)&midLink
->block
[0]);
328 /* The mid-link is considered free. */
329 midLink
->space
= SJME_ALLOC_POOL_SPACE_FREE
;
331 /* The front and back links are in the "invalid" space. */
332 frontLink
->space
= SJME_NUM_ALLOC_POOL_SPACE
;
333 backLink
->space
= SJME_NUM_ALLOC_POOL_SPACE
;
335 /* Determine size that can and cannot be used. */
336 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].reserved
=
337 SJME_SIZEOF_ALLOC_LINK(0);
338 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
= midLink
->blockSize
;
340 /* Link in the first and last actual blocks for the free chain. */
341 pool
->freeFirstLink
= frontLink
;
342 frontLink
->freeNext
= midLink
;
343 midLink
->freePrev
= frontLink
;
344 pool
->freeLastLink
= backLink
;
345 backLink
->freePrev
= midLink
;
346 midLink
->freeNext
= backLink
;
348 /* Guards for all links. */
349 frontLink
->guardFront
= SJME_ALLOC_GUARD_FRONT
;
350 frontLink
->guardBack
= SJME_ALLOC_GUARD_BACK
;
351 midLink
->guardFront
= SJME_ALLOC_GUARD_FRONT
;
352 midLink
->guardBack
= SJME_ALLOC_GUARD_BACK
;
353 backLink
->guardFront
= SJME_ALLOC_GUARD_FRONT
;
354 backLink
->guardBack
= SJME_ALLOC_GUARD_BACK
;
357 frontLink
->pool
= pool
;
358 midLink
->pool
= pool
;
359 backLink
->pool
= pool
;
361 #if defined(SJME_CONFIG_DEBUG)
362 /* Debug source line init blocks. */
363 pool
->frontLink
->debugFile
= "<FRONT LINK>";
364 pool
->frontLink
->debugLine
= 1;
365 pool
->frontLink
->debugFunction
= "<FRONT LINK>";
367 pool
->backLink
->debugFile
= "<BACK LINK>";
368 pool
->backLink
->debugLine
= 1;
369 pool
->backLink
->debugFunction
= "<BACK LINK>";
372 #if defined(SJME_CONFIG_HAS_VALGRIND)
373 /* Reserve front side in Valgrind. */
374 VALGRIND_MAKE_MEM_NOACCESS(baseAddr
,
375 ((uintptr_t)&midLink
->block
[0] - (uintptr_t)baseAddr
));
377 /* Reserve back side in Valgrind. */
378 VALGRIND_MAKE_MEM_NOACCESS(backLink
,
379 (SJME_SIZEOF_ALLOC_LINK(0)));
382 /* If this is a valid link then we are allocating a nested pool. */
384 specialParent
= NULL
;
385 if (!sjme_error_is(sjme_alloc_getLinkOptional(baseAddr
,
386 &specialParent
, SJME_JNI_FALSE
)))
387 specialParent
->flags
|= SJME_ALLOC_LINK_FLAG_NESTED_POOL
;
392 return SJME_ERROR_NONE
;
395 sjme_errorCode
sjme_alloc_poolDestroy(
396 sjme_attrOutNotNull sjme_alloc_pool
* inPool
)
399 return SJME_ERROR_NULL_ARGUMENTS
;
401 return sjme_error_notImplemented(0);
404 sjme_errorCode
sjme_alloc_poolSpaceTotalSize(
405 sjme_attrInNotNull
const sjme_alloc_pool
* pool
,
406 sjme_attrOutNullable sjme_jint
* outTotal
,
407 sjme_attrOutNullable sjme_jint
* outReserved
,
408 sjme_attrOutNullable sjme_jint
* outUsable
)
415 return SJME_ERROR_NULL_ARGUMENTS
;
417 if (outTotal
== NULL
&& outReserved
== NULL
&& outUsable
== NULL
)
418 return SJME_ERROR_NULL_ARGUMENTS
;
420 /* Run through and tally values for each space. */
423 for (i
= 0; i
< SJME_NUM_ALLOC_POOL_SPACE
; i
++)
425 reserved
+= pool
->space
[i
].reserved
;
426 usable
+= pool
->space
[i
].usable
;
429 /* Total space is both. */
430 total
= reserved
+ usable
;
432 /* Store output values. */
433 if (outTotal
!= NULL
)
435 if (outReserved
!= NULL
)
436 *outReserved
= reserved
;
437 if (outUsable
!= NULL
)
441 return SJME_ERROR_NONE
;
444 sjme_errorCode sjme_noOptimize
SJME_DEBUG_IDENTIFIER(sjme_alloc
)(
445 sjme_attrInNotNull
volatile sjme_alloc_pool
* pool
,
446 sjme_attrInPositiveNonZero sjme_jint size
,
447 sjme_attrOutNotNull sjme_pointer
* outAddr
448 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
450 sjme_errorCode error
;
451 sjme_alloc_link
* scanLink
;
452 sjme_alloc_link
* rightLink
;
453 sjme_jint splitMinSize
, roundSize
;
454 sjme_jboolean splitBlock
;
455 sjme_alloc_pool
* nextPool
;
456 volatile sjme_alloc_link
* nextFree
;
458 if (pool
== NULL
|| size
<= 0 || outAddr
== NULL
)
459 return SJME_ERROR_NULL_ARGUMENTS
;
461 #if defined(SJME_CONFIG_DEBUG)
462 if ((size
* 8) == SJME_CONFIG_HAS_POINTER
)
463 sjme_message("Alloc of single pointer in %s (%s:%d).",
467 /* Determine the size this will actually take up, which includes the */
468 /* link to be created following this. */
469 roundSize
= (((size
& 7) != 0) ? ((size
| 7) + 1) : size
);
470 splitMinSize
= roundSize
+
471 (sjme_jint
)SJME_SIZEOF_ALLOC_LINK(SJME_ALLOC_SPLIT_MIN_SIZE
) +
472 (sjme_jint
)SJME_SIZEOF_ALLOC_LINK(0);
473 if (size
> splitMinSize
|| splitMinSize
< 0)
474 return SJME_ERROR_INVALID_ARGUMENT
;
476 /* Take ownership of lock. */
477 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
479 return sjme_error_default(error
);
482 sjme_thread_barrier();
484 /* Find the first free link that this fits in. */
486 splitBlock
= SJME_JNI_FALSE
;
487 for (scanLink
= pool
->freeFirstLink
;
488 scanLink
!= NULL
; scanLink
= scanLink
->freeNext
)
490 /* Has memory been corrupted? */
491 nextFree
= scanLink
->freeNext
;
492 if (sjme_alloc_checkCorruption(pool
, scanLink
) ||
494 sjme_alloc_checkCorruption(pool
, nextFree
)))
496 error
= SJME_ERROR_MEMORY_CORRUPTION
;
500 /* Block is in the "invalid" space, skip it. */
501 if (scanLink
->space
== SJME_NUM_ALLOC_POOL_SPACE
)
504 /* Block fits perfectly here, without needing a split? */
505 if (scanLink
->blockSize
== roundSize
)
508 /* Block fits here when split, try to not split ridiculously small. */
509 if (scanLink
->blockSize
>= splitMinSize
)
511 splitBlock
= SJME_JNI_TRUE
;
517 if (scanLink
== NULL
)
519 /* If there is an adjacent pool, if allocation fails then we shall */
520 /* try the next pool, this means multiple pools can work together */
522 nextPool
= pool
->nextPool
;
523 if (nextPool
!= NULL
)
525 /* Release ownership of lock. */
526 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
527 &pool
->spinLock
, NULL
)))
528 return sjme_error_default(error
);
530 #if defined(SJME_CONFIG_DEBUG)
531 return sjme_allocR(nextPool
, size
, outAddr
,
534 return sjme_alloc(pool
->nextPool
, size
, outAddr
);
538 /* Otherwise fail! */
539 error
= SJME_ERROR_OUT_OF_MEMORY
;
545 sjme_message("Found link at %p: %d bytes, we need %d with split %d.",
546 scanLink
, (int)scanLink
->blockSize
, (int)roundSize
, (int)splitBlock
);
549 /* Does this block need to be split? */
552 /* Check for link corruption on the adjacent links. */
553 if (sjme_alloc_checkCorruption(pool
, scanLink
->next
) ||
554 sjme_alloc_checkCorruption(pool
, scanLink
->prev
) ||
555 sjme_alloc_checkCorruption(pool
, scanLink
->freeNext
) ||
556 sjme_alloc_checkCorruption(pool
, scanLink
->freePrev
))
558 error
= SJME_ERROR_MEMORY_CORRUPTION
;
562 /* Make it so this block can actually fit in here. */
563 rightLink
= (sjme_alloc_link
*)&scanLink
->block
[roundSize
];
565 /* Initialize block to remove any old data. */
566 memset(rightLink
, 0, sizeof(*rightLink
));
568 /* Guards for link. */
569 rightLink
->guardFront
= SJME_ALLOC_GUARD_FRONT
;
570 rightLink
->guardBack
= SJME_ALLOC_GUARD_BACK
;
572 /* Set the right link's pool accordingly. */
573 rightLink
->pool
= pool
;
575 /* Make sure this block is marked as free. */
576 rightLink
->space
= SJME_ALLOC_POOL_SPACE_FREE
;
578 /* Set size of the right link. */
579 rightLink
->blockSize
=
580 (sjme_jint
)((intptr_t)&scanLink
->block
[scanLink
->blockSize
] -
581 (intptr_t)&rightLink
->block
[0]);
582 rightLink
->allocSize
= rightLink
->blockSize
;
584 /* Link in physical links. */
585 rightLink
->next
= scanLink
->next
;
586 rightLink
->next
->prev
= rightLink
;
587 scanLink
->next
= rightLink
;
588 rightLink
->prev
= scanLink
;
590 /* Link in free links. */
591 rightLink
->freeNext
= scanLink
->freeNext
;
592 rightLink
->freeNext
->freePrev
= rightLink
;
593 scanLink
->freeNext
= rightLink
;
594 rightLink
->freePrev
= scanLink
;
596 /* Set size of the left block. */
597 scanLink
->blockSize
=
598 (sjme_jint
)((intptr_t)rightLink
- (intptr_t)&scanLink
->block
[0]);
599 scanLink
->allocSize
= scanLink
->blockSize
;
601 /* Adjust reserved and usable space. */
602 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].reserved
+=
603 SJME_SIZEOF_ALLOC_LINK(0);
604 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
-=
605 SJME_SIZEOF_ALLOC_LINK(0);
607 /* Make sure we did not cause corruption. */
608 if (sjme_alloc_checkCorruption(pool
, scanLink
) ||
609 sjme_alloc_checkCorruption(pool
, rightLink
))
611 error
= SJME_ERROR_MEMORY_CORRUPTION
;
616 /* Setup block information. */
617 scanLink
->space
= SJME_ALLOC_POOL_SPACE_USED
;
619 /* Unlink from free links. */
620 if (scanLink
->freeNext
!= NULL
)
621 scanLink
->freeNext
->freePrev
= scanLink
->freePrev
;
622 if (scanLink
->freePrev
!= NULL
)
623 scanLink
->freePrev
->freeNext
= scanLink
->freeNext
;
624 scanLink
->freePrev
= NULL
;
625 scanLink
->freeNext
= NULL
;
627 /* Use our given allocation size. */
628 scanLink
->allocSize
= size
;
630 /* Adjust space that can actually be used for data. */
631 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
-= scanLink
->blockSize
;
632 pool
->space
[SJME_ALLOC_POOL_SPACE_USED
].usable
+= scanLink
->blockSize
;
634 /* Since this block is claimed, the reserved space moves over. */
635 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].reserved
-=
636 SJME_SIZEOF_ALLOC_LINK(0);
637 pool
->space
[SJME_ALLOC_POOL_SPACE_USED
].reserved
+=
638 SJME_SIZEOF_ALLOC_LINK(0);
640 #if defined(SJME_CONFIG_DEBUG)
641 /* Set debug info. */
642 scanLink
->debugFile
= file
;
643 scanLink
->debugLine
= line
;
644 scanLink
->debugFunction
= func
;
647 /* Make sure we did not cause corruption. */
648 if (sjme_alloc_checkCorruption(pool
, scanLink
) ||
649 sjme_alloc_checkCorruption(pool
, scanLink
->prev
) ||
650 sjme_alloc_checkCorruption(pool
, scanLink
->next
))
652 error
= SJME_ERROR_MEMORY_CORRUPTION
;
657 sjme_thread_barrier();
659 /* Release ownership of lock. */
660 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
661 &pool
->spinLock
, NULL
)))
662 return sjme_error_default(error
);
664 /* Use the given link. */
665 *outAddr
= &scanLink
->block
[0];
666 return SJME_ERROR_NONE
;
670 /* Release ownership of lock before we leave. */
671 if (sjme_error_is(sjme_thread_spinLockRelease(
672 &pool
->spinLock
, NULL
)))
673 return sjme_error_default(error
);
675 return sjme_error_default(error
);
678 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_copy
)(
679 sjme_attrInNotNull
volatile sjme_alloc_pool
* pool
,
680 sjme_attrInPositiveNonZero sjme_jint size
,
681 sjme_attrOutNotNull sjme_pointer
* outAddr
,
682 sjme_attrInNotNull sjme_pointer inAddr
683 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
685 sjme_errorCode error
;
688 if (pool
== NULL
|| outAddr
== NULL
|| inAddr
== NULL
)
689 return SJME_ERROR_NULL_ARGUMENTS
;
691 /* Allocate new copy first. */
693 if (sjme_error_is(error
= SJME_DEBUG_IDENTIFIER(sjme_alloc
)(
695 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY
)) || dest
== NULL
)
696 return sjme_error_default(error
);
699 memmove(dest
, inAddr
, size
);
703 return SJME_ERROR_NONE
;
706 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_copyWeak
)(
707 sjme_attrInNotNull
volatile sjme_alloc_pool
* pool
,
708 sjme_attrInPositiveNonZero sjme_jint size
,
709 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
710 sjme_attrInNullable sjme_pointer inEnqueueData
,
711 sjme_attrOutNotNull sjme_pointer
* outAddr
,
712 sjme_attrInNotNull sjme_pointer inAddr
,
713 sjme_attrOutNullable sjme_alloc_weak
* outWeak
714 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
716 sjme_errorCode error
;
719 if (pool
== NULL
|| outAddr
== NULL
|| inAddr
== NULL
)
720 return SJME_ERROR_NULL_ARGUMENTS
;
722 /* Allocate new copy first. */
724 if (sjme_error_is(error
= SJME_DEBUG_IDENTIFIER(sjme_alloc_weakNew
)(
725 pool
, size
, inEnqueue
, inEnqueueData
, &dest
, outWeak
726 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY
)) || dest
== NULL
)
727 return sjme_error_default(error
);
730 memmove(dest
, inAddr
, size
);
734 return SJME_ERROR_NONE
;
737 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_format
)(
738 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
739 sjme_attrOutNotNull sjme_lpstr
* outString
,
740 SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL SJME_DEBUG_ONLY_COMMA
741 sjme_attrInNotNull sjme_attrFormatArg
const char* format
,
749 if (inPool
== NULL
|| outString
== NULL
|| format
== NULL
)
750 return SJME_ERROR_NULL_ARGUMENTS
;
752 /* Start variable arguments. */
753 va_start(arg
, format
);
755 /* Format string to the buffer. */
756 memset(buf
, 0, sizeof(buf
));
757 vsnprintf(buf
, BUF_SIZE
- 1, format
, arg
);
759 /* Force to end with a NUL. */
760 buf
[BUF_SIZE
- 1] = 0;
765 /* Calculate length of string for copying. */
769 return SJME_DEBUG_IDENTIFIER(sjme_alloc_copy
)(inPool
, len
+ 1,
770 (sjme_pointer
*)outString
, buf
771 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY
);
775 static sjme_errorCode
sjme_alloc_mergeFree(sjme_alloc_link
* link
)
777 sjme_alloc_pool
* pool
;
778 sjme_alloc_link
* right
;
779 sjme_alloc_link
* oldRightFreeNext
;
780 sjme_alloc_link
* rightRight
;
781 sjme_alloc_link
* checkLeft
;
785 return SJME_ERROR_NULL_ARGUMENTS
;
787 /* Need pool for all operations. */
790 /* If the previous block is free, pivot to there. */
791 checkLeft
= link
->prev
;
792 if (checkLeft
->space
== SJME_ALLOC_POOL_SPACE_FREE
)
793 return sjme_alloc_mergeFree(checkLeft
);
795 /* Is the block on the right a candidate for merge? */
797 if (right
->space
!= SJME_ALLOC_POOL_SPACE_FREE
)
798 return SJME_ERROR_NONE
;
800 /* We need the block after to relink. */
801 rightRight
= right
->next
;
803 /* Disconnect in the middle. */
804 link
->next
= rightRight
;
805 rightRight
->prev
= link
;
807 /* Remove from the free chain. */
808 oldRightFreeNext
= right
->freeNext
;
809 right
->freePrev
->freeNext
= right
->freeNext
;
810 oldRightFreeNext
->freePrev
= right
->freePrev
;
812 /* Reclaim the right link data area. */
813 addedSize
= right
->blockSize
+ SJME_SIZEOF_ALLOC_LINK(0);
814 link
->blockSize
+= addedSize
;
816 /* Update pool sizes. */
817 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
+= addedSize
;
818 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].reserved
-=
819 SJME_SIZEOF_ALLOC_LINK(0);
821 /* Synchronize allocation size. */
822 link
->allocSize
= link
->blockSize
;
824 /* Wipe next side block to remove any stale data. */
825 memset(right
, 0, sizeof(*right
));
827 /* Should not have corrupted the block. */
828 if (sjme_alloc_checkCorruption(pool
, link
) ||
829 sjme_alloc_checkCorruption(pool
, link
->prev
) ||
830 sjme_alloc_checkCorruption(pool
, link
->next
) ||
831 sjme_alloc_checkCorruption(pool
, link
->freePrev
) ||
832 sjme_alloc_checkCorruption(pool
, link
->freeNext
))
833 return SJME_ERROR_MEMORY_CORRUPTION
;
835 /* We merged a block, so check again. */
836 return sjme_alloc_mergeFree(link
);
839 sjme_errorCode sjme_noOptimize
sjme_alloc_free(
840 sjme_attrInNotNull sjme_pointer addr
)
842 sjme_alloc_link
* link
;
843 volatile sjme_alloc_pool
* pool
;
844 sjme_errorCode error
;
845 sjme_alloc_weak weak
;
848 return SJME_ERROR_NULL_ARGUMENTS
;
851 sjme_thread_barrier();
855 if (sjme_error_is(error
= sjme_alloc_getLink(addr
, &link
)))
856 return sjme_error_default(error
);
858 /* Get the pool we are in. */
861 /* Take ownership of lock. */
862 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
864 return sjme_error_default(error
);
866 /* Check the integrity of the block before we free it. */
868 if (sjme_alloc_checkCorruption(pool
, link
))
870 error
= SJME_ERROR_MEMORY_CORRUPTION
;
874 /* If there is a weak reference, clear it. */
878 /* Call enqueue handler. */
879 if (weak
->enqueue
!= NULL
)
880 if (sjme_error_is(error
= weak
->enqueue(weak
,
881 weak
->enqueueData
, SJME_JNI_TRUE
)))
883 /* Keeping a weak reference is not considered an error */
884 /* although at this point it has no effect. */
885 if (error
!= SJME_ERROR_ENQUEUE_KEEP_WEAK
)
886 goto fail_weakEnqueueCall
;
889 /* Remove everything. */
892 weak
->pointer
= NULL
;
895 /* Mark block as free. */
896 link
->space
= SJME_ALLOC_POOL_SPACE_FREE
;
898 /* Clear flags, if any. */
901 /* Clear block memory so stale memory is not around. */
902 memset(&link
->block
[0], 0, link
->blockSize
);
904 /* Restore allocation size to block size. */
905 link
->allocSize
= link
->blockSize
;
907 #if defined(SJME_CONFIG_DEBUG)
908 /* Remove debug information. */
909 link
->debugFile
= NULL
;
911 link
->debugFunction
= NULL
;
914 /* Link into free chain. */
915 link
->freeNext
= pool
->freeFirstLink
->freeNext
;
916 pool
->freeFirstLink
->freeNext
= link
;
917 link
->freeNext
->freePrev
= link
;
918 link
->freePrev
= pool
->freeFirstLink
;
920 /* Merge together free blocks. */
921 if (sjme_error_is(error
= sjme_alloc_mergeFree(link
)))
925 sjme_thread_barrier();
927 /* Release ownership of lock. */
928 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
929 &pool
->spinLock
, NULL
)))
930 return sjme_error_default(error
);
933 return SJME_ERROR_NONE
;
935 /* Release ownership of lock. */
937 fail_weakEnqueueCall
:
939 if (sjme_error_is(sjme_thread_spinLockRelease(
940 &pool
->spinLock
, NULL
)))
941 return sjme_error_default(error
);
943 return sjme_error_default(error
);
946 sjme_errorCode
sjme_alloc_getLink(
947 sjme_attrInNotNull sjme_pointer addr
,
948 sjme_attrOutNotNull sjme_alloc_link
** outLink
)
950 return sjme_alloc_getLinkOptional(addr
, outLink
,
954 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_realloc
)(
955 sjme_attrInOutNotNull sjme_pointer
* inOutAddr
,
956 sjme_attrInPositive sjme_jint newSize
957 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
959 sjme_alloc_link
* link
;
963 sjme_errorCode error
;
965 if (inOutAddr
== NULL
|| *inOutAddr
== NULL
)
966 return SJME_ERROR_NULL_ARGUMENTS
;
969 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
972 sjme_thread_barrier();
974 /* Alias for free. */
978 /* Just do a normal free of it since zero was requested. */
979 if (sjme_error_is(error
= sjme_alloc_free(source
)))
980 return sjme_error_default(error
);
986 return SJME_ERROR_NULL_ARGUMENTS
;
989 /* Recover the link. */
991 if (sjme_error_is(error
= sjme_alloc_getLink(source
,
992 &link
)) || link
== NULL
)
993 return sjme_error_default(error
);
995 /* If there is a weak reference, then we cannot touch this. */
996 if (link
->weak
!= NULL
)
997 return SJME_ERROR_WEAK_REFERENCE_ATTACHED
;
999 /* Pointless operation. */
1000 if (newSize
== link
->allocSize
)
1001 return SJME_ERROR_NONE
;
1003 /* There are some padding bytes we can consume. */
1004 else if (newSize
> link
->allocSize
&& newSize
< link
->blockSize
)
1006 /* Just set the new allocation size. */
1007 link
->allocSize
= newSize
;
1010 sjme_thread_barrier();
1013 return SJME_ERROR_NONE
;
1016 /* No space to grow or shrink, move it. */
1019 /* How much do we actually want to copy? */
1020 if (newSize
< link
->allocSize
)
1023 limit
= link
->allocSize
;
1026 sjme_message("Realloc copy %d -> %d (%d)",
1027 link
->allocSize
, newSize
, limit
);
1029 /* Allocate new block. */
1031 if (sjme_error_is(error
= SJME_DEBUG_IDENTIFIER(sjme_alloc
)(
1032 link
->pool
, newSize
, &result
1033 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY
)) ||
1035 return sjme_error_defaultOr(error
,
1036 SJME_ERROR_OUT_OF_MEMORY
);
1038 /* Copy all the data over. */
1039 memmove(result
, source
, limit
);
1041 /* Free the old block. */
1042 if (sjme_error_is(error
= sjme_alloc_free(source
)))
1043 return sjme_error_default(error
);
1046 sjme_thread_barrier();
1049 *inOutAddr
= result
;
1050 return SJME_ERROR_NONE
;
1054 sjme_errorCode
SJME_DEBUG_IDENTIFIER(sjme_alloc_strdup
)(
1055 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
1056 sjme_attrOutNotNull sjme_lpcstr
* outString
,
1057 sjme_attrInNotNull sjme_lpcstr stringToCopy
1058 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
1062 if (inPool
== NULL
|| outString
== NULL
|| stringToCopy
== NULL
)
1063 return SJME_ERROR_NULL_ARGUMENTS
;
1065 /* Use standard string length, include NUL. */
1066 charLen
= strlen(stringToCopy
) + 1;
1068 /* Then just forward to copy. */
1069 #if defined(SJME_CONFIG_DEBUG)
1070 return sjme_alloc_copyR(inPool
, charLen
,
1071 (void**)outString
, (void*)stringToCopy
,
1074 return sjme_alloc_copy(inPool
, charLen
,
1075 outString
, stringToCopy
);
1079 sjme_errorCode sjme_noOptimize
sjme_alloc_weakDelete(
1080 sjme_attrInOutNotNull sjme_alloc_weak
* inOutWeak
)
1082 sjme_errorCode error
;
1083 sjme_alloc_weak weak
;
1085 sjme_jboolean keepWeak
;
1086 sjme_alloc_link
* link
;
1089 if (inOutWeak
== NULL
)
1090 return SJME_ERROR_NULL_ARGUMENTS
;
1092 /* Operate on this weak. */
1097 return SJME_ERROR_NONE
;
1100 sjme_thread_barrier();
1102 /* Get the current count. */
1103 count
= sjme_atomic_sjme_jint_get(&weak
->count
);
1105 /* If zero is reached, it is eligible for free. */
1106 /* Provided, the data is still there. */
1108 block
= weak
->pointer
;
1109 if (count
<= 1 && link
!= NULL
&& block
!= NULL
)
1111 /* Call enqueue handler if it exists. */
1112 keepWeak
= SJME_JNI_FALSE
;
1113 if (weak
->enqueue
!= NULL
)
1114 if (sjme_error_is(error
= weak
->enqueue(weak
,
1115 weak
->enqueueData
, SJME_JNI_FALSE
)))
1117 /* Only fail if we are not keeping it. */
1118 keepWeak
= (error
== SJME_ERROR_ENQUEUE_KEEP_WEAK
);
1120 return sjme_error_default(error
);
1123 /* Clear weak count to zero. */
1124 sjme_atomic_sjme_jint_set(&weak
->count
, 0);
1126 /* Unlink weak reference from block. */
1127 /* So that enqueue is not called multiple times. */
1130 weak
->pointer
= NULL
;
1132 /* Free the block we point to. */
1133 if (sjme_error_is(error
= sjme_alloc_free(block
)))
1134 return sjme_error_default(error
);
1136 /* Delete the weak reference as well? */
1139 /* Inform our pointer that it is gone. */
1142 /* Free the weak reference itself. */
1143 if (sjme_error_is(error
= sjme_alloc_free(weak
)))
1144 return sjme_error_default(error
);
1148 /* Otherwise, just count it down. */
1150 sjme_atomic_sjme_jint_set(&weak
->count
, count
- 1);
1153 sjme_thread_barrier();
1156 return SJME_ERROR_NONE
;
1159 sjme_errorCode
sjme_alloc_weakGetPointer(
1160 sjme_attrInNotNull sjme_alloc_weak inWeak
,
1161 sjme_attrOutNotNull sjme_pointer
* outPointer
)
1163 if (inWeak
== NULL
|| outPointer
== NULL
)
1164 return SJME_ERROR_NULL_ARGUMENTS
;
1167 sjme_thread_barrier();
1169 if (inWeak
->link
== NULL
|| inWeak
->pointer
== NULL
)
1172 *outPointer
= inWeak
->pointer
;
1175 sjme_thread_barrier();
1178 return SJME_ERROR_NONE
;
1181 static sjme_errorCode sjme_noOptimize
sjme_alloc_weakRefInternal(
1182 sjme_attrInNotNull sjme_pointer addr
,
1183 sjme_attrOutNullable sjme_alloc_weak
* outWeak
,
1184 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
1185 sjme_attrInNullable sjme_pointer inEnqueueData
)
1187 sjme_errorCode error
;
1188 sjme_alloc_link
* link
;
1189 sjme_alloc_weak result
;
1193 (inEnqueue
== NULL
&& inEnqueueData
!= NULL
))
1194 return SJME_ERROR_NULL_ARGUMENTS
;
1197 sjme_thread_barrier();
1199 /* Recover the link. */
1201 if (sjme_error_is(error
= sjme_alloc_getLink(addr
,
1202 &link
)) || link
== NULL
)
1203 return sjme_error_default(error
);
1205 /* Is there already a weak reference? */
1206 result
= link
->weak
;
1209 /* Enqueue can be set, but not overwritten. */
1210 if (inEnqueue
!= NULL
)
1213 if (result
->enqueue
== NULL
)
1215 result
->enqueue
= inEnqueue
;
1216 result
->enqueueData
= inEnqueueData
;
1219 /* Must be the same function. */
1220 else if (result
->enqueue
!= inEnqueue
||
1221 result
->enqueueData
!= inEnqueueData
)
1222 return SJME_ERROR_ENQUEUE_ALREADY_SET
;
1226 was
= sjme_atomic_sjme_jint_getAdd(&result
->count
, 1);
1229 sjme_thread_barrier();
1232 #if defined(SJME_CONFIG_DEBUG)
1233 sjme_message("Weak ref %p (%p) count up to %d.",
1234 result
->pointer
, result
, was
+ 1);
1238 if (outWeak
!= NULL
)
1240 return SJME_ERROR_NONE
;
1243 /* We need to allocate the link. */
1244 if (sjme_error_is(error
= sjme_alloc(link
->pool
, sizeof(*result
),
1246 return sjme_error_default(error
);
1248 /* Setup link information. */
1249 sjme_atomic_sjme_jint_set(&result
->valid
,
1250 SJME_ALLOC_WEAK_VALID
);
1251 result
->link
= link
;
1252 result
->pointer
= addr
;
1253 result
->enqueue
= inEnqueue
;
1254 result
->enqueueData
= inEnqueueData
;
1255 sjme_atomic_sjme_jint_set(&result
->count
, 1);
1257 /* Join link back to this. */
1258 link
->weak
= result
;
1261 sjme_thread_barrier();
1264 if (outWeak
!= NULL
)
1266 return SJME_ERROR_NONE
;
1269 sjme_errorCode sjme_noOptimize
SJME_DEBUG_IDENTIFIER(sjme_alloc_weakNew
)(
1270 sjme_attrInNotNull
volatile sjme_alloc_pool
* inPool
,
1271 sjme_attrInPositiveNonZero sjme_jint size
,
1272 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
1273 sjme_attrInNullable sjme_pointer inEnqueueData
,
1274 sjme_attrOutNotNull sjme_pointer
* outAddr
,
1275 sjme_attrOutNullable sjme_alloc_weak
* outWeak
1276 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL
)
1278 sjme_pointer resultPtr
;
1279 sjme_alloc_weak resultWeak
;
1280 sjme_errorCode error
;
1282 if (inPool
== NULL
|| outAddr
== NULL
||
1283 (inEnqueueData
!= NULL
&& inEnqueue
== NULL
))
1284 return SJME_ERROR_NULL_ARGUMENTS
;
1286 /* Take ownership of lock. */
1287 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
1288 &inPool
->spinLock
)))
1289 return sjme_error_default(error
);
1292 sjme_thread_barrier();
1294 /* Attempt block allocation first. */
1296 #if defined(SJME_CONFIG_DEBUG)
1297 if (sjme_error_is(error
= sjme_allocR(inPool
, size
,
1298 &resultPtr
, file
, line
, func
)) ||
1301 if (sjme_error_is(error
= sjme_alloc(inPool
, size
,
1305 goto fail_allocBlock
;
1307 /* Then create the weak reference. */
1309 if (sjme_error_is(error
= sjme_alloc_weakRefInternal(resultPtr
,
1310 &resultWeak
, inEnqueue
, inEnqueueData
)) || resultWeak
== NULL
)
1311 goto fail_allocWeak
;
1314 sjme_thread_barrier();
1316 /* Release ownership of lock. */
1317 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
1318 &inPool
->spinLock
, NULL
)))
1319 return sjme_error_default(error
);
1322 *outAddr
= resultPtr
;
1323 if (outWeak
!= NULL
)
1324 *outWeak
= resultWeak
;
1325 return SJME_ERROR_NONE
;
1329 if (resultPtr
!= NULL
)
1330 sjme_alloc_free(resultPtr
);
1332 /* Release ownership of lock. */
1333 if (sjme_error_is(sjme_thread_spinLockRelease(
1334 &inPool
->spinLock
, NULL
)))
1335 return sjme_error_default(error
);
1337 return sjme_error_default(error
);
1340 sjme_errorCode
sjme_alloc_weakRef(
1341 sjme_attrInNotNull sjme_pointer addr
,
1342 sjme_attrOutNullable sjme_alloc_weak
* outWeak
,
1343 sjme_attrInNullable sjme_alloc_weakEnqueueFunc inEnqueue
,
1344 sjme_attrInNullable sjme_pointer inEnqueueData
)
1346 volatile sjme_alloc_pool
* pool
;
1347 sjme_errorCode error
;
1348 sjme_alloc_link
* link
;
1351 (inEnqueue
== NULL
&& inEnqueueData
!= NULL
))
1352 return SJME_ERROR_NULL_ARGUMENTS
;
1355 sjme_thread_barrier();
1357 /* Recover the link. */
1359 if (sjme_error_is(error
= sjme_alloc_getLink(addr
,
1360 &link
)) || link
== NULL
)
1361 return sjme_error_default(error
);
1363 /* No weak reference here? */
1364 if (link
->weak
== NULL
)
1365 return SJME_ERROR_NOT_WEAK_REFERENCE
;
1367 /* Take ownership of lock. */
1369 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
1371 return sjme_error_default(error
);
1374 error
= sjme_alloc_weakRefInternal(addr
, outWeak
, inEnqueue
,
1377 /* Release ownership of lock. */
1378 if (sjme_error_is(sjme_thread_spinLockRelease(
1379 &pool
->spinLock
, NULL
)))
1380 return sjme_error_default(error
);
1385 sjme_errorCode
sjme_alloc_weakRefGet(
1386 sjme_attrInNotNull sjme_pointer addr
,
1387 sjme_attrOutNullable sjme_alloc_weak
* outWeak
)
1389 volatile sjme_alloc_pool
* pool
;
1390 sjme_errorCode error
;
1391 sjme_alloc_link
* link
;
1392 sjme_alloc_weak weak
;
1394 if (addr
== NULL
|| outWeak
== NULL
)
1395 return SJME_ERROR_NULL_ARGUMENTS
;
1398 sjme_thread_barrier();
1400 /* Recover the link. */
1402 if (sjme_error_is(error
= sjme_alloc_getLink(addr
,
1403 &link
)) || link
== NULL
)
1404 return sjme_error_default(error
);
1406 /* Take ownership of lock. */
1408 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
1410 return sjme_error_default(error
);
1412 /* No weak reference here? */
1415 error
= SJME_ERROR_NOT_WEAK_REFERENCE
;
1417 error
= SJME_ERROR_NONE
;
1419 /* Release ownership of lock. */
1420 if (sjme_error_is(sjme_thread_spinLockRelease(
1421 &pool
->spinLock
, NULL
)))
1422 return sjme_error_default(error
);
1425 if (sjme_error_is(error
))
1426 return sjme_error_default(error
);
1430 return SJME_ERROR_NONE
;
1433 sjme_errorCode
sjme_alloc_weakUnRef(
1434 sjme_attrInNotNull sjme_pointer addr
)
1436 sjme_errorCode error
;
1437 sjme_alloc_weak weak
;
1440 return SJME_ERROR_NULL_ARGUMENTS
;
1442 /* Obtain weak reference. */
1444 if (sjme_error_is(error
= sjme_alloc_weakRefGet(addr
, &weak
)) ||
1446 return sjme_error_default(error
);
1449 if (sjme_error_is(error
= sjme_alloc_weakDelete(&weak
)))
1450 return sjme_error_default(error
);
1453 return SJME_ERROR_NONE
;