swig/Lib/d/dhead.swg
David Nadlinger 278308cfd3 D: Fix exception handling support.
The original code was ported from the C# module. It looks like it
tried to avoid reading TLS data by using a shared counter. However,
without also synchronizing on the counter check (or using atomics)
the code is racy. While the races might be benign (the thread that
sets the exception also increments the counter, so when there is
actually an exception, the visible value will always be non-zero
even if it is outdated), they are still undefined behavior,
strictly speaking. Additionally, just using TLS isn't expensive
either.
2014-11-06 23:04:36 +01:00

298 lines
8.4 KiB
Text

/* -----------------------------------------------------------------------------
* dhead.swg
*
* Support code for exceptions if the SWIG_D_NO_EXCEPTION_HELPER is not defined
* Support code for strings if the SWIG_D_NO_STRING_HELPER is not defined
*
* Support code for function pointers. ----------------------------------------------------------------------------- */
%insert(runtime) %{
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Contract support. */
#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_DSetPendingException(SWIG_DException, msg); return nullreturn; } else
%}
/*
* Exception support code.
*/
#if !defined(SWIG_D_NO_EXCEPTION_HELPER)
%insert(runtime) %{
// Support for throwing D exceptions from C/C++.
typedef enum {
SWIG_DException = 0,
SWIG_DIllegalArgumentException,
SWIG_DIllegalElementException,
SWIG_DIOException,
SWIG_DNoSuchElementException,
} SWIG_DExceptionCodes;
typedef void (* SWIG_DExceptionCallback_t)(const char *);
typedef struct {
SWIG_DExceptionCodes code;
SWIG_DExceptionCallback_t callback;
} SWIG_DException_t;
static SWIG_DException_t SWIG_d_exceptions[] = {
{ SWIG_DException, NULL },
{ SWIG_DIllegalArgumentException, NULL },
{ SWIG_DIllegalElementException, NULL },
{ SWIG_DIOException, NULL },
{ SWIG_DNoSuchElementException, NULL }
};
static void SWIGUNUSED SWIG_DSetPendingException(SWIG_DExceptionCodes code, const char *msg) {
if ((size_t)code < sizeof(SWIG_d_exceptions)/sizeof(SWIG_DException_t)) {
SWIG_d_exceptions[code].callback(msg);
} else {
SWIG_d_exceptions[SWIG_DException].callback(msg);
}
}
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT void SWIGRegisterExceptionCallbacks_$module(
SWIG_DExceptionCallback_t exceptionCallback,
SWIG_DExceptionCallback_t illegalArgumentCallback,
SWIG_DExceptionCallback_t illegalElementCallback,
SWIG_DExceptionCallback_t ioCallback,
SWIG_DExceptionCallback_t noSuchElementCallback) {
SWIG_d_exceptions[SWIG_DException].callback = exceptionCallback;
SWIG_d_exceptions[SWIG_DIllegalArgumentException].callback = illegalArgumentCallback;
SWIG_d_exceptions[SWIG_DIllegalElementException].callback = illegalElementCallback;
SWIG_d_exceptions[SWIG_DIOException].callback = ioCallback;
SWIG_d_exceptions[SWIG_DNoSuchElementException].callback = noSuchElementCallback;
}
%}
#if (SWIG_D_VERSION == 1)
%pragma(d) imdmoduleimports=%{
// Exception throwing support currently requires Tango, but there is no reason
// why it could not support Phobos.
static import tango.core.Exception;
static import tango.core.Thread;
static import tango.stdc.stringz;
%}
%pragma(d) imdmodulecode=%{
private class SwigExceptionHelper {
static this() {
swigRegisterExceptionCallbacks$module(
&setException,
&setIllegalArgumentException,
&setIllegalElementException,
&setIOException,
&setNoSuchElementException);
}
static void setException(char* message) {
auto exception = new object.Exception(tango.stdc.stringz.fromStringz(message).dup);
SwigPendingException.set(exception);
}
static void setIllegalArgumentException(char* message) {
auto exception = new tango.core.Exception.IllegalArgumentException(tango.stdc.stringz.fromStringz(message).dup);
SwigPendingException.set(exception);
}
static void setIllegalElementException(char* message) {
auto exception = new tango.core.Exception.IllegalElementException(tango.stdc.stringz.fromStringz(message).dup);
SwigPendingException.set(exception);
}
static void setIOException(char* message) {
auto exception = new tango.core.Exception.IOException(tango.stdc.stringz.fromStringz(message).dup);
SwigPendingException.set(exception);
}
static void setNoSuchElementException(char* message) {
auto exception = new tango.core.Exception.NoSuchElementException(tango.stdc.stringz.fromStringz(message).dup);
SwigPendingException.set(exception);
}
}
package class SwigPendingException {
public:
static this() {
m_sPendingException = new ThreadLocalData(null);
}
static bool isPending() {
return m_sPendingException.val !is null;
}
static void set(object.Exception e) {
auto pending = m_sPendingException.val;
if (pending !is null) {
e.next = pending;
throw new object.Exception("FATAL: An earlier pending exception from C/C++ " ~
"code was missed and thus not thrown (" ~ pending.classinfo.name ~ ": " ~
pending.msg ~ ")!", e);
}
m_sPendingException.val = e;
}
static object.Exception retrieve() {
auto e = m_sPendingException.val;
m_sPendingException.val = null;
return e;
}
private:
// The reference to the pending exception (if any) is stored thread-local.
alias tango.core.Thread.ThreadLocal!(object.Exception) ThreadLocalData;
static ThreadLocalData m_sPendingException;
}
alias void function(char* message) SwigExceptionCallback;
%}
#else
%pragma(d) imdmoduleimports=%{
static import std.conv;
%}
%pragma(d) imdmodulecode=%{
private class SwigExceptionHelper {
static this() {
// The D1/Tango version maps C++ exceptions to multiple exception types.
swigRegisterExceptionCallbacks$module(
&setException,
&setException,
&setException,
&setException,
&setException
);
}
static void setException(const char* message) {
auto exception = new object.Exception(std.conv.to!string(message));
SwigPendingException.set(exception);
}
}
package struct SwigPendingException {
public:
static this() {
m_sPendingException = null;
}
static bool isPending() {
return m_sPendingException !is null;
}
static void set(object.Exception e) {
if (m_sPendingException !is null) {
e.next = m_sPendingException;
throw new object.Exception("FATAL: An earlier pending exception from C/C++ code " ~
"was missed and thus not thrown (" ~ m_sPendingException.classinfo.name ~
": " ~ m_sPendingException.msg ~ ")!", e);
}
m_sPendingException = e;
}
static object.Exception retrieve() {
auto e = m_sPendingException;
m_sPendingException = null;
return e;
}
private:
// The reference to the pending exception (if any) is stored thread-local.
static object.Exception m_sPendingException;
}
alias void function(const char* message) SwigExceptionCallback;
%}
#endif
// Callback registering function in wrapperloader.swg.
#endif // SWIG_D_NO_EXCEPTION_HELPER
/*
* String support code.
*/
#if !defined(SWIG_D_NO_STRING_HELPER)
%insert(runtime) %{
// Callback for returning strings to D without leaking memory.
typedef char * (* SWIG_DStringHelperCallback)(const char *);
static SWIG_DStringHelperCallback SWIG_d_string_callback = NULL;
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT void SWIGRegisterStringCallback_$module(SWIG_DStringHelperCallback callback) {
SWIG_d_string_callback = callback;
}
%}
#if (SWIG_D_VERSION == 1)
%pragma(d) imdmoduleimports = "static import tango.stdc.stringz;";
%pragma(d) imdmodulecode = %{
private class SwigStringHelper {
static this() {
swigRegisterStringCallback$module(&createString);
}
static char* createString(char* cString) {
// We are effectively dup'ing the string here.
return tango.stdc.stringz.toStringz(tango.stdc.stringz.fromStringz(cString));
}
}
alias char* function(char* cString) SwigStringCallback;
%}
#else
%pragma(d) imdmoduleimports = %{
static import std.conv;
static import std.string;
%}
%pragma(d) imdmodulecode = %{
private class SwigStringHelper {
static this() {
swigRegisterStringCallback$module(&createString);
}
static const(char)* createString(const(char*) cString) {
// We are effectively dup'ing the string here.
// TODO: Is this also correct for D2/Phobos?
return std.string.toStringz(std.conv.to!string(cString));
}
}
alias const(char)* function(const(char*) cString) SwigStringCallback;
%}
#endif
// Callback registering function in wrapperloader.swg.
#endif // SWIG_D_NO_STRING_HELPER
/*
* Function pointer support code.
*/
#if (SWIG_D_VERSION == 1)
%pragma(d) imdmodulecode = %{
template SwigExternC(T) {
static if (is(typeof(*(T.init)) R == return)) {
static if (is(typeof(*(T.init)) P == function)) {
alias extern(C) R function(P) SwigExternC;
}
}
}
%}
#else
%pragma(d) imdmodulecode = %{
template SwigExternC(T) if (is(typeof(*(T.init)) P == function)) {
static if (is(typeof(*(T.init)) R == return)) {
static if (is(typeof(*(T.init)) P == function)) {
alias extern(C) R function(P) SwigExternC;
}
}
}
%}
#endif