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