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@... or alloc@... 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list