-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ff19661
commit ac77ee4
Showing
6 changed files
with
145 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#include "atexit-impl.h" | ||
|
||
#include <new> | ||
|
||
using namespace __impl; | ||
|
||
bool RegistrationList::push_front(const ExitFunctionStorage &new_exit) { | ||
auto ¤t_block = *m_list; | ||
|
||
if (!current_block.full()) { | ||
current_block.push_front(new_exit); | ||
return true; | ||
} | ||
|
||
const auto next_block = new (std::nothrow) FnNode{m_list}; | ||
if (!next_block) { | ||
// not enough memory to allocate another exit function | ||
return false; | ||
} | ||
|
||
// link new block to front of list. | ||
next_block->push_front(new_exit); | ||
m_list = next_block; | ||
return true; | ||
} | ||
|
||
void RegistrationList::run_all_exits() { | ||
while (m_list != &m_tail || !m_list->empty()) { | ||
if (!m_list->empty()) { | ||
// Note: fn may itself call atexit, so pop first. | ||
ExitFunctionStorage fn = m_list->back(); | ||
m_list->pop_back(); | ||
fn(); | ||
} else { | ||
const auto current_node_ptr = static_cast<FnNode *>(m_list); | ||
const auto next_block = current_node_ptr->m_next; | ||
// current_node_ptr is leaked here. We are shutting down. | ||
m_list = next_block; | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#ifndef ATEXIT_IMPL_H | ||
#define ATEXIT_IMPL_H | ||
|
||
#include <cstdint> | ||
|
||
namespace __impl { | ||
|
||
struct ExitFunctionStorage { | ||
void (*m_functionptr)(void *); | ||
void *m_userdata; | ||
|
||
void operator()() const { m_functionptr(m_userdata); } | ||
}; | ||
|
||
/* Exit functions are registered in a singly-linked list of blocks of | ||
* registrations. Each block contains 32 exit registrations, and additional | ||
* space for registrations is allocated on the heap, as needed.*/ | ||
class RegistrationList { | ||
// FnBlock is an array of function pointers and their arguments. | ||
// The logical "front" of the block is the last item appended to | ||
// the array. | ||
struct FnBlock { | ||
static constexpr std::uint8_t BLOCK_SZ = 32; | ||
|
||
ExitFunctionStorage m_funcs[BLOCK_SZ]; | ||
std::uint8_t m_sz; | ||
|
||
bool empty() const { return !m_sz; } | ||
bool full() const { return m_sz == BLOCK_SZ; } | ||
|
||
void push_front(const ExitFunctionStorage &newfn) { | ||
m_funcs[m_sz++] = newfn; | ||
} | ||
|
||
const ExitFunctionStorage &back() const { return m_funcs[m_sz - 1]; } | ||
void pop_back() { m_sz--; } | ||
}; | ||
|
||
struct FnNode : public FnBlock { | ||
FnNode(FnBlock *next) : m_next{next} {} | ||
|
||
FnBlock *const m_next = nullptr; | ||
}; | ||
|
||
// The initial base node allows 32 exit registrations (1 block) | ||
// of exit functions, without allocating. So the minumum required | ||
// 32 exit functions will always be available. | ||
FnBlock m_tail; | ||
FnBlock *m_list = &m_tail; | ||
|
||
public: | ||
bool push_front(const ExitFunctionStorage &new_exit); | ||
void run_all_exits(); | ||
}; | ||
|
||
} // namespace __impl | ||
|
||
#endif // not ATEXIT_IMPL_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#include "atexit-impl.h" | ||
|
||
#include <stdlib.h> | ||
|
||
using namespace __impl; | ||
|
||
static RegistrationList quick_exit_list; | ||
|
||
extern "C" { | ||
|
||
// Implemented under the assumption that there is only a single loaded binary, | ||
// with no dynamic loading. Accordingly, the mechanism for holding a DSO handle | ||
// (the third parameter) is ignored. | ||
int __cxa_at_quick_exit(void (*f)(void *), void *p, void * /* dso_handle */) { | ||
// Return values equal to C/C++ atexit() return value. | ||
return !quick_exit_list.push_front(ExitFunctionStorage{f, p}); | ||
} | ||
|
||
int at_quick_exit(void (*function)(void)) { | ||
return __cxa_at_quick_exit(reinterpret_cast<void (*)(void *)>(function), | ||
nullptr, nullptr); | ||
} | ||
|
||
_Noreturn void quick_exit(int status) { | ||
quick_exit_list.run_all_exits(); | ||
_Exit(status); | ||
} | ||
|
||
} // extern "C" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters