[Libguestfs] [libnbd PATCH 2/2] RFC: generator: Handle shared callbacks in Python

Eric Blake eblake at redhat.com
Tue Jul 16 04:38:12 UTC 2019


[RFC because generated OCaml code needs the same treatment, but I ran
out of time to play with that. At least 'make -C python check' passes,
although coverage is not complete yet, as there is no
python/t/5XX-pread-structured-callback.py...]

[Also RFC because I'm not sure if the use of a record type for
'callback' is the best approach or most idiomatic OCaml - but hey, it
taught me a lot about OCaml. Writing a 'string * callback list' proved
to be a rather interesting exercise]

Our C code has a couple of functions that want to take multiple
callback functions that share a single opaque data
(nbd_aio_pread_structured_callback; nbd_aio_block_status_callback).
However, the mapping of this construct to Python passed only the
opaque handle of the first function to the second callback wrapper,
which means we would invoke the wrong Python Callable; better is
tracking a single malloc()d structure containing the Python opaque
object, and ALL of the Python Callables that reuse that same opaque
object.

We could either add lots of static checking that a
Callback/CallbackPersist cannot appear in the argument list until
after an earlier Opaque, and that the argument name for top-level
Opaque also appears as the first argument for the callback function.
Or, we could bundle the construct through a better constructor that
tracks that an opaque argument and one or more callback functions must
be handled as a unit, where the callback function automatically
outputs the opaque argument first.  This patch attempts the latter.

It may also be worth comparing a diff of the generated
python/methods.c before and after this patch, to see what changes.
---
 generator/generator | 542 ++++++++++++++++++++++----------------------
 1 file changed, 272 insertions(+), 270 deletions(-)

diff --git a/generator/generator b/generator/generator
index ad12b36..e48b1ad 100755
--- a/generator/generator
+++ b/generator/generator
@@ -841,6 +841,13 @@ type call = {
    *)
   may_set_error : bool;
 }
+and callback = {
+  name : string;           (* callback name *)
+  cbargs : arg list;       (* parameters (except opaque) *)
+  (* For now, all callbacks return int; we could list a return type here if
+   * more variety is needed.
+   *)
+}
 and arg =
 | ArrayAndLen of arg * string (* array + number of entries *)
 | Bool of string           (* bool *)
@@ -849,13 +856,14 @@ and arg =
                               written by the function *)
 | BytesPersistIn of string * string (* same as above, but buffer persists *)
 | BytesPersistOut of string * string
-| Callback of string * arg list (* callback function returning int *)
-| CallbackPersist of string * arg list (* as above, but callback persists *)
 | Flags of string          (* NBD_CMD_FLAG_* flags *)
 | Int of string            (* small int *)
 | Int64 of string          (* 64 bit signed int *)
 | Mutable of arg           (* mutable argument, eg. int* *)
-| Opaque of string         (* opaque object, void* in C *)
+| OpaqueAndCallbacks of string * callback list (* one or more callbacks
+                                                * sharing same opaque *)
+| OpaqueAndCallbacksPersist of string * callback list (* as above, but opaque
+                                                       * persists *)
 | Path of string           (* filename or path *)
 | SockAddrAndLen of string * string (* struct sockaddr * + socklen_t *)
 | String of string         (* string *)
