reactos/sdk/lib/ucrt/internal/initialization.cpp

345 lines
9.9 KiB
C++

//
// initialization.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This file defines the main initialization and uninitialization routines for
// the AppCRT, shared by both the static and dynamic AppCRT libraries. In the
// dynamic AppCRT library, these are called by DllMain. In the static AppCRT
// library, these are called by the initialization code.
//
#include <corecrt_internal.h>
#include <corecrt_internal_stdio.h>
#include <stdlib.h>
#include <stdio.h>
extern "C" {
extern _onexit_table_t __acrt_atexit_table;
extern _onexit_table_t __acrt_at_quick_exit_table;
extern void* __acrt_stdout_buffer;
extern void* __acrt_stderr_buffer;
static bool __cdecl initialize_global_variables()
{
__acrt_current_locale_data.initialize(&__acrt_initial_locale_data);
return true;
}
#ifdef CRTDLL
static bool __cdecl initialize_c()
{
_initialize_onexit_table(&__acrt_atexit_table);
_initialize_onexit_table(&__acrt_at_quick_exit_table);
// Do C initialization:
if (_initterm_e(__xi_a, __xi_z) != 0)
{
return false;
}
// Do C++ initialization:
_initterm(__xc_a, __xc_z);
return true;
}
static bool __cdecl uninitialize_c(bool)
{
// Do pre-termination:
_initterm(__xp_a, __xp_z);
// Do termination:
_initterm(__xt_a, __xt_z);
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl initialize_environment()
{
if (_initialize_narrow_environment() < 0)
{
return false;
}
if (!_get_initial_narrow_environment())
{
return false;
}
return true;
}
#else
static bool __cdecl initialize_c()
{
_initialize_onexit_table(&__acrt_atexit_table);
_initialize_onexit_table(&__acrt_at_quick_exit_table);
return true;
}
static bool __cdecl uninitialize_c(bool)
{
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl initialize_environment()
{
return true;
}
#endif
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl uninitialize_environment(bool const terminating)
{
UNREFERENCED_PARAMETER(terminating);
#ifdef _DEBUG
if (terminating)
{
return true;
}
#endif
__dcrt_uninitialize_environments_nolock();
return true;
}
#ifdef _CRT_GLOBAL_STATE_ISOLATION
static bool __cdecl initialize_global_state_isolation()
{
// Configure CRT's per-thread global state mode data
return __crt_state_management::initialize_global_state_isolation();
}
static bool __cdecl uninitialize_global_state_isolation(bool const terminating)
{
// Configure CRT's per-thread global state mode data
__crt_state_management::uninitialize_global_state_isolation(terminating);
return true;
}
#else
static bool __cdecl initialize_global_state_isolation()
{
return true;
}
static bool __cdecl uninitialize_global_state_isolation(bool const /* terminating */)
{
return true;
}
#endif
static bool __cdecl initialize_pointers()
{
void* const encoded_null = __crt_fast_encode_pointer(nullptr);
__acrt_initialize_invalid_parameter_handler(encoded_null);
__acrt_initialize_new_handler(encoded_null);
__acrt_initialize_signal_handlers(encoded_null);
__acrt_initialize_user_matherr(encoded_null);
__acrt_initialize_thread_local_exit_callback(encoded_null);
return true;
}
static bool __cdecl uninitialize_vcruntime(const bool /* terminating */)
{
return __vcrt_uninitialize(false);
}
static bool __cdecl uninitialize_allocated_memory(bool const /* terminating */)
{
__acrt_current_multibyte_data.uninitialize([](__crt_multibyte_data*& multibyte_data)
{
if (_InterlockedDecrement(&multibyte_data->refcount) == 0 &&
multibyte_data != &__acrt_initial_multibyte_data)
{
_free_crt(multibyte_data);
multibyte_data = &__acrt_initial_multibyte_data;
}
});
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl uninitialize_allocated_io_buffers(bool const /* terminating */)
{
_free_crt(__acrt_stdout_buffer);
__acrt_stdout_buffer = nullptr;
_free_crt(__acrt_stderr_buffer);
__acrt_stderr_buffer = nullptr;
_free_crt(__argv);
__argv = nullptr;
_free_crt(__wargv);
__wargv = nullptr;
return true;
}
static bool __cdecl report_memory_leaks(bool const /* terminating */)
{
#ifdef _DEBUG
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
{
_CrtSetDumpClient(nullptr);
_CrtDumpMemoryLeaks();
}
#endif
return true;
}
// This is the table of initializer/uninitializer pairs that is used to perform
// AppCRT initialization. Initializers are run first-to-last during AppCRT
// initialization, and uninitializers are run last-to-first during termination.
static __acrt_initializer const __acrt_initializers[] =
{
// Init globals that can't be set at compile time because they have c'tors
{ initialize_global_variables, nullptr },
// Global pointers are stored in encoded form; they must be dynamically
// initialized to the encoded nullptr value before they are used by the CRT.
{ initialize_pointers, nullptr },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ __acrt_initialize_winapi_thunks, __acrt_uninitialize_winapi_thunks },
#endif
// Configure CRT's global state isolation system. This system calls FlsAlloc
// and thus must occur after the initialize_pointers initialization, otherwise
// it will fall back to call TlsAlloc, then try to use the allocated TLS slot
// with the FLS functions. This does not turn out well. By running this
// initialization after the initialize_pointers step, we ensure that it can
// call FlsAlloc.
{ initialize_global_state_isolation, uninitialize_global_state_isolation },
// The heap and locks must be initialized before most other initialization
// takes place, as other initialization steps rely on the heap and locks:
{ __acrt_initialize_locks, __acrt_uninitialize_locks },
{ __acrt_initialize_heap, __acrt_uninitialize_heap },
// During uninitialization, before the heap is uninitialized, the AppCRT
// needs to notify all VCRuntime instances in the process to allow them to
// release any memory that they allocated via the AppCRT heap.
//
// First, we notify all modules that registered for shutdown notification.
// This only occurs in the AppCRT DLL, because the static CRT is only ever
// used by a single module, so this notification is never required.
//
// Then, we notify our own VCRuntime instance. Note that after this point
// during uninitialization, no exception handling may take place in any
// CRT module.
{ nullptr, uninitialize_vcruntime },
{ __acrt_initialize_ptd, __acrt_uninitialize_ptd },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ __acrt_initialize_lowio, __acrt_uninitialize_lowio },
{ __acrt_initialize_command_line, __acrt_uninitialize_command_line },
#endif
{ __acrt_initialize_multibyte, nullptr },
{ nullptr, report_memory_leaks },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ nullptr, uninitialize_allocated_io_buffers },
#endif
{ nullptr, uninitialize_allocated_memory },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ initialize_environment, uninitialize_environment },
#endif
{ initialize_c, uninitialize_c },
};
__crt_bool __cdecl __acrt_initialize()
{
#if defined CRTDLL
__isa_available_init();
#endif
return __acrt_execute_initializers(
__acrt_initializers,
__acrt_initializers + _countof(__acrt_initializers)
);
}
__crt_bool __cdecl __acrt_uninitialize(__crt_bool const terminating)
{
UNREFERENCED_PARAMETER(terminating);
// If the process is terminating, there's no point in cleaning up, except
// in debug builds.
#ifndef _DEBUG
if (terminating) {
#ifndef _UCRT_ENCLAVE_BUILD
if (__acrt_stdio_is_initialized()) {
_flushall();
}
#endif
return TRUE;
}
#endif
return __acrt_execute_uninitializers(
__acrt_initializers,
__acrt_initializers + _countof(__acrt_initializers)
);
}
__crt_bool __cdecl __acrt_uninitialize_critical(__crt_bool const terminating)
{
__acrt_uninitialize_ptd(terminating);
#ifdef _CRT_GLOBAL_STATE_ISOLATION
uninitialize_global_state_isolation(terminating);
#endif
return true;
}
__crt_bool __cdecl __acrt_thread_attach()
{
// Create a per-thread data structure for this thread (getptd will attempt
// to create a new per-thread data structure if one does not already exist
// for this thread):
if (__acrt_getptd_noexit() == nullptr)
return false;
return true;
}
__crt_bool __cdecl __acrt_thread_detach()
{
// Free the per-thread data structure for this thread:
__acrt_freeptd();
return true;
}
}