Hi,

I'm wrapping a C++ library that's actually just a thin wrapper around a C
lib.

Through a dispatch() method of a Dispatcher class there's an invocation of
callbacks which get implemented on the Python side, by subclassing callback
classes exposed through Boost.Python.

Now, for performing the actual dispatch the C++ library calls into the
underlying C library.

This hasn't been a problem so far as we've been targetting Solaris using
Sun/Oracle studio
compilers.

However, on Linux compiled with GCC, if an exception gets raised in the
Python callback the
program segfaults. Obviously the C part of the vendor library has not been
compiled with
(GCC-) exception support for Linux.

Unfortunately this isn't under my control and the library provider seems
not to be willing
to make the library robust against exceptions in user callback code.

So I need to keep the Boost C++ exception that "signals" the Python
exception from passing
through the C parts.

Instead of introducing some custom error/exception notification scheme I
*think* I can simply
do this:

As I need  wrapper classes for the virtual method override mechanisms
anyway I can
just ignore/suppress the exception in the callback wrapper layer and
re-throw the exception
again in the dispatcher, provided that in between we do not return to
Python and no other
call into Python is made:

I.e.

The callback wrapper simply suppresses the C++ exception "signalled" for
the Python exception:

class CallbackWrap : public Callback, public bp::wrapper<Callback> {

    // pure virtual so no need for default implementation
    // virtual void onMsg(MsgListener* listener, Msg& msg) = 0;
    virtual void onMsg(MsgListener* listener, Msg& msg) {
        try {
            this->get_override("onMsg")(bp::ptr(listener), boost::ref
(msg));
        } catch (const bp::error_already_set& e) {
            if (PyErr_Occurred()) {
                // Do nothing: The Dispatcher  that invoked the callback
                // MUST check if a Python error has been set and re-throw
            }
        }
    }
};


The Dispatcher is then responsible for re-throwing, to not let the Python
exception
go undetected when returning to the Python world:

    // virtual Status dispatch      ();
    virtual Status dispatch() {
        Status ret;
        if (bp::override f = this->get_override("dispatch")) {
                ret = f(); // *note*
        } else {
            ret = Queue::dispatch();
        }
        if (PyErr_Occurred()) {
            // Re-throw the error that stems from the Python exception in
the dispatched callback
            bp::throw_error_already_set();
        }
        return ret;
    }


Does this sound sane?

Any hints appreciated,
Holger



Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to