#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <exception>
#include "unwind-cxx.h"
using namespace __cxxabiv1;
#define EMERGENCY_OBJ_SIZE 256
#define EMERGENCY_OBJ_COUNT 2
#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
typedef unsigned int bitmask_type;
#else
typedef unsigned long bitmask_type;
#endif
#ifndef NO_EMERGENCY_BUFFER
typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
static bitmask_type emergency_used;
#endif
namespace
{
pthread_mutex_t emergency_mutex = PTHREAD_MUTEX_INITIALIZER;
}
extern "C" void *
__cxxabiv1::__cxa_allocate_exception(size_t thrown_size) throw()
{
void *ret;
thrown_size += sizeof (__cxa_exception);
ret = malloc (thrown_size);
if (! ret)
{
#ifndef NO_EMERGENCY_BUFFER
pthread_mutex_lock(&emergency_mutex);
bitmask_type used = emergency_used;
unsigned int which = 0;
if (thrown_size > EMERGENCY_OBJ_SIZE)
goto failed;
while (used & 1)
{
used >>= 1;
if (++which >= EMERGENCY_OBJ_COUNT)
goto failed;
}
emergency_used |= (bitmask_type)1 << which;
ret = &emergency_buffer[which][0];
failed:;
pthread_mutex_unlock(&emergency_mutex);
#endif
if (!ret)
std::terminate ();
}
memset (ret, 0, sizeof (__cxa_exception));
return (void *)((char *)ret + sizeof (__cxa_exception));
}
extern "C" void
__cxxabiv1::__cxa_free_exception(void *vptr) throw()
{
char *ptr = (char *) vptr;
#ifndef NO_EMERGENCY_BUFFER
if (ptr >= &emergency_buffer[0][0]
&& ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer))
{
const unsigned int which
= (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE;
pthread_mutex_lock(&emergency_mutex);
emergency_used &= ~((bitmask_type)1 << which);
pthread_mutex_unlock(&emergency_mutex);
}
else
#endif
free (ptr - sizeof (__cxa_exception));
}
extern "C" void*
__cxxabiv1::__cxa_allocate_dependent_exception() throw()
{
size_t thrown_size = sizeof(__cxa_dependent_exception);
void* ret = ::malloc(thrown_size);
if (!ret)
{
#ifndef NO_EMERGENCY_BUFFER
pthread_mutex_lock(&emergency_mutex);
bitmask_type used = emergency_used;
unsigned int which = 0;
if (thrown_size > EMERGENCY_OBJ_SIZE)
goto failed;
while (used & 1)
{
used >>= 1;
if (++which >= EMERGENCY_OBJ_COUNT)
goto failed;
}
emergency_used |= (bitmask_type)1 << which;
ret = &emergency_buffer[which][0];
failed:
pthread_mutex_unlock(&emergency_mutex);
#endif
if (!ret)
std::terminate ();
}
::memset(ret, 0, thrown_size);
return ret;
}
extern "C" void
__cxxabiv1::__cxa_free_dependent_exception(void* vptr) throw()
{
char* ptr = (char*)vptr;
#ifndef NO_EMERGENCY_BUFFER
if (&emergency_buffer[0][0] <= ptr &&
ptr < &emergency_buffer[0][0] + sizeof(emergency_buffer))
{
const unsigned int which = (unsigned)(ptr - &emergency_buffer[0][0])
/ EMERGENCY_OBJ_SIZE;
pthread_mutex_lock(&emergency_mutex);
emergency_used &= ~((bitmask_type)1 << which);
pthread_mutex_unlock(&emergency_mutex);
}
else
#endif
::free(ptr);
}