Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232//// onexit.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// The _onexit registry, which stores pointers to functions to be called when// the program terminates or, when the CRT is statically linked into a DLL, when// the DLL is unloaded.//// When the CRT is statically linked into an EXE or a DLL, this registry is used// to hold the on-exit functions for the module (EXE or DLL) into which it is// linked.//// When the dynamic CRT is used, this object is part of the AppCRT DLL and this// registry stores the on-exit functions for the VCRuntime. If the EXE for the// process uses this VCRuntime, then this registry also stores the on-exit// functions for that EXE. If a DLL uses the dynamic CRT, then that DLL has its// own registry, defined in the statically-linked VCStartup library.//#include <corecrt_internal.h>
// The global atexit and at_quick_exit registriesextern "C" { _onexit_table_t __acrt_atexit_table{}; }extern "C" { _onexit_table_t __acrt_at_quick_exit_table{}; }
enum : size_t{ initial_table_count = 32, minimum_table_increment = 4, maximum_table_increment = 512};
// Registers a function to be executed on exit. This function modifies the global// onexit table.extern "C" int __cdecl _crt_atexit(_PVFV const function){ return _register_onexit_function(&__acrt_atexit_table, reinterpret_cast<_onexit_t>(function));}
extern "C" int __cdecl _crt_at_quick_exit(_PVFV const function){ return _register_onexit_function(&__acrt_at_quick_exit_table, reinterpret_cast<_onexit_t>(function));}
extern "C" int __cdecl _initialize_onexit_table(_onexit_table_t* const table){ if (!table) { return -1; }
// If the table has already been initialized, do not do anything. Note that // this handles both the case where the table was value initialized and where // the table was initialized with encoded null pointers. if (table->_first != table->_end) { return 0; }
_PVFV* const encoded_nullptr = __crt_fast_encode_pointer(nullptr);
table->_first = encoded_nullptr; table->_last = encoded_nullptr; table->_end = encoded_nullptr;
return 0;}
// Appends the given 'function' to the given onexit 'table'. Returns 0 on// success; returns -1 on failure. In general, failures are considered fatal// in calling code.extern "C" int __cdecl _register_onexit_function(_onexit_table_t* const table, _onexit_t const function){ return __acrt_lock_and_call(__acrt_select_exit_lock(), [&] { if (!table) { return -1; }
_PVFV* first = __crt_fast_decode_pointer(table->_first); _PVFV* last = __crt_fast_decode_pointer(table->_last); _PVFV* end = __crt_fast_decode_pointer(table->_end);
// If there is no room for the new entry, reallocate a larger table: if (last == end) { size_t const old_count = end - first;
size_t const increment = old_count > maximum_table_increment ? maximum_table_increment : old_count;
// First, try to double the capacity of the table: size_t new_count = old_count + increment; if (new_count == 0) { new_count = initial_table_count; }
_PVFV* new_first = nullptr; if (new_count >= old_count) { new_first = _recalloc_crt_t(_PVFV, first, new_count).detach(); }
// If that didn't work, try to allocate a smaller increment: if (new_first == nullptr) { new_count = old_count + minimum_table_increment; new_first = _recalloc_crt_t(_PVFV, first, new_count).detach(); }
if (new_first == nullptr) { return -1; }
first = new_first; last = new_first + old_count; end = new_first + new_count;
// The "additional" storage obtained from recalloc is sero-initialized. // The array holds encoded function pointers, so we need to fill the // storage with encoded nullptrs: _PVFV const encoded_nullptr = __crt_fast_encode_pointer(nullptr); for (auto it = last; it != end; ++it) { *it = encoded_nullptr; } }
*last++ = reinterpret_cast<_PVFV>(__crt_fast_encode_pointer(function));
table->_first = __crt_fast_encode_pointer(first); table->_last = __crt_fast_encode_pointer(last); table->_end = __crt_fast_encode_pointer(end);
return 0; });}
// This function executes a table of _onexit()/atexit() functions. The// terminators are executed in reverse order, to give the required LIFO// execution order. If the table is uninitialized, this function has no// effect. After executing the terminators, this function resets the table// so that it is uninitialized. Returns 0 on success; -1 on failure.extern "C" int __cdecl _execute_onexit_table(_onexit_table_t* const table){ return __acrt_lock_and_call(__acrt_select_exit_lock(), [&] { if (!table) { return -1; }
_PVFV* first = __crt_fast_decode_pointer(table->_first); _PVFV* last = __crt_fast_decode_pointer(table->_last); if (!first || first == reinterpret_cast<_PVFV*>(-1)) { return 0; }
// This loop calls through caller-provided function pointers. We must // save and reset the global state mode before calling them, to maintain // proper mode nesting. (These calls to caller-provided function pointers // are the only non-trivial calls, so we can do this once for the entire // loop.) { __crt_state_management::scoped_global_state_reset saved_state;
_PVFV const encoded_nullptr = __crt_fast_encode_pointer(nullptr);
_PVFV* saved_first = first; _PVFV* saved_last = last; for (;;) { // Find the last valid function pointer to call: while (--last >= first && *last == encoded_nullptr) { // Keep going backwards }
if (last < first) { // There are no more valid entries in the list; we are done: break; }
// Store the function pointer and mark it as visited in the list: _PVFV const function = __crt_fast_decode_pointer(*last); *last = encoded_nullptr;
function();
_PVFV* const new_first = __crt_fast_decode_pointer(table->_first); _PVFV* const new_last = __crt_fast_decode_pointer(table->_last);
// Reset iteration if either the begin or end pointer has changed: if (new_first != saved_first || new_last != saved_last) { first = saved_first = new_first; last = saved_last = new_last; } } }
if (first != reinterpret_cast<_PVFV*>(-1)) { _free_crt(first); }
_PVFV* const encoded_nullptr = __crt_fast_encode_pointer(nullptr);
table->_first = encoded_nullptr; table->_last = encoded_nullptr; table->_end = encoded_nullptr;
return 0; });}