X-Git-Url: http://git.annexia.org/?p=virt-top.git;a=blobdiff_plain;f=libvirt%2Flibvirt_c_prologue.c;fp=libvirt%2Flibvirt_c_prologue.c;h=1e81d5a5829b423754400f8789f7105cbe50dcec;hp=0000000000000000000000000000000000000000;hb=43b894e0ef93f380dcd8b1b20a3cd6626a8f3b7d;hpb=ebb4ff16c73674ef768674c85f600b71b63448e7 diff --git a/libvirt/libvirt_c_prologue.c b/libvirt/libvirt_c_prologue.c new file mode 100644 index 0000000..1e81d5a --- /dev/null +++ b/libvirt/libvirt_c_prologue.c @@ -0,0 +1,176 @@ +/* OCaml bindings for libvirt. + * (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc. + * http://libvirt.org/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Please read libvirt/README file. */ + +static char *Optstring_val (value strv); +typedef value (*Val_ptr_t) (void *); +static value Val_opt (void *ptr, Val_ptr_t Val_ptr); +/*static value option_default (value option, value deflt);*/ +static void _raise_virterror (virConnectPtr conn, const char *fn) Noreturn; +static void not_supported (const char *fn) Noreturn; +static value Val_virterror (virErrorPtr err); + +/* Use this around synchronous libvirt API calls to release the OCaml + * lock, allowing other threads to run simultaneously. 'code' must not + * perform any caml_* calls, run any OCaml code, or raise any exception. + * http://web.archive.org/web/20030521020915/http://caml.inria.fr/archives/200106/msg00199.html + */ +#define NONBLOCKING(code) \ + do { \ + caml_enter_blocking_section (); \ + code; \ + caml_leave_blocking_section (); \ + } while (0) + +/* Check error condition from a libvirt function, and automatically raise + * an exception if one is found. + */ +#define CHECK_ERROR(cond, conn, fn) \ + do { if (cond) _raise_virterror (conn, fn); } while (0) + +/* For more about weak symbols, see: + * http://kolpackov.net/pipermail/notes/2004-March/000006.html + * We are using this to do runtime detection of library functions + * so that if we dynamically link with an older version of + * libvirt than we were compiled against, it won't fail (provided + * libvirt >= 0.2.1 - we don't support anything older). + */ +#ifdef __GNUC__ +#ifdef linux +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3) +#define HAVE_WEAK_SYMBOLS 1 +#endif +#endif +#endif + +#ifdef HAVE_WEAK_SYMBOLS +#define WEAK_SYMBOL_CHECK(sym) \ + do { if (!sym) not_supported(#sym); } while (0) +#else +#define WEAK_SYMBOL_CHECK(sym) +#endif /* HAVE_WEAK_SYMBOLS */ + +/*----------------------------------------------------------------------*/ + +/* Some notes about the use of custom blocks to store virConnectPtr, + * virDomainPtr and virNetworkPtr. + *------------------------------------------------------------------ + * + * Libvirt does some tricky reference counting to keep track of + * virConnectPtr's, virDomainPtr's and virNetworkPtr's. + * + * There is only one function which can return a virConnectPtr + * (virConnectOpen*) and that allocates a new one each time. + * + * virDomainPtr/virNetworkPtr's on the other hand can be returned + * repeatedly (for the same underlying domain/network), and we must + * keep track of each one and explicitly free it with virDomainFree + * or virNetworkFree. If we lose track of one then the reference + * counting in libvirt will keep it open. We therefore wrap these + * in a custom block with a finalizer function. + * + * We also have to allow the user to explicitly free them, in + * which case we set the pointer inside the custom block to NULL. + * The finalizer notices this and doesn't free the object. + * + * Domains and networks "belong to" a connection. We have to avoid + * the situation like this: + * + * let conn = Connect.open ... in + * let dom = Domain.lookup_by_id conn 0 in + * (* conn goes out of scope and is garbage collected *) + * printf "dom name = %s\n" (Domain.get_name dom) + * + * The reason is that when conn is garbage collected, virConnectClose + * is called and any subsequent operations on dom will fail (in fact + * will probably segfault). To stop this from happening, the OCaml + * wrappers store domains (and networks) as explicit (dom, conn) + * pairs. + * + * Further complication with virterror / exceptions: Virterror gives + * us virConnectPtr, virDomainPtr, virNetworkPtr pointers. If we + * follow standard practice and wrap these up in blocks with + * finalizers then we'll end up double-freeing (in particular, calling + * virConnectClose at the wrong time). So for virterror, we have + * "special" wrapper functions (Val_connect_no_finalize, etc.). + * + * Update 2008/01: Storage pools and volumes work the same way as + * domains and networks. + */ + +/* Unwrap a custom block. */ +#define Connect_val(rv) (*((virConnectPtr *)Data_custom_val(rv))) +#define Dom_val(rv) (*((virDomainPtr *)Data_custom_val(rv))) +#define Net_val(rv) (*((virNetworkPtr *)Data_custom_val(rv))) +#ifdef HAVE_VIRSTORAGEPOOLPTR +#define Pol_val(rv) (*((virStoragePoolPtr *)Data_custom_val(rv))) +#endif +#ifdef HAVE_VIRSTORAGEVOLPTR +#define Vol_val(rv) (*((virStorageVolPtr *)Data_custom_val(rv))) +#endif + +/* Wrap up a pointer to something in a custom block. */ +static value Val_connect (virConnectPtr conn); +static value Val_dom (virDomainPtr dom); +static value Val_net (virNetworkPtr net); +#ifdef HAVE_VIRSTORAGEPOOLPTR +static value Val_pol (virStoragePoolPtr pool); +#endif +#ifdef HAVE_VIRSTORAGEVOLPTR +static value Val_vol (virStorageVolPtr vol); +#endif + +/* ONLY for use by virterror wrappers. */ +static value Val_connect_no_finalize (virConnectPtr conn); +static value Val_dom_no_finalize (virDomainPtr dom); +static value Val_net_no_finalize (virNetworkPtr net); + +/* Domains and networks are stored as pairs (dom/net, conn), so have + * some convenience functions for unwrapping and wrapping them. + */ +#define Domain_val(rv) (Dom_val(Field((rv),0))) +#define Network_val(rv) (Net_val(Field((rv),0))) +#ifdef HAVE_VIRSTORAGEPOOLPTR +#define Pool_val(rv) (Pol_val(Field((rv),0))) +#endif +#ifdef HAVE_VIRSTORAGEVOLPTR +#define Volume_val(rv) (Vol_val(Field((rv),0))) +#endif +#define Connect_domv(rv) (Connect_val(Field((rv),1))) +#define Connect_netv(rv) (Connect_val(Field((rv),1))) +#ifdef HAVE_VIRSTORAGEPOOLPTR +#define Connect_polv(rv) (Connect_val(Field((rv),1))) +#endif +#ifdef HAVE_VIRSTORAGEVOLPTR +#define Connect_volv(rv) (Connect_val(Field((rv),1))) +#endif + +static value Val_domain (virDomainPtr dom, value connv); +static value Val_network (virNetworkPtr net, value connv); +#ifdef HAVE_VIRSTORAGEPOOLPTR +static value Val_pool (virStoragePoolPtr pol, value connv); +#endif +#ifdef HAVE_VIRSTORAGEVOLPTR +static value Val_volume (virStorageVolPtr vol, value connv); +#endif + +/* ONLY for use by virterror wrappers. */ +static value Val_domain_no_finalize (virDomainPtr dom, value connv); +static value Val_network_no_finalize (virNetworkPtr net, value connv);