/usr/share/octave/packages/parallel-3.1.1/rfeval.m is in octave-parallel 3.1.1-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | ## Copyright (C) 2015, 2016 Olaf Till <i7tiol@t-online.de>
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 3 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, see <http://www.gnu.org/licenses/>.
## -*- texinfo -*-
## @deftypefn{Function File} {} rfeval (@var{func}, @dots{}, @var{nout}, @var{isout}, @var{connection})
## Evaluate a function at a remote machine.
##
## @var{func} is evaluated with arguments @code{@dots{}} and number of
## output arguments set to @var{nout} at remote machine given by
## @var{connection}. If @var{isout} is not empty, it must be a logical
## array with @var{nout} elements, which are true for each of the
## @var{nout} output arguments which are requested from the function;
## the other output arguments will be marked as not requested
## with @code{~} at remote execution.
##
## This function can only be successfully called at the client machine.
## See @code{pconnect} for a description of the @var{connection}
## variable. @var{connection} must contain one single connection.
##
## If an output argument is given to @code{rfeval}, the function waits
## for completion of the remote function call, retrieves the results and
## returns them. They will be returned as one cell-array with an entry
## for each output argument. If some output arguments are marked as not
## requested by setting some elements of @var{isout} to false, the
## returned cell-array will only have entries for the requested output
## arguments. For consistency, the returned cell-array can be empty. To
## assign the output arguments to single variables, you can for example
## use: @code{[a, b, c] = returned_cell_array@{:@};}.
##
## If no output argument is given to @code{rfeval}, the function does
## not retrieve the results of the remote function call but returns
## immediately. It is left to the user to retrieve the results with
## @code{precv}. The results will be in the same format as if returned
## by @code{rfeval}. Note that a cell-array, possibly empty, will always
## have to be retrieved, even if the remote function call should have
## been performed without output arguments.
##
## Parallel execution can be achieved by calling @code{rfeval} several
## times with different specified server machines before starting to
## retrieve the results.
##
## The specified function handle can refer to a function present at the
## executing machine or be an anonymous function. In the latter case,
## the function specification sent to the server includes the anonymous
## functions context (generation of the sent function specification is
## implemented in the Octave core). Sending a handle to a subfunction,
## however, will currently not work. Sending a handle to a private
## function will only work if its file path is the same at the server.
## Sending an anonymous function using "varargin" in the argument list
## will currently not work.
##
## @seealso{pconnect, pserver, sclose, install_vars, netcellfun}
## @end deftypefn
function ret = rfeval (varargin)
if ((nargs = nargin ()) < 4)
print_usage ();
endif
fname = "rfeval";
if (! isa (conn = varargin{end}, "pconnections"))
error ("%s: `connection' must be a parallel connections object", fname);
elseif (numel (conn) != 1)
error ("%s: exactly one connection must be specified", fname);
elseif (network_get_info (conn).local_machine)
error ("%s: client was specified instead of server");
## reval() checks if specified at server side
endif
if (! is_function_handle (varargin{1}))
error ("%s: `func' must be a function handle", fname);
endif
if (! isnumeric (nout = varargin{end - 2}) || ! isscalar (nout) || ...
(nout = round (nout)) < 0)
error ("%s: `nout' must be a non-negative integer", fname);
endif
if (isempty (isout = varargin{end - 1}))
isout = true (1, nout);
elseif (! islogical (isout) || numel (isout) != nout)
error ("%s: `isout' must be empty or a logical with `nout' elements",
fname);
endif
isout = isout(:);
## feval() isn't called remotely since it doesn't resepect ignoring of
## output variables with '~'. So the function handle has to be sent
## separately and a remote temporary variable has to be used for it.
##
## rargs = varargin(1 : end - 3); # could be used with feval
func = varargin{1};
rargs = varargin(2 : end - 3);
if (any (ign = ! isout))
rout = repmat ({"__pserver_tout__{%i},"}, nout, 1);
rout(ign) = {"~,"};
rout = cstrcat (rout{:});
rout = sprintf (rout, 1 : sum (isout));
rout = rout(1 : end - 1); # remove final ','
rout = sprintf ("[%s]", rout);
if (all (ign))
init_rout = "__pserver_tout__ = {}; ";
else
init_rout = "";
endif
else
rout = sprintf ("[__pserver_tout__{1:%i}]", nout);
init_rout = "";
endif
cmd = sprintf ...
("__pserver_tfunc__ = precv (sockets(1)); %s%s = __pserver_tfunc__ (precv (sockets(1)){:}); psend (__pserver_tout__, sockets(1)); clear ('__pserver_tout__');",
init_rout, rout);
reval (cmd, conn);
ready = false;
unwind_protect
psend (func, conn);
psend (rargs, conn);
ready = true;
unwind_protect_cleanup
if (! ready)
sclose (conns); # might already be closed from within reval or psend
endif
end_unwind_protect
if (nargout () > 0)
ret = precv (conn);
endif
endfunction
|