Skip to content

Commit

Permalink
feature(exit): change _atexit_call into __cxa_finalize
Browse files Browse the repository at this point in the history
JIRA: RTOS-900
  • Loading branch information
badochov committed Aug 27, 2024
1 parent 49f0324 commit 01d99b7
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 25 deletions.
66 changes: 43 additions & 23 deletions stdlib/atexit.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ typedef void (*destructor_t)(void);

struct atexit_node {
destructor_t destructors[ATEXIT_MAX];
void *handles[ATEXIT_MAX];
void *args[ATEXIT_MAX];
uint32_t fntype;
uint32_t called;
struct atexit_node *prev;
};

Expand All @@ -53,7 +55,7 @@ void _atexit_init(void)


/* Generic function to register destructors */
static int _atexit_register(int isarg, void (*fn)(void), void *arg)
static int _atexit_register(int isarg, void (*fn)(void), void *arg, void *handle)
{
struct atexit_node *node;

Expand All @@ -79,53 +81,71 @@ static int _atexit_register(int isarg, void (*fn)(void), void *arg)
}
node->destructors[atexit_common.idx] = fn;

node->handles[atexit_common.idx] = handle;

atexit_common.idx++;

mutexUnlock(atexit_common.lock);
return 0;
}


/* Call all registered destructors */
void _atexit_call(void)
/* Call destructors registered for given object, or all in case of NULL */
/* Conforming: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#dso-dtor */
void __cxa_finalize(void *handle)
{
struct atexit_node *head = atexit_common.head;
unsigned int idx = atexit_common.idx;

mutexLock(atexit_common.lock);
while ((atexit_common.head != NULL) && (atexit_common.idx != 0)) {
atexit_common.idx--;
destructor_t destructor = atexit_common.head->destructors[atexit_common.idx];
if (((atexit_common.head->fntype >> atexit_common.idx) & 1) == 1) {
void *arg = atexit_common.head->args[atexit_common.idx];
mutexUnlock(atexit_common.lock);
((void (*)(void *))destructor)(arg);
while ((head != NULL) && (idx != 0)) {
idx--;

if (((handle == NULL) || (handle == head->handles[idx])) && (((head->called >> idx) & 1) == 0)) {
destructor_t destructor = head->destructors[idx];
/* Prevent calling destructor twice */
head->called |= (1 << idx);

if (((head->fntype >> idx) & 1) == 1) {
void *arg = head->args[idx];
mutexUnlock(atexit_common.lock);
((void (*)(void *))destructor)(arg);
}
else {
mutexUnlock(atexit_common.lock);
destructor();
}
mutexLock(atexit_common.lock);
}
else {
mutexUnlock(atexit_common.lock);
destructor();

if (idx == 0) {
head = head->prev;
idx = ATEXIT_MAX;
}
mutexLock(atexit_common.lock);
}

if (atexit_common.idx == 0) {
/* Final call, free memory */
if (handle == NULL) {
/* Ensure the first node that is statically allocated is not freed */
while (atexit_common.head->prev != NULL) {
struct atexit_node *last = atexit_common.head;
atexit_common.head = atexit_common.head->prev;
if (atexit_common.head != NULL) {
/* Free only if it's not the first node (statically allocated) */
free(last);
atexit_common.idx = ATEXIT_MAX;
}
free(last);
}
}

mutexUnlock(atexit_common.lock);
}


int atexit(void (*func)(void))
{
return _atexit_register(0, func, NULL);
return _atexit_register(0, func, NULL, NULL);
}


/* Register a function to run at process termination with given arguments */
int __cxa_atexit(void (*func)(void *), void *arg, void *handler)
int __cxa_atexit(void (*func)(void *), void *arg, void *handle)
{
return _atexit_register(1, (void (*)(void))func, arg);
return _atexit_register(1, (void (*)(void))func, arg, handle);
}
4 changes: 2 additions & 2 deletions stdlib/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <stdlib.h>
#include <stdio.h>

extern void _atexit_call(void);
extern void __cxa_finalize(void*);
extern void sys_exit(int) __attribute__((noreturn));


Expand All @@ -35,7 +35,7 @@ void _Exit(int status)
void exit(int status)
{
fflush(NULL);
_atexit_call();
__cxa_finalize(NULL);
_exit(status);
for(;;);
}

0 comments on commit 01d99b7

Please sign in to comment.