summaryrefslogtreecommitdiffstats
path: root/libvirt/libvirt_c_prologue.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvirt/libvirt_c_prologue.c')
-rw-r--r--libvirt/libvirt_c_prologue.c176
1 files changed, 176 insertions, 0 deletions
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);