Thallium and PyMargo are respectively C++ and Python wrappers for Margo, hence, the three are interoperable. The table bellow summarizes the mapping between Margo constructs and Thallium and PyMargo classes.













hg_handle_t (sender)



hg_handle_t (receiver)






From Margo to Thallium

The Thallium engine and endpoint classes provide constructors that will create instances from their Margo counterparts. To construct a Thallium bulk from a Margo hg_bulk_t, you can use engine::wrap(). It is also possible to retrieve the underlying Margo constructs from Thallium. The engine::get_margo_instance(), endpoint::get_addr(), and bulk::get_bulk() functions return the object’s internal margo_instance_id, hg_addr_t, and hg_bulk_t respectively.

There is no conversion mechanism (but generally no need for them) between hg_handle_t and callable_remote_procedure or request, and between async_response and margo_request.

Serialization mechanisms differ between Margo and Thallium. Margo uses either Mercury’s boost preprocessor macros to automatically define serialization function or rely on user-provided hg_proc functions, while Thallium relies on the Cereal library. Hence it is not possible to, for instance, define an RPC using MARGO_REGISTER on the client side, and with thallium::engine::define() on the server side, and vice versa.


If you are provided with a margo_instance_id and wrap it in a Thallium engine to define some RPC functions in C++, you will need your engine instance to remain alive after having defined the RPC. This is because the RPC function retains a weak pointer to the engine’s internal structure and will use it when it is invoked. This also applies when creating an instance of a provider: while Thallium’s provider class constructor takes an engine argument, it only keeps a weak reference to it.

From Margo to PyMargo

PyMargo uses pybind11 to convert Margo structures and functions into Python. More specifically, native C handles are exposed as Python capsules. Higher-level classes then wrap these capsules to provide an object-oriented interface for them. For instance, the Address class is a pure-python class wrapping a _pymargo.hg_addr_t capsule, itself exposing an hg_addr_t native handle.

High-level Python classes generally have functions to get the internal capsule of an object, should they be necessary to pass to C/C++ functions. For instance, Address has the hg_addr property, Engine has an mid property, and so on.

If you have a Mochi library developped in C or C++ and want to make a Python binding for it that is compatible with PyMargo, we recommend that you look at how Yokan does it, in its python folder.

Serialization in PyMargo relies on Python’s pickle module, hence it is not possible to register an RPC with MARGO_REGISTER or engine::define() on one side, and expect Python to correctly work on the other side.


If you use Thallium as an intermediary between PyMargo and a C++ library, you can get a margo_instance_id from a PyMargo Engine, then create a Thallium engine from it, but don’t forget to keep this instance alive.