You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1680 lines
50 KiB
1680 lines
50 KiB
/* /////////////////////////////////////////////////////////////////////////
|
|
* File: src/core/api.cpp
|
|
*
|
|
* Purpose: Implementation file for Pantheios core API.
|
|
*
|
|
* Created: 21st June 2005
|
|
* Updated: 7th August 2012
|
|
*
|
|
* Home: http://www.pantheios.org/
|
|
*
|
|
* Copyright (c) 2005-2012, Matthew Wilson and Synesis Software
|
|
* Copyright (c) 1999-2005, Synesis Software and Matthew Wilson
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* - Neither the name(s) of Matthew Wilson and Synesis Software nor the
|
|
* names of any contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
|
|
/* Pantheios header files
|
|
*
|
|
* NOTE: We do _not_ include pantheios/pantheios.hpp here, since we are
|
|
* not using any of the Application Layer.
|
|
*/
|
|
#include <pantheios/pantheios.h>
|
|
#include <pantheios/internal/lean.h>
|
|
#include <pantheios/internal/nox.h>
|
|
#include <pantheios/backend.h>
|
|
#include <pantheios/frontend.h>
|
|
|
|
#include <pantheios/init_codes.h>
|
|
#include <pantheios/quality/contract.h>
|
|
#include <pantheios/internal/safestr.h>
|
|
#ifndef UNIXSTL_NO_ATOMIC_INTEGER_OPERATIONS_ON_WINDOWS
|
|
# define UNIXSTL_NO_ATOMIC_INTEGER_OPERATIONS_ON_WINDOWS
|
|
#endif /* !UNIXSTL_NO_ATOMIC_INTEGER_OPERATIONS_ON_WINDOWS */
|
|
#include <pantheios/internal/threading.h>
|
|
#include <pantheios/util/string/snprintf.h>
|
|
#include <pantheios/util/string/strdup.h>
|
|
|
|
/* STLSoft header files */
|
|
|
|
#include <stlsoft/conversion/char_conversions.hpp>
|
|
#include <stlsoft/iterators/cstring_concatenator_iterator.hpp>
|
|
#include <stlsoft/iterators/member_selector_iterator.hpp>
|
|
#include <stlsoft/memory/allocator_selector.hpp>
|
|
#include <pantheios/util/memory/auto_buffer_selector.hpp>
|
|
#include <stlsoft/shims/access/string.hpp>
|
|
#include <stlsoft/smartptr/scoped_handle.hpp>
|
|
#include <stlsoft/synch/lock_scope.hpp>
|
|
|
|
#include <platformstl/platformstl.h>
|
|
#include <platformstl/synch/util/features.h>
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
# include <platformstl/synch/atomic_functions.h>
|
|
# include <platformstl/synch/spin_mutex.hpp>
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
#if defined(PANTHEIOS_MT) && \
|
|
!defined(PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS)
|
|
# include <platformstl/synch/thread_mutex.hpp>
|
|
#else /* ? PANTHEIOS_MT */
|
|
# include <stlsoft/synch/null_mutex.hpp>
|
|
#endif /* PANTHEIOS_MT */
|
|
|
|
/* Standard C++ header files */
|
|
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <new>
|
|
#include <numeric>
|
|
|
|
/* Standard C header files */
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_BORLAND)
|
|
# include <memory.h>
|
|
#endif /* compiler */
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/* Operating-system header files */
|
|
|
|
#ifdef PANTHEIOS_MT
|
|
# ifndef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
# if defined(PLATFORMSTL_OS_IS_UNIX)
|
|
# include <pthread.h>
|
|
# include <platformstl/synch/thread_mutex.hpp>
|
|
# endif /* OS */
|
|
# endif /* !PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
#endif /* PANTHEIOS_MT */
|
|
|
|
#if defined(PLATFORMSTL_OS_IS_UNIX)
|
|
# include <syslog.h>
|
|
#endif /* OS */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Features
|
|
*/
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
# undef PANTHEIOS_DEFINE_BACK_END_MAP /* Not yet released */
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Compiler compatibility
|
|
*/
|
|
|
|
#if ( defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER < 1200)
|
|
# define _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
#endif /* compiler */
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER < 1310
|
|
# define _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
#endif /* compiler */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Warning suppression
|
|
*/
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_BORLAND)
|
|
# pragma warn -8080
|
|
#endif /* compiler */
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER >= 1310
|
|
# pragma warning(disable : 4702) /* don't warn about unused catch blocks */
|
|
#endif /* compiler */
|
|
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
defined(PANTHEIOS_USING_SAFE_STR_FUNCTIONS)
|
|
/* Who would credit that I'd have to pull such a hack just to avoid
|
|
* being told that in using a standard function I'm using deprecated
|
|
* functionality. Deprecated by whom?
|
|
*/
|
|
namespace std
|
|
{
|
|
|
|
template< typename I
|
|
, typename O
|
|
>
|
|
inline O daft_msvc_copy_workaround_(I first, I last, O out)
|
|
{
|
|
for(; first != last; ++first, ++out)
|
|
{
|
|
*out = *first;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
}
|
|
|
|
# define copy daft_msvc_copy_workaround_
|
|
|
|
/* Also pulling the same trick for wcstombs
|
|
*/
|
|
|
|
namespace
|
|
{
|
|
|
|
size_t daft_msvc_wcstombs_workaround_(
|
|
char* s1
|
|
, const wchar_t* s2
|
|
, size_t n
|
|
)
|
|
{
|
|
# pragma warning(push)
|
|
# pragma warning(disable : 4996)
|
|
|
|
return ::wcstombs(s1, s2, n);
|
|
|
|
# pragma warning(pop)
|
|
}
|
|
}
|
|
|
|
# define wcstombs daft_msvc_wcstombs_workaround_
|
|
|
|
|
|
# include <stlsoft/algorithms/std/alt.hpp>
|
|
namespace std
|
|
{
|
|
using stlsoft::std_fill_n;
|
|
|
|
# define fill_n std_fill_n
|
|
|
|
} // namespace std
|
|
|
|
#endif /* STLSOFT_COMPILER_IS_MSVC && PANTHEIOS_USING_SAFE_STR_FUNCTIONS */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* String encoding compatibility
|
|
*/
|
|
|
|
#ifdef PANTHEIOS_USE_WIDE_STRINGS
|
|
|
|
# define pan_strlen_ wcslen
|
|
|
|
#else /* ? PANTHEIOS_USE_WIDE_STRINGS */
|
|
|
|
# define pan_strlen_ strlen
|
|
|
|
#endif /* PANTHEIOS_USE_WIDE_STRINGS */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Helper functions
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace pantheios
|
|
{
|
|
namespace ximpl_core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* To be declared in pantheios.core.h */
|
|
void pantheios_initPad_(void);
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace ximpl_core */
|
|
} /* namespace pantheios */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Typedefs
|
|
*/
|
|
|
|
#ifndef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
namespace pantheios_x
|
|
{
|
|
|
|
class thread_mutex_t
|
|
# ifdef PANTHEIOS_MT
|
|
: public platformstl::thread_mutex
|
|
# else /* ? PANTHEIOS_MT */
|
|
: public stlsoft::null_mutex
|
|
# endif /* PANTHEIOS_MT */
|
|
{
|
|
public: // Member types
|
|
# ifdef PANTHEIOS_MT
|
|
typedef platformstl::thread_mutex parent_class_type;
|
|
# else /* ? PANTHEIOS_MT */
|
|
typedef stlsoft::null_mutex parent_class_type;
|
|
# endif /* PANTHEIOS_MT */
|
|
public: // Construction
|
|
explicit thread_mutex_t(bool b)
|
|
# if defined(PANTHEIOS_MT) && \
|
|
defined(PLATFORMSTL_OS_IS_UNIX)
|
|
: parent_class_type(b)
|
|
# endif /* PANTHEIOS_MT && OS */
|
|
{
|
|
STLSOFT_SUPPRESS_UNUSED(b);
|
|
}
|
|
|
|
private:
|
|
thread_mutex_t(thread_mutex_t const&);
|
|
thread_mutex_t& operator =(thread_mutex_t const&);
|
|
};
|
|
|
|
} // namespace pantheios_x
|
|
|
|
namespace stlsoft
|
|
{
|
|
inline void lock_instance(::pantheios_x::thread_mutex_t& mx)
|
|
{
|
|
::stlsoft::lock_instance(static_cast< ::pantheios_x::thread_mutex_t::parent_class_type&>(mx));
|
|
}
|
|
inline void unlock_instance(::pantheios_x::thread_mutex_t& mx)
|
|
{
|
|
::stlsoft::unlock_instance(static_cast< ::pantheios_x::thread_mutex_t::parent_class_type&>(mx));
|
|
}
|
|
|
|
} // namespace stlsoft
|
|
|
|
#endif /* !PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Namespace
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace pantheios
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Constants
|
|
*/
|
|
|
|
#ifndef PANTHEIOS_CORE_LOG_N_INTERNAL_BUFFER_SIZE
|
|
# define PANTHEIOS_CORE_LOG_N_INTERNAL_BUFFER_SIZE (2048)
|
|
#endif /* !PANTHEIOS_CORE_LOG_N_INTERNAL_BUFFER_SIZE */
|
|
|
|
#ifndef PANTHEIOS_CORE_LOGPRINTF_STACK_SIZE
|
|
# define PANTHEIOS_CORE_LOGPRINTF_STACK_SIZE (4096)
|
|
#endif /* !PANTHEIOS_CORE_LOG_BUFFER_SIZE */
|
|
|
|
#ifndef PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS
|
|
# define PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS (1000)
|
|
#else /* ? PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS */
|
|
# if PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS < (1000)
|
|
# error Compile-time customisations of pad length must define at least 1000 characters
|
|
# endif
|
|
#endif /* !PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS */
|
|
|
|
#ifndef PANTHEIOS_CORE_BACKENDID_BASE
|
|
# define PANTHEIOS_CORE_BACKENDID_BASE (1000)
|
|
#else /* ? PANTHEIOS_CORE_BACKENDID_BASE */
|
|
# if PANTHEIOS_CORE_BACKENDID_BASE < (1)
|
|
# error Compile-time customisations of backEndId base must be a +ve integer
|
|
# endif
|
|
#endif /* PANTHEIOS_CORE_BACKENDID_BASE */
|
|
|
|
#define PANTHEIOS_MAXIMUM_MAX_PROCESS_IDENTITY_LENGTH (1000)
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
namespace
|
|
{
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
const size_t LOG_STACK_BUFFER_SIZE = PANTHEIOS_CORE_LOG_N_INTERNAL_BUFFER_SIZE -1;
|
|
const size_t PRINTF_STACK_BUFFER_SIZE = PANTHEIOS_CORE_LOGPRINTF_STACK_SIZE - 1;
|
|
size_t const PAD_BUFFER_SIZE = PANTHEIOS_CORE_MINIMUM_PAD_CHARACTERS;
|
|
|
|
struct pantheios_log_n_buffer_size_constraint_
|
|
{
|
|
~pantheios_log_n_buffer_size_constraint_()
|
|
{
|
|
// The pantheios_log_n() internal buffer size must be between 1B and 1MB
|
|
STLSOFT_STATIC_ASSERT(LOG_STACK_BUFFER_SIZE >= 1);
|
|
STLSOFT_STATIC_ASSERT(LOG_STACK_BUFFER_SIZE <= 0x100000);
|
|
}
|
|
};
|
|
|
|
struct pantheios_logprintf_stack_size_constraint_
|
|
{
|
|
~pantheios_logprintf_stack_size_constraint_()
|
|
{
|
|
// The pantheios_log_n() internal buffer size must be between 64B and 1MB
|
|
STLSOFT_STATIC_ASSERT(PRINTF_STACK_BUFFER_SIZE >= 64);
|
|
STLSOFT_STATIC_ASSERT(PRINTF_STACK_BUFFER_SIZE < 0x100000);
|
|
}
|
|
};
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
} // anonymous namespace
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Statics
|
|
*/
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
namespace
|
|
{
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
|
|
#ifndef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
using pantheios_x::thread_mutex_t;
|
|
|
|
#endif /* !PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
// Forward declarations
|
|
class BackEndMap;
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// API initialisation control variables
|
|
|
|
// The API initialisation count
|
|
platformstl::sint32_t s_apiInit;
|
|
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
// The spin mutex used to guard the API init count
|
|
//
|
|
// See section 10.2.2 of Imperfect C++ (http://imperfectcplusplus.com/)
|
|
//
|
|
// When using spin-mutexes, the API initialisation itself can be
|
|
// safely invoked by multiple concurrently contending threads.
|
|
platformstl::spin_mutex::atomic_int_type s_mx;
|
|
|
|
// The spin mutex used to guard the memory pool allocation list
|
|
platformstl::spin_mutex::atomic_int_type s_mxMem;
|
|
|
|
#else /* ? PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
// When the architecture does not support atomic integer
|
|
// operations, we have to use a bona-fide mutex. Naturally,
|
|
// the question is how to ensure that the mutex itself is
|
|
// (un)initialised.
|
|
//
|
|
// When not using spin-mutexes, the API initialisation itself cannot
|
|
// be safely invoked by multiple concurrently contending threads.
|
|
// Only a single thread can be allowed (by the user) to invoke
|
|
// application initialisation (via pantheios_init()) for the first
|
|
// time. Any number of subsequent initialisation attempts (calls to
|
|
// pantheios_init()) may then be allowed.
|
|
//
|
|
|
|
// A pointer to the API mutex instance. Also serves as a Boolean
|
|
// indicator as to whether the API is initialised.
|
|
thread_mutex_t* s_pmxApi = NULL;
|
|
|
|
// A pointer to the back-end Id mutex instance
|
|
thread_mutex_t* s_pmxBEI = NULL;
|
|
|
|
// A pointer to the memory pool mutex instance
|
|
thread_mutex_t* s_pmxMem = NULL;
|
|
|
|
// Memory used for the mutexes
|
|
union mx_union_t
|
|
{
|
|
long l;
|
|
double d;
|
|
long double ld;
|
|
stlsoft::byte_t bytes[sizeof(thread_mutex_t)];
|
|
|
|
} s_mx1_
|
|
, s_mx2_
|
|
, s_mx3_;
|
|
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
// The value of the first API initialisation return
|
|
int s_init = 0;
|
|
|
|
// A Boolean that indicates whether the application is
|
|
// currently undergoing its (first) initialisation.
|
|
int s_isInitialising = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// X
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
BackEndMap* s_backEndMap = NULL;
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// API context variables
|
|
|
|
// The memory pool
|
|
struct memory_pool_entry_t;
|
|
struct memory_pool_entry_t
|
|
{
|
|
public:
|
|
memory_pool_entry_t* next;
|
|
size_t cbEntry;
|
|
long double padding;
|
|
stlsoft::byte_t bytes[1];
|
|
|
|
private:
|
|
static
|
|
size_t
|
|
round_up_(
|
|
size_t n
|
|
)
|
|
{
|
|
return (n + 15) & ~(15);
|
|
}
|
|
|
|
public:
|
|
static
|
|
memory_pool_entry_t*
|
|
alloc(
|
|
size_t cb
|
|
, memory_pool_entry_t* next
|
|
)
|
|
{
|
|
size_t cbActual = offsetof(memory_pool_entry_t, bytes) + cb;
|
|
|
|
cbActual = round_up_(cbActual);
|
|
|
|
#if defined(_DEBUG) && \
|
|
defined(PLATFORMSTL_OS_IS_WINDOWS)
|
|
memory_pool_entry_t* entry = static_cast<memory_pool_entry_t*>(::HeapAlloc(::GetProcessHeap(), 0, cbActual));
|
|
#else /* ? VC++ _DEBUG */
|
|
memory_pool_entry_t* entry = static_cast<memory_pool_entry_t*>(::malloc(cbActual));
|
|
#endif /* VC++ _DEBUG */
|
|
|
|
if(NULL != entry)
|
|
{
|
|
entry->next = next;
|
|
entry->cbEntry = cb;
|
|
|
|
::memset(&entry->bytes[0], 0, cb);
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
static
|
|
void
|
|
free(void* pv)
|
|
{
|
|
#if defined(_DEBUG) && \
|
|
defined(PLATFORMSTL_OS_IS_WINDOWS)
|
|
::HeapFree(::GetProcessHeap(), 0, pv);
|
|
#else /* ? VC++ _DEBUG */
|
|
::free(pv);
|
|
#endif /* VC++ _DEBUG */
|
|
}
|
|
|
|
static
|
|
void
|
|
deallocate(
|
|
memory_pool_entry_t* head
|
|
)
|
|
{
|
|
{ for(memory_pool_entry_t* entry = head; NULL != entry; )
|
|
{
|
|
void* pv = entry;
|
|
|
|
entry = entry->next;
|
|
|
|
memory_pool_entry_t::free(pv);
|
|
}}
|
|
}
|
|
};
|
|
memory_pool_entry_t* s_memPoolHead = NULL;
|
|
|
|
// The front-end initialisation token
|
|
void* s_feToken = NULL;
|
|
|
|
// The back-end initialisation token
|
|
void* s_beToken = NULL;
|
|
|
|
// Process identity (1.0.1 b214+)
|
|
//
|
|
// If this is NULL, then the front-end indicated has its dynamic nature
|
|
// by returning NULL for the first call of
|
|
// pantheios_fe_getProcessIdentity(), and will be called each time
|
|
// process identity is required; otherwise, it's (assumed to be) a
|
|
// "classic" front-end, and the value has been cached by this
|
|
// variable.
|
|
pan_char_t* s_internalProcessIdentity = NULL;
|
|
|
|
// The padding characters
|
|
pan_char_t s_padCharacters[PAD_BUFFER_SIZE + 1u];
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
} // anonymous namespace
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Core functions
|
|
*/
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
namespace
|
|
{
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
using ximpl_core::pantheios_initPad_;
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
using pantheios::util::pantheios_onBailOut3;
|
|
using pantheios::util::pantheios_onBailOut4;
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
|
|
class BackEndMap
|
|
{
|
|
public:
|
|
typedef BackEndMap class_type;
|
|
|
|
public:
|
|
BackEndMap();
|
|
|
|
public:
|
|
int lookup(int backEndId, void** ptoken) const;
|
|
int add(int backEndId, void* token);
|
|
int remove(int backEndId);
|
|
|
|
private:
|
|
typedef std::map<int, void*> map_type_;
|
|
|
|
thread_mutex_t m_mx;
|
|
map_type_ m_map;
|
|
|
|
private:
|
|
BackEndMap(class_type const&);
|
|
class_type& operator =(class_type const&);
|
|
};
|
|
|
|
int pantheios_init_backEndMap()
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL == s_backEndMap, "Should not be called if back-end map already created");
|
|
|
|
# ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
try
|
|
{
|
|
# endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
s_backEndMap = new BackEndMap();
|
|
|
|
if(NULL == s_backEndMap)
|
|
{
|
|
return PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
}
|
|
catch(std::bad_alloc&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
catch(std::exception&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE;
|
|
}
|
|
catch(...)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNKNOWN_FAILURE;
|
|
}
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
return 0;
|
|
}
|
|
|
|
void pantheios_uninit_backEndMap()
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_backEndMap, "Should not be called if no back-end map");
|
|
|
|
delete s_backEndMap;
|
|
|
|
s_backEndMap = NULL;
|
|
}
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
int pantheios_init_onetime()
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(!s_isInitialising, "initialisation already in progress");
|
|
|
|
s_isInitialising = 1;
|
|
|
|
// 0. Initialise the Pantheios memory pool
|
|
|
|
// Nothing to do; the head pointer is set to NULL during static initialisation
|
|
|
|
|
|
// fill all the pad characters
|
|
pantheios_initPad_();
|
|
|
|
// TODO: do a table of APIs in Pan core init (somewhat like !(C ^ C++))
|
|
|
|
// 1. Initialise front-end
|
|
|
|
int r = pantheios_fe_init(0, &s_feToken);
|
|
|
|
if(r < 0)
|
|
{
|
|
pantheios_onBailOut4(PANTHEIOS_SEV_ALERT, "front-end did not initialise", NULL, pantheios_getInitCodeString(r));
|
|
}
|
|
else
|
|
{
|
|
// TODO: Mechanism to allow a measure of dynamism in
|
|
// pantheios_fe_getProcessIdentity() without breaking existing
|
|
// existing front-ends (or back-ends):
|
|
//
|
|
// 1. Current behaviour:
|
|
//
|
|
// pantheios_fe_getProcessIdentity() called at most once during
|
|
// startup; may be called multiple times by bailout calls
|
|
// return value may not be NULL
|
|
//
|
|
// 2. Want ability for following:
|
|
//
|
|
// a. Core store process identity, so can implement
|
|
// pantheios_getProcessIdentity()
|
|
// b. Dynamic process identity (calling
|
|
// pantheios_fe_getProcessIdentity() every time) when needed
|
|
// by back-end
|
|
//
|
|
// Solutions:
|
|
// ----------
|
|
//
|
|
// 2a can be handled, without breaking any existing
|
|
// front/back-ends, by having core take copy and use that
|
|
// henceforth
|
|
// 2b requires front-ends to return NULL on the FIRST CALL ONLY,
|
|
// the core take note of this, pass this on to the back-end
|
|
// initialisation, and then all subsequent calls to
|
|
// pantheios_getProcessIdentity() and within all back-ends
|
|
// would call pantheios_fe_getProcessIdentity() every time.
|
|
|
|
bool requirePICopy = false;
|
|
PAN_CHAR_T const* processIdentity = pantheios_fe_getProcessIdentity(s_feToken);
|
|
|
|
if(NULL == processIdentity)
|
|
{
|
|
// Now, according to protocol, we call a second time, and
|
|
// expect to receive a non-NULL pointer to string.
|
|
|
|
processIdentity = pantheios_fe_getProcessIdentity(s_feToken);
|
|
}
|
|
else
|
|
{
|
|
// We're dealing with a "classic" front-end - one that does
|
|
// not expect repeated calls and which, presumably, always
|
|
// returns the same string - so we indicate this by setting
|
|
// requirePICopy
|
|
|
|
requirePICopy = true;
|
|
}
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_RETURN_API(NULL != processIdentity, "returned string from pantheios_fe_getProcessIdentity() must not be null");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_RETURN_API(pan_strlen_(processIdentity) <= PANTHEIOS_MAXIMUM_MAX_PROCESS_IDENTITY_LENGTH, "returned string from pantheios_fe_getProcessIdentity() must be no longer than 1000 characters");
|
|
|
|
if(requirePICopy)
|
|
{
|
|
s_internalProcessIdentity = pantheios_util_strdup_nothrow(processIdentity);
|
|
|
|
if(NULL == s_internalProcessIdentity)
|
|
{
|
|
r = PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
processIdentity = s_internalProcessIdentity;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_ASSUMPTION(NULL == s_internalProcessIdentity);
|
|
}
|
|
|
|
// Before we do the back-end initialisation, we need to get the
|
|
// process identity from the front-end and, if in widestring
|
|
// mode, convert it to multibyte in case we need to pass it to
|
|
// bail-out.
|
|
//
|
|
// Note: there is no failure response here, since we only use it
|
|
// in bail-out.
|
|
|
|
#ifdef PANTHEIOS_USE_WIDE_STRINGS
|
|
char processIdentity_[PANTHEIOS_MAXIMUM_MAX_PROCESS_IDENTITY_LENGTH + 1];
|
|
size_t const n = ::wcstombs(processIdentity_, processIdentity, STLSOFT_NUM_ELEMENTS(processIdentity_) - 1);
|
|
char const* processIdentity_m;
|
|
|
|
if(n < STLSOFT_NUM_ELEMENTS(processIdentity_))
|
|
{
|
|
processIdentity_[STLSOFT_NUM_ELEMENTS(processIdentity_) - 1] = '\0';
|
|
processIdentity_m = processIdentity_;
|
|
}
|
|
else
|
|
{
|
|
processIdentity_m = NULL;
|
|
}
|
|
|
|
# define pantheios_core_impl_getProcessIdentity_a() processIdentity_m
|
|
#else /* ? PANTHEIOS_USE_WIDE_STRINGS */
|
|
# define pantheios_core_impl_getProcessIdentity_a() processIdentity
|
|
#endif /* PANTHEIOS_USE_WIDE_STRINGS */
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
// 2. Initialise back-end map
|
|
|
|
r = pantheios_init_backEndMap();
|
|
|
|
if(r < 0)
|
|
{
|
|
pantheios_onBailOut4(PANTHEIOS_SEV_ALERT, "back-end map creation failed", pantheios_core_impl_getProcessIdentity_a(), pantheios_getInitCodeString(r));
|
|
}
|
|
else
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
{
|
|
// 3. Initialise back-end
|
|
|
|
r = pantheios_be_init(processIdentity, 0, &s_beToken);
|
|
|
|
if(r < 0)
|
|
{
|
|
pantheios_onBailOut4(PANTHEIOS_SEV_ALERT, "back-end did not initialise", pantheios_core_impl_getProcessIdentity_a(), pantheios_getInitCodeString(r));
|
|
}
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
if(r < 0)
|
|
{
|
|
pantheios_uninit_backEndMap();
|
|
}
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
}
|
|
|
|
if(r < 0)
|
|
{
|
|
pantheios_fe_uninit(s_feToken);
|
|
s_feToken = NULL;
|
|
|
|
pantheios_util_strfree(s_internalProcessIdentity);
|
|
}
|
|
}
|
|
|
|
s_isInitialising = 0;
|
|
|
|
return r;
|
|
|
|
#undef pantheios_core_impl_getProcessIdentity_a
|
|
|
|
}
|
|
|
|
void pantheios_uninit_onetime()
|
|
{
|
|
// 3. Uninitialise back-end
|
|
pantheios_be_uninit(s_beToken);
|
|
s_beToken = NULL;
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
// 2. Uninitialise back-end map
|
|
pantheios_uninit_backEndMap();
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
// 1. Uninitialise front-end
|
|
pantheios_fe_uninit(s_feToken);
|
|
s_feToken = NULL;
|
|
|
|
pantheios_util_strfree(s_internalProcessIdentity);
|
|
s_internalProcessIdentity = NULL;
|
|
|
|
// 0. Deallocate all entries in memory pool
|
|
memory_pool_entry_t::deallocate(s_memPoolHead);
|
|
s_memPoolHead = NULL;
|
|
}
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
|
|
inline BackEndMap::BackEndMap()
|
|
{}
|
|
|
|
inline int BackEndMap::lookup(int backEndId, void** ptoken) const
|
|
{
|
|
stlsoft::lock_scope<thread_mutex_t> lock(const_cast<class_type*>(this)->m_mx);
|
|
|
|
void* token_;
|
|
map_type_::const_iterator it = m_map.find(backEndId);
|
|
|
|
// Null Object (Variable) here, for ptoken;
|
|
if(NULL == ptoken)
|
|
{
|
|
ptoken = &token_;
|
|
}
|
|
|
|
return (m_map.end() == it) ? 0 : (*ptoken = (*it).second, 1);
|
|
}
|
|
|
|
inline int BackEndMap::add(int backEndId, void* token)
|
|
{
|
|
stlsoft::lock_scope<thread_mutex_t> lock(m_mx);
|
|
|
|
# ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
try
|
|
{
|
|
# endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
if(m_map.find(backEndId) != m_map.end())
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// We *never* use operator [] (and no-one in their
|
|
// right mind should!)
|
|
|
|
m_map.insert(std::make_pair(backEndId, token));
|
|
}
|
|
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
}
|
|
catch(std::bad_alloc&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
catch(std::exception&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_EXCEPTION;
|
|
}
|
|
catch(...)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNKNOWN_FAILURE;
|
|
}
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
return 0;
|
|
}
|
|
|
|
inline int BackEndMap::remove(int backEndId)
|
|
{
|
|
stlsoft::lock_scope<thread_mutex_t> lock(m_mx);
|
|
|
|
return m_map.erase(backEndId) > 0;
|
|
}
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
#ifndef _PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES
|
|
} // anonymous namespace
|
|
#endif /* !_PANTHEIOS_COMPILER_CANNOT_USE_ANONYMOUS_NAMESPACES */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Core API
|
|
*
|
|
* Note: for those compilers that object to instantiating templates within
|
|
* extern "C" functions, the actual functions and their implementations are
|
|
* separated by the use of intermediary extern "C++" forms. For example,
|
|
* pantheios_init() is implemented in terms of pantheios_init__cpp(). For
|
|
* compilers that do not have such a problem, the intermediary forms are not
|
|
* used
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* Defined here, for the moment, as not currently declared in pantheios.h */
|
|
PANTHEIOS_CALL(int) pantheios_dispatch(
|
|
pan_sev_t severity
|
|
, size_t cchEntry
|
|
, pan_char_t const* entry
|
|
);
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
extern "C++" pan_uint32_t pantheios_getVersion__cpp();
|
|
extern "C++" int pantheios_init__cpp();
|
|
extern "C++" void pantheios_uninit__cpp();
|
|
extern "C++" int pantheios_isSeverityLogged__cpp(
|
|
pan_sev_t severity
|
|
);
|
|
extern "C++" pan_char_t const* pantheios_getProcessIdentity__cpp();
|
|
extern "C++" int pantheios_dispatch__cpp(
|
|
pan_sev_t severity
|
|
, size_t cchEntry
|
|
, pan_char_t const* entry
|
|
);
|
|
extern "C++" int pantheios_log_n__cpp(
|
|
pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices
|
|
);
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
|
|
|
|
PANTHEIOS_CALL(pan_uint32_t) pantheios_getVersion()
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_getVersion__cpp();
|
|
}
|
|
pan_uint32_t pantheios_getVersion__cpp()
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
return PANTHEIOS_VER;
|
|
}
|
|
|
|
/* Core initialisation function */
|
|
PANTHEIOS_CALL(int) pantheios_init()
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_init__cpp();
|
|
}
|
|
int pantheios_init__cpp()
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
// If we can make the initialisation thread-safe, without
|
|
// expense, then we do so.
|
|
platformstl::spin_mutex mx(&s_mx);
|
|
stlsoft::lock_scope<platformstl::spin_mutex> lock(mx);
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_ASSUMPTION(!s_isInitialising);
|
|
|
|
if(1 == ++s_apiInit)
|
|
{
|
|
s_init = pantheios_init_onetime();
|
|
}
|
|
|
|
return s_init;
|
|
|
|
#else /* ? PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
if(NULL == s_pmxApi)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(0 == s_apiInit, "api initialisation must be 0");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL == s_pmxBEI, "back-end id mutex must be uninitialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL == s_pmxMem, "memory pool mutex must be uninitialised");
|
|
|
|
# ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
try
|
|
{
|
|
# endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
|
|
s_pmxApi = new(&s_mx1_.bytes[0]) thread_mutex_t(false);
|
|
|
|
if(NULL == s_pmxApi)
|
|
{
|
|
pantheios_onBailOut3(PANTHEIOS_SEV_ALERT, "failed to create Pantheios core API mutex", NULL);
|
|
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
s_pmxBEI = new(&s_mx2_.bytes[0]) thread_mutex_t(false);
|
|
|
|
if(NULL == s_pmxBEI)
|
|
{
|
|
pantheios_onBailOut3(PANTHEIOS_SEV_ALERT, "failed to create back-end Id mutex", NULL);
|
|
|
|
s_pmxApi->~thread_mutex_t();
|
|
s_pmxApi = NULL;
|
|
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
s_pmxMem = new(&s_mx3_.bytes[0]) thread_mutex_t(false);
|
|
|
|
if(NULL == s_pmxMem)
|
|
{
|
|
pantheios_onBailOut3(PANTHEIOS_SEV_ALERT, "failed to create memory pool mutex", NULL);
|
|
|
|
s_pmxApi->~thread_mutex_t();
|
|
s_pmxApi = NULL;
|
|
|
|
s_pmxBEI->~thread_mutex_t();
|
|
s_pmxBEI = NULL;
|
|
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
stlsoft::lock_scope<thread_mutex_t> lock(*s_pmxApi);
|
|
|
|
s_init = pantheios_init_onetime();
|
|
|
|
if(s_init < 0)
|
|
{
|
|
s_pmxApi->~thread_mutex_t();
|
|
s_pmxApi = NULL;
|
|
|
|
s_pmxBEI->~thread_mutex_t();
|
|
s_pmxBEI = NULL;
|
|
|
|
s_pmxMem->~thread_mutex_t();
|
|
s_pmxMem = NULL;
|
|
|
|
return s_init;
|
|
}
|
|
|
|
++s_apiInit;
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(1 == s_apiInit, "api initialisation must be counted");
|
|
|
|
return s_init;
|
|
}
|
|
}
|
|
}
|
|
|
|
# ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
}
|
|
catch(...)
|
|
{
|
|
pantheios_onBailOut3(PANTHEIOS_SEV_ALERT, "exception occurred when creating Pantheios mutexes", NULL);
|
|
|
|
if(NULL != s_pmxApi)
|
|
{
|
|
s_pmxApi->~thread_mutex_t();
|
|
s_pmxApi = NULL;
|
|
}
|
|
|
|
if(NULL != s_pmxBEI)
|
|
{
|
|
s_pmxBEI->~thread_mutex_t();
|
|
s_pmxBEI = NULL;
|
|
}
|
|
|
|
if(NULL != s_pmxMem)
|
|
{
|
|
s_pmxMem->~thread_mutex_t();
|
|
s_pmxMem = NULL;
|
|
}
|
|
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE;
|
|
}
|
|
# endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
}
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL != s_pmxApi, "api mutex must be initialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL != s_pmxBEI, "back-end id mutex must be initialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL != s_pmxMem, "memory pool mutex must be initialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(0 != s_apiInit, "api initialisation must be counted");
|
|
|
|
stlsoft::lock_scope<thread_mutex_t> lock(*s_pmxApi);
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(0 != s_apiInit, "api initialisation must be counted");
|
|
|
|
++s_apiInit;
|
|
|
|
return s_init;
|
|
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
}
|
|
|
|
/* Core uninitialisation function */
|
|
PANTHEIOS_CALL(void) pantheios_uninit()
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
pantheios_uninit__cpp();
|
|
}
|
|
void pantheios_uninit__cpp()
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
// If we can make the (un)initialisation thread-safe, without
|
|
// expense, then we do so.
|
|
platformstl::spin_mutex mx(&s_mx);
|
|
stlsoft::lock_scope<platformstl::spin_mutex> lock(mx);
|
|
|
|
if(0 == --s_apiInit)
|
|
{
|
|
pantheios_uninit_onetime();
|
|
}
|
|
|
|
#else /* ? PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
bool bLast = false;
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_pmxApi, "api mutex must be initialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(0 != s_apiInit, "api initialisation must be counted");
|
|
|
|
{ stlsoft::lock_scope<thread_mutex_t> lock(*s_pmxApi);
|
|
|
|
if(0 == --s_apiInit)
|
|
{
|
|
bLast = true;
|
|
}
|
|
}
|
|
|
|
if(bLast)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(0 == s_apiInit, "api initialisation must be 0");
|
|
|
|
s_pmxApi->~thread_mutex_t();
|
|
s_pmxApi = NULL;
|
|
|
|
s_pmxBEI->~thread_mutex_t();
|
|
s_pmxBEI = NULL;
|
|
|
|
s_pmxMem->~thread_mutex_t();
|
|
s_pmxMem = NULL;
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL == s_pmxApi, "api mutex must be uninitialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL == s_pmxBEI, "back-end id mutex must be uninitialised");
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_STATE_API(NULL == s_pmxMem, "thread pool mutex must be uninitialised");
|
|
|
|
pantheios_uninit_onetime();
|
|
}
|
|
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
}
|
|
|
|
|
|
/* Core severity test function */
|
|
PANTHEIOS_CALL(int) pantheios_isSeverityLogged(pan_sev_t severity)
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_isSeverityLogged__cpp(severity);
|
|
}
|
|
int pantheios_isSeverityLogged__cpp(pan_sev_t severity)
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
return pantheios_fe_isSeverityLogged(s_feToken, static_cast<int>(severity), 0);
|
|
}
|
|
|
|
/* Core-exposed process identity. */
|
|
PANTHEIOS_CALL(pan_char_t const*) pantheios_getProcessIdentity()
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_getProcessIdentity__cpp();
|
|
}
|
|
int pantheios_getProcessIdentity__cpp()
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
if(NULL != s_internalProcessIdentity)
|
|
{
|
|
// use cached
|
|
|
|
return s_internalProcessIdentity;
|
|
}
|
|
else
|
|
{
|
|
return pantheios_fe_getProcessIdentity(s_feToken);
|
|
}
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* Core diagnostic logging functions */
|
|
|
|
/* dispatching for *all* diagnostic logging functions */
|
|
PANTHEIOS_CALL(int) pantheios_dispatch(
|
|
pan_sev_t severity
|
|
, size_t cchEntry
|
|
, pan_char_t const* entry
|
|
)
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_dispatch__cpp(severity, numSlices, slices);
|
|
}
|
|
int pantheios_dispatch__cpp(
|
|
pan_sev_t severity
|
|
, size_t cchEntry
|
|
, pan_char_t const* entry
|
|
)
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_PARAMS_INTERNAL(NULL != entry, "entry may not be null");
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_PARAMS_INTERNAL('\0' == entry[cchEntry], "entry must be nul-terminated, and equal the given length");
|
|
|
|
return pantheios_be_logEntry(s_feToken, s_beToken, severity, entry, cchEntry);
|
|
}
|
|
|
|
/* assembler for all log_???? functions */
|
|
PANTHEIOS_CALL(int) pantheios_log_n( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
#ifdef _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS
|
|
{
|
|
return pantheios_log_n__cpp(severity, numSlices, slices);
|
|
}
|
|
int pantheios_log_n__cpp( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
#endif /* _PANTHEIOS_COMPILER_REQUIRES_EXTERNCPP_DEFINITIONS */
|
|
{
|
|
// Precondition check
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API((NULL != slices || 0 == numSlices), "slices may only be null if the number of slices is zero");
|
|
|
|
#if defined(PANTHEIOS_NO_NAMESPACE)
|
|
typedef auto_buffer_selector<
|
|
#else /* ? PANTHEIOS_NO_NAMESPACE */
|
|
typedef ::pantheios::util::auto_buffer_selector<
|
|
#endif /* PANTHEIOS_NO_NAMESPACE */
|
|
pan_char_t
|
|
, 1 + LOG_STACK_BUFFER_SIZE
|
|
>::type buffer_t;
|
|
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
try
|
|
{
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
// Calculate the total size of the log statement, by summation of the slice array
|
|
|
|
#if !defined(STLSOFT_COMPILER_IS_BORLAND)
|
|
|
|
// The sophisticated way
|
|
const size_t n = std::accumulate(stlsoft::member_selector(slices, &pan_slice_t::len)
|
|
, stlsoft::member_selector(slices + numSlices, &pan_slice_t::len)
|
|
, size_t(0));
|
|
|
|
#else /* ? compiler */
|
|
|
|
// The crappy way, for less-than compilers
|
|
size_t n = 0;
|
|
|
|
{ for(size_t i = 0; i != numSlices; ++i)
|
|
{
|
|
n += slices[i].len;
|
|
}}
|
|
|
|
#endif /* compiler */
|
|
|
|
buffer_t buffer(1 + n);
|
|
size_t nWritten = 0;
|
|
|
|
// We do a check here, so as to cater for cases where the allocator does not
|
|
// throw bad_alloc.
|
|
if(0 == buffer.size())
|
|
{
|
|
return PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
std::copy( slices
|
|
, slices + numSlices
|
|
, stlsoft::cstring_concatenator(&buffer[0], &nWritten));
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_POSTCONDITION_RETURN_INTERNAL(nWritten == n, "Written length differs from allocated length");
|
|
|
|
buffer[n] = '\0';
|
|
|
|
return pantheios_dispatch(static_cast<int>(severity), n, &buffer[0]);
|
|
}
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
}
|
|
catch(std::bad_alloc&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_OUT_OF_MEMORY;
|
|
}
|
|
catch(std::exception&)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNSPECIFIED_EXCEPTION;
|
|
}
|
|
catch(...)
|
|
{
|
|
return PANTHEIOS_INIT_RC_UNKNOWN_FAILURE;
|
|
}
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
#if 1 && \
|
|
( !defined(STLSOFT_COMPILER_IS_BORLAND) || \
|
|
__BORLANDC__ < 0x0560) && \
|
|
!defined(STLSOFT_COMPILER_IS_COMO) && \
|
|
( !defined(STLSOFT_COMPILER_IS_MSVC) || \
|
|
_MSC_VER < 1300) && \
|
|
( !defined(STLSOFT_COMPILER_IS_INTEL) || \
|
|
__INTEL_COMPILER < 1200) && \
|
|
1
|
|
return 0;
|
|
#endif /* compiler */
|
|
}
|
|
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* printf() functions
|
|
*/
|
|
|
|
PANTHEIOS_CALL(int)
|
|
pantheios_logvprintf(
|
|
pan_sev_t severity
|
|
, pan_char_t const* format
|
|
, va_list args
|
|
)
|
|
{
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
using pantheios::core::pantheios_dispatch;
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
if(pantheios_isSeverityLogged(severity))
|
|
{
|
|
/* The standard requires that the return value is either:
|
|
*
|
|
* - the number of characters written, if that is < cch
|
|
* - the number of characters that would have been written, if >= cch
|
|
* - a negative value if an error occurs
|
|
*
|
|
* However, some implementations return a negative value in the
|
|
* second case. Consequently, the following code has to be a little
|
|
* bit more intelligent:
|
|
*
|
|
* - write a leading '\0' before calling vsnprintf
|
|
* - write a trailing '\0' after calling vsnprintf
|
|
*/
|
|
pan_char_t sz[PRINTF_STACK_BUFFER_SIZE + 1] = { '\0' };
|
|
int cch = pantheios_util_vsnprintf(&sz[0], STLSOFT_NUM_ELEMENTS(sz) - 1, format, args);
|
|
|
|
sz[STLSOFT_NUM_ELEMENTS(sz) - 1] = '\0';
|
|
|
|
if(cch < 0)
|
|
{
|
|
cch = static_cast<int>(pan_strlen_(sz));
|
|
}
|
|
else if(cch >= int(STLSOFT_NUM_ELEMENTS(sz) - 1))
|
|
{
|
|
cch = STLSOFT_NUM_ELEMENTS(sz) - 1;
|
|
}
|
|
|
|
return pantheios_dispatch(severity, static_cast<size_t>(cch), &sz[0]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Core functions
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
|
|
PANTHEIOS_CALL(int) pantheios_isInitialising(void)
|
|
{
|
|
return s_isInitialising;
|
|
}
|
|
|
|
PANTHEIOS_CALL(int) pantheios_isInitialised(void)
|
|
{
|
|
return 0 != s_apiInit;
|
|
}
|
|
|
|
PANTHEIOS_CALL(int) pantheios_getNextBackEndId(void)
|
|
{
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
static platformstl::atomic_int_t s_nextId = PANTHEIOS_CORE_BACKENDID_BASE;
|
|
|
|
return static_cast<int>(platformstl::atomic_preincrement(&s_nextId));
|
|
|
|
#else /* ? PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
static int s_nextId = PANTHEIOS_CORE_BACKENDID_BASE;
|
|
|
|
stlsoft::lock_scope<thread_mutex_t> lock(*s_pmxBEI);
|
|
|
|
return ++s_nextId;
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
PANTHEIOS_CALL(void)
|
|
pantheios_logassertfail(
|
|
pan_sev_t severity
|
|
, char const* fileLine
|
|
, char const* message
|
|
)
|
|
{
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
using pantheios::core::pantheios_dispatch;
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
if(pantheios_isSeverityLogged(severity))
|
|
{
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
try
|
|
{
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
# if defined(PANTHEIOS_NO_NAMESPACE)
|
|
typedef auto_buffer_selector<
|
|
# else /* ? PANTHEIOS_NO_NAMESPACE */
|
|
typedef ::pantheios::util::auto_buffer_selector<
|
|
# endif /* PANTHEIOS_NO_NAMESPACE */
|
|
char
|
|
, 1 + LOG_STACK_BUFFER_SIZE
|
|
>::type buffer_t;
|
|
|
|
size_t const cchFileLine = stlsoft::c_str_len(fileLine);
|
|
size_t const cchMessage = stlsoft::c_str_len(message);
|
|
buffer_t buff(1 + cchFileLine + cchMessage);
|
|
|
|
if(buff.empty())
|
|
{
|
|
goto logassertfail_no_memory;
|
|
}
|
|
else
|
|
{
|
|
::memcpy(&buff[0] + 0u, fileLine, sizeof(char) * cchFileLine);
|
|
::memcpy(&buff[0] + cchFileLine, message, sizeof(char) * cchMessage);
|
|
buff[cchFileLine + cchMessage] = '\0';
|
|
|
|
#ifdef PANTHEIOS_USE_WIDE_STRINGS
|
|
|
|
stlsoft::m2w message2(buff.data(), cchFileLine + cchMessage);
|
|
|
|
pantheios_dispatch(severity, message2.size(), message2.data());
|
|
|
|
#else /* ? PANTHEIOS_USE_WIDE_STRINGS */
|
|
|
|
pantheios_dispatch(severity, cchFileLine + cchMessage, buff.data());
|
|
|
|
#endif /* PANTHEIOS_USE_WIDE_STRINGS */
|
|
}
|
|
|
|
#ifdef STLSOFT_CF_EXCEPTION_SUPPORT
|
|
}
|
|
catch(std::bad_alloc&)
|
|
{
|
|
goto logassertfail_no_memory;
|
|
}
|
|
catch(...)
|
|
{
|
|
pantheios_onBailOut4(PANTHEIOS_SEV_EMERGENCY, "assertion failed", NULL, NULL);
|
|
}
|
|
#endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
|
|
|
|
return;
|
|
|
|
logassertfail_no_memory:
|
|
|
|
pantheios_onBailOut4(PANTHEIOS_SEV_EMERGENCY, "out-of-memory condition occurred when reporting assertion failure at", NULL, fileLine);
|
|
}
|
|
}
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Memory functions
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
PANTHEIOS_CALL(void*) pantheios_malloc(size_t cb)
|
|
{
|
|
#ifdef PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS
|
|
|
|
platformstl::spin_mutex mx(&s_mxMem);
|
|
stlsoft::lock_scope<platformstl::spin_mutex> lock(mx);
|
|
|
|
#else /* ? PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_pmxMem, "memory pool mutex must be initialised");
|
|
|
|
stlsoft::lock_scope<thread_mutex_t> lock(*s_pmxMem);
|
|
|
|
#endif /* PANTHEIOS_MT_HAS_ATOMIC_INTEGER_OPERATIONS */
|
|
|
|
memory_pool_entry_t* entry = memory_pool_entry_t::alloc(cb, s_memPoolHead);
|
|
|
|
if(NULL != entry)
|
|
{
|
|
s_memPoolHead = entry;
|
|
|
|
return &entry->bytes[0];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Inserter memory functions
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
PANTHEIOS_CALL(void*) pantheios_inserterAllocate(size_t cb)
|
|
{
|
|
return ::malloc(cb);
|
|
}
|
|
|
|
PANTHEIOS_CALL(void) pantheios_inserterDeallocate(void* pv)
|
|
{
|
|
::free(pv);
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Pad functions
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace ximpl_core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* To be declared in pantheios.core.h */
|
|
void pantheios_initPad_(void)
|
|
{
|
|
std::fill_n(s_padCharacters, STLSOFT_NUM_ELEMENTS(s_padCharacters) - 1u, ' ');
|
|
s_padCharacters[STLSOFT_NUM_ELEMENTS(s_padCharacters) - 1u] = '\0';
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace ximpl_core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
namespace core
|
|
{
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
PANTHEIOS_CALL(pan_char_t const*) pantheios_getPad(size_t minimumWidth, size_t* actualWidth)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != actualWidth, "pointer cannot be null");
|
|
|
|
if(minimumWidth > (STLSOFT_NUM_ELEMENTS(s_padCharacters) - 1u))
|
|
{
|
|
*actualWidth = (STLSOFT_NUM_ELEMENTS(s_padCharacters) - 1u);
|
|
}
|
|
else
|
|
{
|
|
*actualWidth = minimumWidth;
|
|
}
|
|
|
|
return s_padCharacters;
|
|
}
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace core */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Back-end map functions
|
|
*/
|
|
|
|
#ifdef PANTHEIOS_DEFINE_BACK_END_MAP
|
|
|
|
PANTHEIOS_CALL(int) pantheios_backEndMap_lookup(int backEndId, void** ptoken)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_backEndMap, "Cannot be called when Pantheios core is not initialised");
|
|
|
|
return s_backEndMap->lookup(backEndId, ptoken);
|
|
}
|
|
|
|
PANTHEIOS_CALL(int) pantheios_backEndMap_add(int backEndId, void* token)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_backEndMap, "Cannot be called when Pantheios core is not initialised");
|
|
|
|
return s_backEndMap->add(backEndId, token);
|
|
}
|
|
|
|
PANTHEIOS_CALL(int) pantheios_backEndMap_remove(int backEndId)
|
|
{
|
|
PANTHEIOS_CONTRACT_ENFORCE_PRECONDITION_STATE_API(NULL != s_backEndMap, "Cannot be called when Pantheios core is not initialised");
|
|
|
|
return s_backEndMap->remove(backEndId);
|
|
}
|
|
#endif /* PANTHEIOS_DEFINE_BACK_END_MAP */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Namespace
|
|
*/
|
|
|
|
#if !defined(PANTHEIOS_NO_NAMESPACE)
|
|
} /* namespace pantheios */
|
|
#endif /* !PANTHEIOS_NO_NAMESPACE */
|
|
|
|
/* ///////////////////////////// end of file //////////////////////////// */
|