[libvirt] [PATCH 1/7] rpcgen: Add support for generating funcs returning alloc'd typed params

Peter Krempa pkrempa at redhat.com
Mon Jun 20 14:34:15 UTC 2016


Since it's rather tedious to write the dispatchers for functions that
return an array of typed parameters (which are rather common) let's add
some rpcgen code to generate them.
---
 src/remote/remote_protocol.x |  5 +++++
 src/rpc/gendispatch.pl       | 45 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 0170c0c..cec6bd2 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -414,6 +414,11 @@ struct remote_domain_disk_error {
  * insert@<offset> comment to indicate the offset in the parameter list of
  * the function to be called.
  *
+ * For cases where the API allocates memory and fills the arguments (mostly
+ * typed parameters) a similar comment indicates the type and offset
+ * of the variable to be filled with the count of returned elements.
+ * alloc@<offset>@unsigned int@<count offset>
+ *
  * Dynamic opaque and remote_nonnull_string arrays can be annotated with an
  * optional typecast */

diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 5564b2e..173189c 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -862,6 +862,25 @@ elsif ($mode eq "server") {
                     $single_ret_var = $2;
                     $single_ret_by_ref = 0;
                     $single_ret_check = " == NULL";
+                } elsif ($ret_member =~ m/^remote_typed_param (\S+)<(\S+)>;\s*\/\*\s*alloc@(\d+)@([^@]+)@(\d+)\s*\*\//) {
+                    push(@vars_list, "virTypedParameterPtr $1 = NULL");
+                    push(@vars_list, "$4 $1_len = 0");
+
+                    $single_ret_by_ref = 1;
+                    $single_ret_var = undef;
+
+                    splice(@args_list, int($3), 0, "&$1");
+                    splice(@args_list, int($5), 0, "&$1_len");
+
+                    push(@ret_list, "if (virTypedParamsSerialize($1, $1_len,\n" .
+                                    "                                (virTypedParameterRemotePtr *) &ret->$1.$1_val,\n" .
+                                    "                                &ret->$1.$1_len,\n" .
+                                    "                                VIR_TYPED_PARAM_STRING_OKAY) < 0)\n" .
+                                    "        goto cleanup;\n");
+
+                    push(@free_list, "    virTypedParamsFree($1, $1_len);");
+                    push(@free_list_on_error, "virTypedParamsRemoteFree((virTypedParameterRemotePtr) ret->params.params_val,\n" .
+                                              "                                 ret->params.params_len);\n");
                 } elsif ($ret_member =~ m/^(\/)?\*/) {
                     # ignore comments
                 } else {
@@ -1422,6 +1441,7 @@ elsif ($mode eq "client") {
         my $modern_ret_as_list = 0;
         my $modern_ret_struct_name = "undefined";
         my $modern_ret_var_type = "undefined";
+        my @custom_error_cleanup = ();

         if ($rettype ne "void" and
             scalar(@{$call->{ret_members}}) > 1) {
@@ -1519,6 +1539,23 @@ elsif ($mode eq "client") {
                         $single_ret_var = "vir${type_name}Ptr rv = NULL";
                         $single_ret_type = "vir${type_name}Ptr";
                     }
+                } elsif ($ret_member =~ m/^remote_typed_param (\S+)<(\S+)>;\s*\/\*\s*alloc@(\d+)@([^@]+)@(\d+)\s*\*\//) {
+                    # handle self allocating arrays of typed parameters
+                    splice(@args_list, int($3), 0, ("virTypedParameterPtr *$1"));
+                    splice(@args_list, int($5), 0, ("$4 *n$1"));
+                    push(@vars_list, "virTypedParameterPtr ret_params = NULL");
+                    push(@vars_list, "int ret_nparams = 0");
+                    # virTypedParamsDeserialize allocates the array if @params is null
+                    push(@ret_list2, "if (virTypedParamsDeserialize((virTypedParameterRemotePtr) ret.$1.$1_val,\n" .
+                                     "                                  ret.$1.$1_len,\n" .
+                                     "                                  $2,\n" .
+                                     "                                  &ret_params,\n" .
+                                     "                                  &ret_nparams) < 0)\n" .
+                                     "        goto cleanup;\n");
+                    push(@ret_list2, "*$1 = ret_params;");
+                    push(@ret_list2, "*n$1 = ret_nparams;");
+                    push(@custom_error_cleanup, "virTypedParamsFree(ret_params, ret_nparams);\n");
+                    $single_ret_cleanup = 1;
                 } elsif ($ret_member =~ m/^remote_typed_param (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) {
                     splice(@args_list, int($3), 0, ("virTypedParameterPtr $1"));
                     push(@ret_list2, "if (virTypedParamsDeserialize((virTypedParameterRemotePtr) ret.$1.$1_val,\n" .
@@ -1530,7 +1567,7 @@ elsif ($mode eq "client") {
                     $single_ret_cleanup = 1;
                 } elsif ($ret_member =~ m/^remote_typed_param (\S+)<\S+>;/) {
                     # error out on unannotated arrays
-                    die "remote_typed_param array without insert@<offset> annotation: $ret_member";
+                    die "remote_typed_param array without insert at ... or alloc at ... annotation: $ret_member";
                 } elsif ($ret_member =~ m/^int (\S+);/) {
                     my $arg_name = $1;

@@ -1876,6 +1913,12 @@ elsif ($mode eq "client") {
         if ($single_ret_as_list or $single_ret_cleanup or $modern_ret_as_list) {
             print "\n";
             print "cleanup:\n";
+            if (@custom_error_cleanup) {
+                print "    if (rv != 0) {\n";
+                print "        ";
+                print join("\n        ", @custom_error_cleanup);
+                print "    }\n";
+            }
             if ($modern_ret_as_list) {
                 print "    if (tmp_results) {\n";
                 print "        for (i = 0; i < ret.$single_ret_list_name.${single_ret_list_name}_len; i++)\n";
-- 
2.8.3




More information about the libvir-list mailing list