Let's call it modern_ret_as_list as opposed to single_ret_as_list. The
latter was able to return list of things. However the new, more modern,
version came and it is used since listAllDomains till nowadays in
ListServers.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/rpc/gendispatch.pl | 200 ++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 172 insertions(+), 28 deletions(-)
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 29f2c6ac033b..d6ce9b85e158 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -617,6 +617,9 @@ elsif ($mode eq "server") {
my $single_ret_list_max_var = "undefined";
my $single_ret_list_max_define = "undefined";
my $multi_ret = 0;
+ my $modern_ret_as_list = 0;
+ my $modern_ret_struct_name = "undefined";
+ my $single_ret_list_error_msg_type = "undefined";
if ($rettype ne "void" and
scalar(@{$call->{ret_members}}) > 1) {
@@ -633,7 +636,16 @@ elsif ($mode eq "server") {
push(@ret_list, "memcpy(ret->$3, tmp.$3,
sizeof(ret->$3));");
} elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper)
(\S+);/) {
- push(@ret_list, "ret->$3 = tmp.$3;");
+ if (!$modern_ret_as_list) {
+ push(@ret_list, "ret->$3 = tmp.$3;");
+ }
+ } elsif ($ret_member =~ m/admin_nonnull_(server)
(\S+)<(\S+)>;/) {
+ $modern_ret_struct_name = $1;
+ $single_ret_list_error_msg_type = $1;
+ $single_ret_list_name = $2;
+ $single_ret_list_max_define = $3;
+
+ $modern_ret_as_list = 1;
} else {
die "unhandled type for multi-return-value:
$ret_member";
}
@@ -817,27 +829,43 @@ elsif ($mode eq "server") {
# select struct type for multi-return-value functions
if ($multi_ret) {
- if (!(defined $call->{ret_offset})) {
- die "multi-return-value without insert@<offset> annotation:
$call->{ret}";
- }
+ if (defined $call->{ret_offset}) {
+ push_privconn(\@args_list);
- push_privconn(\@args_list);
+ if ($modern_ret_as_list) {
+ my $struct_name = name_to_TypeName($modern_ret_struct_name);
- my $struct_name = $call->{ProcName};
- $struct_name =~ s/Get//;
+ if ($structprefix eq "admin") {
+ $struct_name = "Net${struct_name}";
+ }
- splice(@args_list, $call->{ret_offset}, 0, ("&tmp"));
+ push(@vars_list, "vir${struct_name}Ptr *result = NULL");
+ push(@vars_list, "int nresults = 0");
- if ($call->{ProcName} eq "DomainBlockStats" ||
- $call->{ProcName} eq "DomainInterfaceStats") {
- # SPECIAL: virDomainBlockStats and virDomainInterfaceStats
- # have a 'Struct' suffix on the actual struct name
- # and take the struct size as additional argument
- $struct_name .= "Struct";
- splice(@args_list, $call->{ret_offset} + 1, 0,
("sizeof(tmp)"));
- }
+ @args_list = grep {!/\bneed_results\b/} @args_list;
- push(@vars_list, "vir$struct_name tmp");
+ splice(@args_list, $call->{ret_offset}, 0,
+ ("args->need_results ? &result : NULL"));
+ } else {
+ my $struct_name = $call->{ProcName};
+ $struct_name =~ s/Get//;
+
+ splice(@args_list, $call->{ret_offset}, 0,
("&tmp"));
+
+ if ($call->{ProcName} eq "DomainBlockStats" ||
+ $call->{ProcName} eq "DomainInterfaceStats") {
+ # SPECIAL: virDomainBlockStats and virDomainInterfaceStats
+ # have a 'Struct' suffix on the actual struct
name
+ # and take the struct size as additional argument
+ $struct_name .= "Struct";
+ splice(@args_list, $call->{ret_offset} + 1, 0,
("sizeof(tmp)"));
+ }
+
+ push(@vars_list, "vir$struct_name tmp");
+ }
+ } else {
+ die "multi-return-value without insert@<offset> annotation:
$call->{ret}";
+ }
}
if ($call->{streamflag} ne "none") {
@@ -868,6 +896,10 @@ elsif ($mode eq "server") {
print "{\n";
print " int rv = -1;\n";
+ if ($modern_ret_as_list) {
+ print " size_t i;\n";
+ }
+
foreach my $var (@vars_list) {
print " $var;\n";
}
@@ -974,9 +1006,17 @@ elsif ($mode eq "server") {
print " goto cleanup;\n";
print "\n";
} else {
- print " if (vir$call->{ProcName}(";
- print join(', ', @args_list);
- print ") < 0)\n";
+ if ($modern_ret_as_list) {
+ print " if ((nresults = \n";
+ my $indln = " $prefix$call->{ProcName}(";
+ print $indln;
+ print join(",\n" . ' ' x (length $indln), @args_list);
+ print ")) < 0)\n";
+ } else {
+ print " if ($prefix$call->{ProcName}(";
+ print join(', ', @args_list);
+ print ") < 0)\n";
+ }
print " goto cleanup;\n";
print "\n";
}
@@ -995,6 +1035,29 @@ elsif ($mode eq "server") {
print "\n";
}
+ if ($modern_ret_as_list) {
+ print " if (nresults > $single_ret_list_max_define) {\n";
+ print " virReportError(VIR_ERR_INTERNAL_ERROR,\n";
+ print " _(\"Too many
${single_ret_list_error_msg_type}s '%d' for limit '%d'\"),\n";
+ print " nresults,
$single_ret_list_max_define);\n";
+ print " goto cleanup;\n";
+ print " }\n";
+ print "\n";
+ print " if (result && nresults) {\n";
+ print " if
(VIR_ALLOC_N(ret->$single_ret_list_name.${single_ret_list_name}_val, nresults) <
0)\n";
+ print " goto cleanup;\n";
+ print "\n";
+ print " ret->$single_ret_list_name.${single_ret_list_name}_len
= nresults;\n";
+ print " for (i = 0; i < nresults; i++)\n";
+ print "
make_nonnull_$modern_ret_struct_name(ret->$single_ret_list_name.${single_ret_list_name}_val
+ i, result[i]);\n";
+ print " } else {\n";
+ print " ret->$single_ret_list_name.${single_ret_list_name}_len
= 0;\n";
+ print " ret->$single_ret_list_name.${single_ret_list_name}_val
= NULL;\n";
+ print " }\n";
+ print "\n";
+ print " ret->ret = nresults;\n";
+ }
+
if (@prepare_ret_list) {
print " ";
print join("\n ", @prepare_ret_list);
@@ -1030,6 +1093,14 @@ elsif ($mode eq "server") {
print "\n";
}
+ if ($modern_ret_as_list) {
+ print " if (result) {\n";
+ print " for (i = 0; i < nresults; i++)\n";
+ print " virObjectUnref(result[i]);\n";
+ print " }\n";
+ print " VIR_FREE(result);\n";
+ }
+
print " return rv;\n";
print "}\n\n\n\n";
}
@@ -1277,6 +1348,9 @@ elsif ($mode eq "client") {
my $single_ret_list_max_define = "undefined";
my $single_ret_cleanup = 0;
my $multi_ret = 0;
+ my $modern_ret_as_list = 0;
+ my $modern_ret_struct_name = 0;
+ my $modern_ret_var_type = "undefined";
if ($rettype ne "void" and
scalar(@{$call->{ret_members}}) > 1) {
@@ -1296,6 +1370,20 @@ elsif ($mode eq "client") {
}
push(@ret_list, "memcpy(result->$3, ret.$3,
sizeof(result->$3));");
+ } elsif ($ret_member =~ m/admin_nonnull_(server)
(\S+)<(\S+)>;/) {
+ my $proc_name = name_to_TypeName($1);
+
+ if ($structprefix eq "admin") {
+ $modern_ret_var_type = "virAdm${proc_name}Ptr";
+ } else {
+ $modern_ret_var_type = "vir${proc_name}Ptr";
+ }
+
+ $modern_ret_struct_name = $1;
+ $single_ret_list_name = $2;
+ $single_ret_list_max_var = $3;
+
+ $modern_ret_as_list = 1;
} elsif ($ret_member =~ m/<\S+>;/ or $ret_member =~
m/\[\S+\];/) {
# just make all other array types fail
die "unhandled type for multi-return-value for " .
@@ -1305,7 +1393,7 @@ elsif ($mode eq "client") {
my $sign = ""; $sign = "U" if ($1);
push(@ret_list, "HYPER_TO_${sign}LONG(result->$3,
ret.$3);");
- } else {
+ } elsif (!$modern_ret_as_list) {
push(@ret_list, "result->$3 = ret.$3;");
}
} else {
@@ -1434,16 +1522,40 @@ elsif ($mode eq "client") {
}
}
+ if ($modern_ret_as_list) {
+ # clear arguments and setters we don't want in this code
+ @args_list = grep {!/\bneed_results\b/} @args_list;
+ @setters_list = grep {!/\bneed_results\b/} @setters_list;
+
+ push(@vars_list, "${modern_ret_var_type} *tmp_results = NULL");
+ push(@setters_list, "args.need_results = !!result;");
+
+ $single_ret_var = "int rv = -1";
+ $single_ret_type = "int";
+ }
+
# select struct type for multi-return-value functions
if ($multi_ret) {
+ my $struct_name = "undefined";
+
if (!(defined $call->{ret_offset})) {
die "multi-return-value without insert@<offset> annotation:
$call->{ret}";
}
- my $struct_name = $call->{ProcName};
- $struct_name =~ s/Get//;
+ if ($modern_ret_as_list) {
+ $struct_name = name_to_TypeName($modern_ret_struct_name);
+
+ $struct_name .= "Ptr **";
+ if ($structprefix eq "admin") {
+ $struct_name = "Adm${struct_name}";
+ }
+ } else {
+ $struct_name = $call->{ProcName};
- splice(@args_list, $call->{ret_offset}, 0, ("vir${struct_name}Ptr
result"));
+ $struct_name =~ s/Get//;
+ $struct_name = "${struct_name}Ptr "
+ }
+ splice(@args_list, $call->{ret_offset}, 0, ("vir$struct_name
result"));
}
if ($call->{streamflag} ne "none") {
@@ -1482,7 +1594,8 @@ elsif ($mode eq "client") {
print " $var;\n";
}
- if ($single_ret_as_list) {
+ if ($single_ret_as_list or
+ $modern_ret_as_list) {
print " size_t i;\n";
}
@@ -1595,7 +1708,8 @@ elsif ($mode eq "client") {
print " }\n";
print "\n";
- if ($single_ret_as_list) {
+ if ($single_ret_as_list or
+ $modern_ret_as_list) {
print " if (ret.$single_ret_list_name.${single_ret_list_name}_len
> $single_ret_list_max_var) {\n";
print " virReportError(VIR_ERR_RPC,\n";
print " _(\"too many remote
${single_ret_list_error_msg_type}s: %d > %d\"),\n";
@@ -1603,6 +1717,9 @@ elsif ($mode eq "client") {
print " goto cleanup;\n";
print " }\n";
print "\n";
+ }
+
+ if ($single_ret_as_list) {
print " /* This call is caller-frees (although that isn't clear
from\n";
print " * the documentation). However xdr_free will free up both
the\n";
print " * names and the list of pointers, so we have to VIR_STRDUP
the\n";
@@ -1618,8 +1735,23 @@ elsif ($mode eq "client") {
print " }\n";
print " }\n";
print "\n";
+ } elsif ($modern_ret_as_list) {
+ print " if (result) {\n";
+ print " if (VIR_ALLOC_N(tmp_results,
ret.$single_ret_list_name.${single_ret_list_name}_len + 1) < 0)\n";
+ print " goto cleanup;\n";
+ print "\n";
+ print " for (i = 0; i <
ret.$single_ret_list_name.${single_ret_list_name}_len; i++) {\n";
+ print " tmp_results[i] =
get_nonnull_$modern_ret_struct_name($priv_src,
ret.$single_ret_list_name.${single_ret_list_name}_val[i]);\n";
+ print " if (!tmp_results[i])\n";
+ print " goto cleanup;\n";
+ print " }\n";
+ print " *result = tmp_results;\n";
+ print " tmp_results = NULL;\n";
+ print " }\n";
+ print "\n";
}
+
if (@ret_list2) {
print " ";
print join("\n ", @ret_list2);
@@ -1641,12 +1773,24 @@ elsif ($mode eq "client") {
}
if ($multi_ret or !@ret_list) {
- print " rv = 0;\n";
+ if ($modern_ret_as_list) {
+ print " rv = ret.ret;\n";
+ } else {
+ print " rv = 0;\n";
+ }
}
- if ($single_ret_as_list or $single_ret_cleanup) {
+ if ($single_ret_as_list or $single_ret_cleanup or $modern_ret_as_list) {
print "\n";
print "cleanup:\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";
+ print " virObjectUnref(tmp_results[i]);\n";
+ print " VIR_FREE(tmp_results);\n";
+ print " }\n";
+ print "\n";
+ }
print " xdr_free((xdrproc_t)xdr_$call->{ret}, (char
*)&ret);\n";
}
--
2.7.2