@@ -915,9 +923,10 @@ Return the state of the debug flag on this handle.";

   "set_debug_callback", {
     default_call with
-    args = [ Opaque "data";
-             CallbackPersist ("debug_fn", [Opaque "data";
-                                           String "context"; String "msg"]) ];
+    args = [ OpaqueAndCallbacksPersist ("data",
+                                        [ {name="debug_fn";
+                                           cbargs=[ String "context";
+                                                    String "msg" ]}]) ];
     ret = RErr;
     shortdesc = "set the debug callback";
     longdesc = "\
@@ -1345,10 +1354,11 @@ protocol extensions).";
   "pread_structured", {
     default_call with
     args = [ BytesOut ("buf", "count"); UInt64 "offset";
-             Opaque "data";
-             Callback ("chunk", [ Opaque "data"; BytesIn ("subbuf", "count");
-                                  UInt64 "offset"; Int "status";
-                                  Mutable (Int "error"); ]);
+             OpaqueAndCallbacks ("data",
+                                 [ {name="chunk";
+                                    cbargs=[ BytesIn ("subbuf", "count");
+                                             UInt64 "offset"; Int "status";
+                                             Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RErr;
     permitted_states = [ Connected ];
@@ -1534,12 +1544,13 @@ punching a hole.";
   "block_status", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             Callback ("extent", [Opaque "data"; String "metacontext";
-                                  UInt64 "offset";
-                                  ArrayAndLen (UInt32 "entries",
-                                               "nr_entries");
-                                  Mutable (Int "error")]);
+             OpaqueAndCallbacks ("data",
+                                 [ {name="extent";
+                                    cbargs=[String "metacontext";
+                                            UInt64 "offset";
+                                            ArrayAndLen (UInt32 "entries",
+                                                         "nr_entries");
+                                            Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RErr;
     permitted_states = [ Connected ];
@@ -1717,9 +1728,10 @@ C<nbd_pread>.";
   "aio_pread_callback", {
     default_call with
     args = [ BytesPersistOut ("buf", "count"); UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1747,12 +1759,12 @@ cause a deadlock.";
   "aio_pread_structured", {
     default_call with
     args = [ BytesPersistOut ("buf", "count"); UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("chunk", [ Opaque "data";
-                                         BytesIn ("subbuf", "count");
-                                         UInt64 "offset";
-                                         Int "status";
-                                         Mutable (Int "error"); ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="chunk";
+                                           cbargs=[ BytesIn ("subbuf", "count");
+                                                    UInt64 "offset";
+                                                    Int "status";
+                                                    Mutable (Int "error"); ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1769,14 +1781,15 @@ documented in C<nbd_pread_structured>.";
   "aio_pread_structured_callback", {
     default_call with
     args = [ BytesPersistOut ("buf", "count"); UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("chunk", [ Opaque "data";
-                                         BytesIn ("subbuf", "count");
-                                         UInt64 "offset";
-                                         Int "status";
-                                         Mutable (Int "error"); ]);
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="chunk";
+                                           cbargs=[ BytesIn ("subbuf", "count");
+                                                    UInt64 "offset";
+                                                    Int "status";
+                                                    Mutable (Int "error"); ]};
+                                          {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1819,9 +1832,10 @@ C<nbd_pwrite>.";
   "aio_pwrite_callback", {
     default_call with
     args = [ BytesPersistIn ("buf", "count"); UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1884,9 +1898,10 @@ Parameters behave as documented in C<nbd_flush>.";

   "aio_flush_callback", {
     default_call with
-    args = [ Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+    args = [ OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1927,9 +1942,10 @@ Parameters behave as documented in C<nbd_trim>.";
   "aio_trim_callback", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                          Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -1970,9 +1986,10 @@ Parameters behave as documented in C<nbd_cache>.";
   "aio_cache_callback", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -2013,9 +2030,10 @@ Parameters behave as documented in C<nbd_zero>.";
   "aio_zero_callback", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -2042,12 +2060,13 @@ cause a deadlock.";
   "aio_block_status", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("extent", [Opaque "data"; String "metacontext";
-                                         UInt64 "offset";
-                                         ArrayAndLen (UInt32 "entries",
-                                                      "nr_entries");
-                                         Mutable (Int "error")]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="extent";
+                                           cbargs=[ String "metacontext";
+                                                    UInt64 "offset";
+                                                    ArrayAndLen (UInt32 "entries",
+                                                                 "nr_entries");
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -2063,14 +2082,16 @@ Parameters behave as documented in C<nbd_block_status>.";
   "aio_block_status_callback", {
     default_call with
     args = [ UInt64 "count"; UInt64 "offset";
-             Opaque "data";
-             CallbackPersist ("extent", [Opaque "data"; String "metacontext";
-                                         UInt64 "offset";
-                                         ArrayAndLen (UInt32 "entries",
-                                                      "nr_entries");
-                                         Mutable (Int "error") ]);
-             CallbackPersist ("callback", [ Opaque "data"; Int64 "cookie";
-                                            Mutable (Int "error") ]);
+             OpaqueAndCallbacksPersist ("data",
+                                        [ {name="extent";
+                                           cbargs=[ String "metacontext";
+                                                    UInt64 "offset";
+                                                    ArrayAndLen (UInt32 "entries",
+                                                                 "nr_entries");
+                                                    Mutable (Int "error") ]};
+                                          {name="callback";
+                                           cbargs=[ Int64 "cookie";
+                                                    Mutable (Int "error") ]}]);
              Flags "flags" ];
     ret = RInt64;
     permitted_states = [ Connected ];
@@ -3150,11 +3171,11 @@ let rec name_of_arg = function
 | BytesOut (n, len) -> [n; len]
 | BytesPersistIn (n, len) -> [n; len]
 | BytesPersistOut (n, len) -> [n; len]
-| Callback (n, _) | CallbackPersist (n, _) -> [n]
 | Flags n -> [n]
 | Int n -> [n]
 | Int64 n -> [n]
-| Opaque n -> [n]
+| OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+   [n] @ List.map (fun cb -> cb.name) cbs
 | Mutable arg -> name_of_arg arg
 | Path n -> [n]
 | SockAddrAndLen (n, len) -> [n; len]
@@ -3185,15 +3206,17 @@ let rec print_c_arg_list ?(handle = None) args =
       | BytesPersistIn (n, len) -> pr "const void *%s, size_t %s" n len
       | BytesOut (n, len)
       | BytesPersistOut (n, len) -> pr "void *%s, size_t %s" n len
-      | Callback (n, args)
-      | CallbackPersist (n, args) ->
-         pr "int (*%s) " n; print_c_arg_list args
       | Flags n -> pr "uint32_t %s" n
       | Int n -> pr "int %s" n
       | Int64 n -> pr "int64_t %s" n
       | Mutable (Int n) -> pr "int *%s" n
       | Mutable arg -> assert false
-      | Opaque n -> pr "void *%s" n
+      | OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+         pr "void *%s" n;
+         List.iter (fun cb ->
+           let first = "void *" ^ n in
+           pr ", int (*%s)" cb.name;
+           print_c_arg_list ~handle:(Some first) cb.cbargs) cbs
       | Path n
       | String n -> pr "const char *%s" n
       | StringList n -> pr "char **%s" n
@@ -3715,155 +3738,138 @@ let print_python_binding name { args; ret } =
    * have to generate a wrapper function which translates the
    * callback parameters back to Python.
    *)
-  let find_callback opaque_id =
-    let cb =
-      try
-        List.find (
-          function
-          | Callback (_, args) | CallbackPersist (_, args) ->
-             List.mem (Opaque opaque_id) args
-          | _ -> false
-        ) args
-      with
-        Not_found ->
-        failwithf "%s: couldn't find callback associated with Opaque %s"
-                  name opaque_id in
-    match cb with
-    | Callback (name, _) | CallbackPersist (name, _) -> name
-    | _ -> assert false
+  let print_callback cb =
+    pr "static int\n";
+    pr "%s_%s_wrapper " name cb.name;
+    print_c_arg_list ~handle:(Some "void *_data") cb.cbargs;
+    pr "\n";
+    pr "{\n";
+    pr "  int ret;\n";
+    pr "  PyGILState_STATE py_save = PyGILState_UNLOCKED;\n";
+    pr "  PyObject *py_args, *py_ret;\n";
+    pr "  struct %s_data *data = _data;\n" name;
+    List.iter (
+      function
+      | ArrayAndLen (UInt32 n, len) ->
+         pr "  PyObject *py_%s = PyList_New (%s);\n" n len;
+         pr "  for (size_t i = 0; i < %s; ++i)\n" len;
+         pr "    PyList_SET_ITEM (py_%s, i, PyLong_FromUnsignedLong (%s[i]));\n" n n
+      | BytesIn _
+      | Int _
+      | Int64 _ -> ()
+      | Mutable (Int n) ->
+         pr "  PyObject *py_%s_modname = PyUnicode_FromString (\"ctypes\");\n" n;
+         pr "  if (!py_%s_modname) { PyErr_PrintEx (0); return -1; }\n" n;
+         pr "  PyObject *py_%s_mod = PyImport_Import (py_%s_modname);\n" n n;
+         pr "  Py_DECREF (py_%s_modname);\n" n;
+         pr "  if (!py_%s_mod) { PyErr_PrintEx (0); return -1; }\n" n;
+         pr "  PyObject *py_%s = PyObject_CallMethod (py_%s_mod, \"c_int\", \"i\", *%s);\n" n n n;
+         pr "  if (!py_%s) { PyErr_PrintEx (0); return -1; }\n" n;
+      | String n
+      | UInt64 n -> ()
+      (* The following not yet implemented for callbacks XXX *)
+      | ArrayAndLen _ | Bool _ | BytesOut _
+      | BytesPersistIn _ | BytesPersistOut _
+      | Flags _ | Mutable _
+      | OpaqueAndCallbacks _ | OpaqueAndCallbacksPersist _
+      | Path _ | SockAddrAndLen _ | StringList _
+      | UInt _ | UInt32 _ -> assert false
+    ) cb.cbargs;
+    pr "\n";
+
+    pr "  py_args = Py_BuildValue (\"(O\"";
+    List.iter (
+      function
+      | ArrayAndLen (UInt32 n, len) -> pr " \"O\""
+      | BytesIn (n, len) -> pr " \"y#\""
+      | Int n -> pr " \"i\""
+      | Int64 n -> pr " \"L\""
+      | Mutable (Int n) -> pr " \"O\""
+      | String n -> pr " \"s\""
+      | UInt64 n -> pr " \"K\""
+      (* The following not yet implemented for callbacks XXX *)
+      | ArrayAndLen _ | Bool _ | BytesOut _
+      | BytesPersistIn _ | BytesPersistOut _
+      | Flags _ | Mutable _
+      | OpaqueAndCallbacks _ | OpaqueAndCallbacksPersist _
+      | Path _ | SockAddrAndLen _ | StringList _
+      | UInt _ | UInt32 _ -> assert false
+    ) cb.cbargs;
+    pr " \")\", data->data";
+    List.iter (
+      function
+      | ArrayAndLen (UInt32 n, _) -> pr ", py_%s" n
+      | BytesIn (n, len) -> pr ", %s, (int) %s" n len
+      | Mutable (Int n) -> pr ", py_%s" n
+      | Int n | Int64 n
+      | String n
+      | UInt64 n -> pr ", %s" n
+      (* The following not yet implemented for callbacks XXX *)
+      | ArrayAndLen _ | Bool _ | BytesOut _
+      | BytesPersistIn _ | BytesPersistOut _
+      | Flags _ | Mutable _
+      | OpaqueAndCallbacks _ | OpaqueAndCallbacksPersist _
+      | Path _ | SockAddrAndLen _ | StringList _
+      | UInt _ | UInt32 _ -> assert false
+    ) cb.cbargs;
+    pr ");\n";
+    pr "  Py_INCREF (py_args);\n";
+    pr "\n";
+    pr "  if (PyEval_ThreadsInitialized ())\n";
+    pr "    py_save = PyGILState_Ensure ();\n";
+    pr "\n";
+    pr "  py_ret = PyObject_CallObject (data->%s, py_args);\n" cb.name;
+    pr "\n";
+    pr "  if (PyEval_ThreadsInitialized ())\n";
+    pr "    PyGILState_Release (py_save);\n";
+    pr "\n";
+    pr "  Py_DECREF (py_args);\n";
+    pr "\n";
+    pr "  if (py_ret != NULL) {\n";
+    pr "    ret = 0;\n";
+    pr "    Py_DECREF (py_ret); /* return value is discarded */\n";
+    pr "  }\n";
+    pr "  else {\n";
+    pr "    ret = -1;\n";
+    pr "    PyErr_PrintEx (0); /* print exception */\n";
+    pr "  };\n";
+    pr "\n";
+    List.iter (
+      function
+      | ArrayAndLen (UInt32 n, _) ->
+         pr "  Py_DECREF (py_%s);\n" n
+      | Mutable (Int n) ->
+         pr "  PyObject *py_%s_ret = PyObject_GetAttrString (py_%s, \"value\");\n" n n;
+         pr "  *%s = PyLong_AsLong (py_%s_ret);\n" n n;
+         pr "  Py_DECREF (py_%s_ret);\n" n;
+         pr "  Py_DECREF (py_%s);\n" n
+      | BytesIn _
+      | Int _ | Int64 _
+      | String _
+      | UInt64 _ -> ()
+      (* The following not yet implemented for callbacks XXX *)
+      | ArrayAndLen _ | Bool _ | BytesOut _
+      | BytesPersistIn _ | BytesPersistOut _
+      | Flags _ | Mutable _
+      | OpaqueAndCallbacks _ | OpaqueAndCallbacksPersist _
+      | Path _ | SockAddrAndLen _ | StringList _
+      | UInt _ | UInt32 _ -> assert false
+    ) cb.cbargs;
+    pr "  return ret;\n";
+    pr "}\n";
+    pr "\n"
   in

   List.iter (
     function
-    | Callback (cb_name, args) | CallbackPersist (cb_name, args) ->
-       pr "struct %s_%s_data {\n" name cb_name;
-       pr "  PyObject *fn;\n";
+    | OpaqueAndCallbacks (data, cbs) | OpaqueAndCallbacksPersist (data, cbs) ->
+       pr "struct %s_data {\n" name;
        pr "  PyObject *data;\n";
+       List.iter (fun cb ->
+         pr "  PyObject *%s;\n" cb.name) cbs;
        pr "};\n";
        pr "\n";
-       pr "static int\n";
-       pr "%s_%s_wrapper " name cb_name;
-       print_c_arg_list args;
-       pr "\n";
-       pr "{\n";
-       pr "  int ret;\n";
-       pr "  PyGILState_STATE py_save = PyGILState_UNLOCKED;\n";
-       pr "  PyObject *py_args, *py_ret;\n";
-       List.iter (
-         function
-         | ArrayAndLen (UInt32 n, len) ->
-            pr "  PyObject *py_%s = PyList_New (%s);\n" n len;
-            pr "  for (size_t i = 0; i < %s; ++i)\n" len;
-            pr "    PyList_SET_ITEM (py_%s, i, PyLong_FromUnsignedLong (%s[i]));\n" n n
-         | BytesIn _
-         | Int _
-         | Int64 _ -> ()
-         | Mutable (Int n) ->
-            pr "  PyObject *py_%s_modname = PyUnicode_FromString (\"ctypes\");\n" n;
-            pr "  if (!py_%s_modname) { PyErr_PrintEx (0); return -1; }\n" n;
-            pr "  PyObject *py_%s_mod = PyImport_Import (py_%s_modname);\n" n n;
-            pr "  Py_DECREF (py_%s_modname);\n" n;
-            pr "  if (!py_%s_mod) { PyErr_PrintEx (0); return -1; }\n" n;
-            pr "  PyObject *py_%s = PyObject_CallMethod (py_%s_mod, \"c_int\", \"i\", *%s);\n" n n n;
-            pr "  if (!py_%s) { PyErr_PrintEx (0); return -1; }\n" n;
-         | Opaque n ->
-            pr "  struct %s_%s_data *_data = %s;\n" name cb_name n
-         | String n
-         | UInt64 n -> ()
-         (* The following not yet implemented for callbacks XXX *)
-         | ArrayAndLen _ | Bool _ | BytesOut _
-         | BytesPersistIn _ | BytesPersistOut _
-         | Callback _ | CallbackPersist _
-         | Flags _ | Mutable _
-         | Path _ | SockAddrAndLen _ | StringList _
-         | UInt _ | UInt32 _ -> assert false
-       ) args;
-       pr "\n";
-
-       pr "  py_args = Py_BuildValue (\"(\"";
-       List.iter (
-         function
-         | ArrayAndLen (UInt32 n, len) -> pr " \"O\""
-         | BytesIn (n, len) -> pr " \"y#\""
-         | Int n -> pr " \"i\""
-         | Int64 n -> pr " \"L\""
-         | Mutable (Int n) -> pr " \"O\""
-         | Opaque n -> pr " \"O\""
-         | String n -> pr " \"s\""
-         | UInt64 n -> pr " \"K\""
-         (* The following not yet implemented for callbacks XXX *)
-         | ArrayAndLen _ | Bool _ | BytesOut _
-         | BytesPersistIn _ | BytesPersistOut _
-         | Callback _ | CallbackPersist _
-         | Flags _ | Mutable _
-         | Path _ | SockAddrAndLen _ | StringList _
-         | UInt _ | UInt32 _ -> assert false
-       ) args;
-       pr " \")\"";
-       List.iter (
-         function
-         | ArrayAndLen (UInt32 n, _) -> pr ", py_%s" n
-         | BytesIn (n, len) -> pr ", %s, (int) %s" n len
-         | Mutable (Int n) -> pr ", py_%s" n
-         | Opaque _ -> pr ", _data->data"
-         | Int n | Int64 n
-         | String n
-         | UInt64 n -> pr ", %s" n
-         (* The following not yet implemented for callbacks XXX *)
-         | ArrayAndLen _ | Bool _ | BytesOut _
-         | BytesPersistIn _ | BytesPersistOut _
-         | Callback _ | CallbackPersist _
-         | Flags _ | Mutable _
-         | Path _ | SockAddrAndLen _ | StringList _
-         | UInt _ | UInt32 _ -> assert false
-       ) args;
-       pr ");\n";
-       pr "  Py_INCREF (py_args);\n";
-       pr "\n";
-       pr "  if (PyEval_ThreadsInitialized ())\n";
-       pr "    py_save = PyGILState_Ensure ();\n";
-       pr "\n";
-       pr "  py_ret = PyObject_CallObject (_data->fn, py_args);\n";
-       pr "\n";
-       pr "  if (PyEval_ThreadsInitialized ())\n";
-       pr "    PyGILState_Release (py_save);\n";
-       pr "\n";
-       pr "  Py_DECREF (py_args);\n";
-       pr "\n";
-       pr "  if (py_ret != NULL) {\n";
-       pr "    ret = 0;\n";
-       pr "    Py_DECREF (py_ret); /* return value is discarded */\n";
-       pr "  }\n";
-       pr "  else {\n";
-       pr "    ret = -1;\n";
-       pr "    PyErr_PrintEx (0); /* print exception */\n";
-       pr "  };\n";
-       pr "\n";
-       List.iter (
-         function
-         | ArrayAndLen (UInt32 n, _) ->
-            pr "  Py_DECREF (py_%s);\n" n
-         | Mutable (Int n) ->
-            pr "  PyObject *py_%s_ret = PyObject_GetAttrString (py_%s, \"value\");\n" n n;
-            pr "  *%s = PyLong_AsLong (py_%s_ret);\n" n n;
-            pr "  Py_DECREF (py_%s_ret);\n" n;
-            pr "  Py_DECREF (py_%s);\n" n
-         | BytesIn _
-         | Int _ | Int64 _
-         | Opaque _
-         | String _
-         | UInt64 _ -> ()
-         (* The following not yet implemented for callbacks XXX *)
-         | ArrayAndLen _ | Bool _ | BytesOut _
-         | BytesPersistIn _ | BytesPersistOut _
-         | Callback _ | CallbackPersist _
-         | Flags _ | Mutable _
-         | Path _ | SockAddrAndLen _ | StringList _
-         | UInt _ | UInt32 _ -> assert false
-       ) args;
-       pr "  return ret;\n";
-       pr "}\n";
-       pr "\n"
+       List.iter (fun cb -> print_callback cb) cbs
     | _ -> ()
   ) args;

@@ -3901,10 +3907,6 @@ let print_python_binding name { args; ret } =
        pr "  PyObject *%s; /* PyCapsule pointing to struct py_aio_buffer */\n"
           n;
        pr "  struct py_aio_buffer *%s_buf;\n" n
-    | Callback (n, _) ->
-       pr "  struct %s_%s_data _%s_data, *%s_data = &_%s_data;\n" name n n n n
-    | CallbackPersist (n, _) ->
-       pr "  struct %s_%s_data *%s_data;\n" name n n
     | Flags n ->
        pr "  uint32_t %s_u32;\n" n;
        pr "  unsigned int %s; /* really uint32_t */\n" n
@@ -3914,7 +3916,10 @@ let print_python_binding name { args; ret } =
        pr "  long long %s; /* really int64_t */\n" n
     | Mutable arg ->
        pr "  PyObject *%s;\n" (List.hd (name_of_arg arg))
-    | Opaque _ -> ()
+    | OpaqueAndCallbacks (n, _) ->
+       pr "  struct %s_data _%s, *%s = &_%s;\n" name n n n
+    | OpaqueAndCallbacksPersist (n, _) ->
+       pr "  struct %s_data *%s;\n" name n
     | Path n ->
        pr "  PyObject *py_%s = NULL;\n" n;
        pr "  char *%s = NULL;\n" n
@@ -3946,17 +3951,16 @@ let print_python_binding name { args; ret } =
     | BytesPersistIn _
     | BytesOut _
     | BytesPersistOut _
-    | Callback _ -> ()
-    | CallbackPersist (n, _) ->
-       pr "  %s_data = malloc (sizeof *%s_data);\n" n n;
-       pr "  if (%s_data == NULL) {\n" n;
-       pr "    PyErr_NoMemory ();\n";
-       pr "    return NULL;\n";
-       pr "  }\n"
     | Flags _
     | Int _
     | Int64 _
-    | Opaque _
+    | OpaqueAndCallbacks _ -> ()
+    | OpaqueAndCallbacksPersist (n, _) ->
+       pr "  %s = malloc (sizeof *%s);\n" n n;
+       pr "  if (%s == NULL) {\n" n;
+       pr "    PyErr_NoMemory ();\n";
+       pr "    return NULL;\n";
+       pr "  }\n"
     | Mutable _
     | Path _
     | SockAddrAndLen _
@@ -3977,12 +3981,13 @@ let print_python_binding name { args; ret } =
     | BytesPersistIn (n, _) -> pr " \"O\""
     | BytesOut (_, count) -> pr " \"n\""
     | BytesPersistOut (_, count) -> pr " \"O\""
-    | Callback (n, _) | CallbackPersist (n, _) -> pr " \"O\""
     | Flags n -> pr " \"I\""
     | Int n -> pr " \"i\""
     | Int64 n -> pr " \"L\""
     | Mutable _ -> pr " \"O\""
-    | Opaque _ -> pr " \"O\""
+    | OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+       pr " \"O\"";
+       List.iter (fun _ -> pr " \"O\"") cbs
     | Path n -> pr " \"O&\""
     | SockAddrAndLen (n, _) -> pr " \"O\""
     | String n -> pr " \"s\""
@@ -4002,12 +4007,13 @@ let print_python_binding name { args; ret } =
     | BytesIn (n, _) | BytesPersistIn (n, _)
     | BytesPersistOut (n, _) -> pr ", &%s" n
     | BytesOut (_, count) -> pr ", &%s" count
-    | Callback (n, _) | CallbackPersist (n, _) -> pr ", &%s_data->fn" n
     | Flags n -> pr ", &%s" n
     | Int n -> pr ", &%s" n
     | Int64 n -> pr ", &%s" n
     | Mutable arg -> pr ", &%s" (List.hd (name_of_arg arg))
-    | Opaque n -> pr ", &%s_data->data" (find_callback n)
+    | OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+       pr ", &%s->data" n;
+       List.iter (fun cb -> pr ", &%s->%s" n cb.name) cbs
     | Path n -> pr ", PyUnicode_FSConverter, &py_%s" n
     | SockAddrAndLen (n, _) -> pr ", &%s" n
     | String n -> pr ", &%s" n
@@ -4046,19 +4052,20 @@ let print_python_binding name { args; ret } =
        pr "  %s = malloc (%s);\n" n count
     | BytesPersistIn (n, _) | BytesPersistOut (n, _) ->
        pr "  %s_buf = nbd_internal_py_get_aio_buffer (%s);\n" n n
-    | Callback (n, _) | CallbackPersist (n, _) ->
-       pr "  if (!PyCallable_Check (%s_data->fn)) {\n" n;
-       pr "    PyErr_SetString (PyExc_TypeError,\n";
-       pr "                     \"callback parameter %s is not callable\");\n"
-          n;
-       pr "    return NULL;\n";
-       pr "  }\n"
     | Flags n -> pr "  %s_u32 = %s;\n" n n
     | Int _ -> ()
     | Int64 n -> pr "  %s_i64 = %s;\n" n n
     | Mutable _ ->
        pr "  abort (); /* Mutable for normal Python parameters not impl */\n"
-    | Opaque n -> ()
+    | OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+       List.iter (fun cb ->
+         pr "  if (!PyCallable_Check (%s->%s)) {\n" n cb.name;
+         pr "    PyErr_SetString (PyExc_TypeError,\n";
+         pr "                     \"callback parameter %s is not callable\");\n"
+            cb.name;
+         pr "    return NULL;\n";
+         pr "  }\n"
+       ) cbs
     | Path n ->
        pr "  %s = PyBytes_AS_STRING (py_%s);\n" n n;
        pr "  assert (%s != NULL);\n" n
@@ -4084,12 +4091,13 @@ let print_python_binding name { args; ret } =
     | BytesOut (n, count) -> pr ", %s, %s" n count
     | BytesPersistIn (n, _)
     | BytesPersistOut (n, _) -> pr ", %s_buf->data, %s_buf->len" n n
-    | Callback (n, _) | CallbackPersist (n, _) -> pr ", %s_%s_wrapper" name n
     | Flags n -> pr ", %s_u32" n
     | Int n -> pr ", %s" n
     | Int64 n -> pr ", %s_i64" n
     | Mutable arg -> pr ", /* XXX */ (void *) %s" (List.hd (name_of_arg arg))
-    | Opaque n -> pr ", %s_data" (find_callback n)
+    | OpaqueAndCallbacks (n, cbs) | OpaqueAndCallbacksPersist (n, cbs) ->
+       pr ", %s" n;
+       List.iter (fun cb -> pr ", %s_%s_wrapper" name cb.name) cbs
     | Path n -> pr ", %s" n
     | SockAddrAndLen (n, _) -> pr ", /* XXX */ (void *) %s, 0" n
     | String n -> pr ", %s" n
@@ -4119,12 +4127,11 @@ let print_python_binding name { args; ret } =
     | Bool _
     | BytesIn _
     | BytesPersistIn _ | BytesPersistOut _
-    | Callback _ | CallbackPersist _
     | Flags _
     | Int _
     | Int64 _
     | Mutable _
-    | Opaque _
+    | OpaqueAndCallbacks _ | OpaqueAndCallbacksPersist _
     | Path _
     | SockAddrAndLen _
     | String _
@@ -4162,15 +4169,14 @@ let print_python_binding name { args; ret } =
     | Bool _ -> ()
     | BytesIn (n, _) -> pr "  PyBuffer_Release (&%s);\n" n
     | BytesPersistIn _ | BytesOut _ | BytesPersistOut _ -> ()
-    | Callback _ -> ()
-    | CallbackPersist (n, _) ->
-       pr "  /* This ensures the callback data is freed eventually. */\n";
-       pr "  nbd_add_close_callback (h, free, %s_data);\n" n
     | Flags _ -> ()
     | Int _ -> ()
     | Int64 _ -> ()
     | Mutable _ -> ()
-    | Opaque _ -> ()
+    | OpaqueAndCallbacks _ -> ()
+    | OpaqueAndCallbacksPersist (n, _) ->
+       pr "  /* This ensures the callback data is freed eventually. */\n";
+       pr "  nbd_add_close_callback (h, free, %s);\n" n
     | Path n ->
        pr "  Py_XDECREF (py_%s);\n" n
     | SockAddrAndLen _ -> ()
@@ -4312,12 +4318,13 @@ class NBD (object):
                      | BytesIn (n, _) | BytesPersistIn (n, _) -> n, None
                      | BytesPersistOut (n, _) -> n, None
                      | BytesOut (_, count) -> count, None
-                     | Callback (n, _) | CallbackPersist (n, _) -> n, None
                      | Flags n -> n, Some "0"
                      | Int n -> n, None
                      | Int64 n -> n, None
                      | Mutable arg -> List.hd (name_of_arg arg), None
-                     | Opaque n -> n, None
+                     | OpaqueAndCallbacks (n, cbs)
+                     | OpaqueAndCallbacksPersist (n, cbs) ->
+                        n ^ ", " ^ String.concat ", " (List.map (fun cb -> cb.name) cbs), None
                      | Path n -> n, None
                      | SockAddrAndLen (n, _) -> n, None
                      | String n -> n, None
@@ -4399,16 +4406,12 @@ and ocaml_arg_to_string = function
   | OCamlArg (BytesPersistIn _) -> "Buffer.t"
   | OCamlArg (BytesOut _) -> "bytes"
   | OCamlArg (BytesPersistOut _) -> "Buffer.t"
-  | OCamlArg (Callback (_, args))
-  | OCamlArg (CallbackPersist (_, args)) ->
-     sprintf "(%s)"
-             (ocaml_fundecl_to_string (List.map (fun a -> OCamlArg a) args)
-                                      RErr)
   | OCamlArg (Flags _) -> assert false (* see above *)
   | OCamlArg (Int _) -> "int"
   | OCamlArg (Int64 _) -> "int64"
   | OCamlArg (Mutable arg) -> ocaml_arg_to_string (OCamlArg arg) ^ " ref"
-  | OCamlArg (Opaque n) -> sprintf "'%s" n
+  | OCamlArg (OpaqueAndCallbacks _) | OCamlArg (OpaqueAndCallbacksPersist _) ->
+     sprintf "string" (* XXX not impl *)
   | OCamlArg (Path _) -> "string"
   | OCamlArg (SockAddrAndLen _) -> "string" (* XXX not impl *)
   | OCamlArg (String _) -> "string"
@@ -4574,22 +4577,13 @@ external close : t -> unit = \"nbd_internal_ocaml_nbd_close\"

 let print_ocaml_binding (name, { args; ret }) =
   (* Functions with a callback parameter require special handling. *)
-  let find_callback opaque_id =
-    try
-      List.find (
-        function
-        | Callback (_, args) | CallbackPersist (_, args) ->
-           List.mem (Opaque opaque_id) args
-        | _ -> false
-      ) args
-    with
-      Not_found ->
-      failwithf "%s: couldn't find callback associated with Opaque %s"
-                name opaque_id
-  in

   List.iter (
     function
+    | OpaqueAndCallbacks (cb_name, cbs)
+    | OpaqueAndCallbacksPersist (cb_name, cbs) ->
+       pr " /* Callbacks not implemented yet... */\n"
+      (*
     | Callback (cb_name, args) | CallbackPersist (cb_name, args) ->
        let argnames =
          List.map (
@@ -4642,7 +4636,7 @@ let print_ocaml_binding (name, { args; ret }) =
             pr "  %sv = *_%s->data;\n" n n
          | Mutable (Int n) ->
             pr "  %sv = caml_alloc_tuple (1);\n" n;
-            pr "  Store_field (%sv, 0, Val_int (*%s));\n" n n
+            pr "  Store_field (%sv, 0, Val_int (" ^ "*%s));\n" n n
          (* The following not yet implemented for callbacks XXX *)
          | ArrayAndLen _ | Bool _ | BytesOut _
          | BytesPersistIn _ | BytesPersistOut _
@@ -4694,7 +4688,8 @@ let print_ocaml_binding (name, { args; ret }) =
        pr "  caml_enter_blocking_section ();\n";
        pr "  return ret;\n";
        pr "}\n"
-    | _ -> ()
+       *)
+     | _ -> ()
   ) args;

   (* Convert the generic args to OCaml args. *)
@@ -4760,6 +4755,7 @@ let print_ocaml_binding (name, { args; ret }) =
        pr "  struct nbd_buffer %s_buf = NBD_buffer_val (%sv);\n" n n;
        pr "  void *%s = %s_buf.data;\n" n n;
        pr "  size_t %s = %s_buf.len;\n" count n
+       (*
     | OCamlArg (Callback (n, _)) ->
        pr "  /* This is safe because we only call this while this stack\n";
        pr "   * frame is live.\n";
@@ -4777,12 +4773,14 @@ let print_ocaml_binding (name, { args; ret }) =
        pr "  nbd_add_close_callback (h, nbd_internal_ocaml_free_root, %s_cb);\n"
           n;
        pr "  const void *%s = %s_%s_wrapper;\n" n name n
+        *)
     | OCamlArg (Flags _) -> assert false (* see above *)
     | OCamlArg (Int n) ->
        pr "  int %s = Int_val (%sv);\n" n n
     | OCamlArg (Int64 n) ->
        pr "  int64_t %s = Int64_val (%sv);\n" n n
     | OCamlArg (Mutable _) -> assert false
+      (*
     | OCamlArg (Opaque n) ->
        (match find_callback n with
         | Callback (cb_name, _) ->
@@ -4801,6 +4799,9 @@ let print_ocaml_binding (name, { args; ret }) =
            pr "  nbd_add_close_callback (h, nbd_internal_ocaml_free_root, %s_data);\n" n
         | _ -> assert false
        )
+       *)
+    | OCamlArg (OpaqueAndCallbacks _) | OCamlArg (OpaqueAndCallbacksPersist _) ->
+       pr "  /* callbacks not implemented yet */\n"
     | OCamlArg (Path n) | OCamlArg (String n) ->
        pr "  const char *%s = String_val (%sv);\n" n n
     | OCamlArg (SockAddrAndLen (n, len)) ->
@@ -4818,6 +4819,7 @@ let print_ocaml_binding (name, { args; ret }) =
   ) oargs;

   (* Create wrapper data for callbacks. *)
+  (*
   List.iter (
     function
     | OCamlArg (Opaque n) ->
@@ -4836,6 +4838,7 @@ let print_ocaml_binding (name, { args; ret }) =
        )
     | _ -> ()
   ) oargs;
+   *)

   let errcode =
     match ret with
@@ -4877,13 +4880,12 @@ let print_ocaml_binding (name, { args; ret }) =
     | OCamlArg (BytesPersistIn _)
     | OCamlArg (BytesOut _)
     | OCamlArg (BytesPersistOut _)
-    | OCamlArg (Callback _)
-    | OCamlArg (CallbackPersist _)
     | OCamlArg (Flags _)
     | OCamlArg (Int _)
     | OCamlArg (Int64 _)
     | OCamlArg (Mutable _)
-    | OCamlArg (Opaque _)
+    | OCamlArg (OpaqueAndCallbacks _)
+    | OCamlArg (OpaqueAndCallbacksPersist _)
     | OCamlArg (Path _)
     | OCamlArg (String _)
     | OCamlArg (SockAddrAndLen _)
-- 
2.20.1




More information about the Libguestfs mailing list