% Invoke ECLiPSe on all available machines and accept a hello message
% from them.
connect_machines :-
machine_list(List), % make a list of machines from ruptime
socket(internet, datagram, sigio(s)), % signal when data comes
bind(s, Address),
set_interrupt_handler(io, io_handler/0),
connect_machines(List, Address).
% As soon as a message arrives to the socket, the io signal will
% be sent and the handler reads the message.
io_handler :-
set_flag(enable_interrupts, off),
read_string(s, "\n", _, Message),
writeln(Message),
set_flag(enable_interrupts, on).
% Invoke eclipse on all machines with small load and let them execute
% the start/0 predicate
connect_machines([info(RHost, UpTime, Users, L1, _, _)|Rest], Host/Port) :-
UpTime > 0, % it is not down
L1 < 0.5, % load not too high
Users < 3, % not too many users
!,
concat_string(, Command),
exec(['rsh', RHost, 'eclipse', Host, Port, '-b',
'/home/lp/micha/sepia4/up.pl', '-e', 'start'], [], _),
connect_machines(Rest, Host/Port).
connect_machines([_|Rest], Address) :-
connect_machines(Rest, Address).
connect_machines([], _).
% ECLiPSe on remote hosts is invoked with
% eclipse host port -b file.pl -e start
% It connects to the socket of the main process,
% sends it a hello message and exits.
start :-
is_built_in(socket/3), % to ignore non-BSD machines
argv(1, SHost),
argv(2, SPort),
atom_string(Host, SHost),
number_string(Port, SPort),
get_flag(hostname, LHost),
socket(internet, datagram, s), % create the socket
connect(s, Host/Port), % connect to the main process
printf(s, "hello from %s\n%b", LHost).
% Invoke ruptime(1) and parse its output to a list of accessible
% machines in the form
% info(Host, UpTime, Users, Load1, Load2, Load3).
machine_list(List) :-
% exec/2 cannot be used as it could overflow
% the pipe and then block
exec(['ruptime', '-l'], [null, S], P),
parse_ruptime(S, List),
close(S),
wait(P, _),
!.
% Parse the output of ruptime
parse_ruptime(S, [Info|List]) :-
parse_uptime_record(S, Info),
!,
parse_ruptime(S, List).
parse_ruptime(_, []).
% parse one line of the ruptime output
parse_uptime_record(S, info(Host, Time, Users, Load1, Load2, Load3)) :-
read_token(S, Host, _),
Host \== end_of_file,
read_token(S, Up, _),
(Up == up ->
read_time(S, Time),
read_token(S, ',', _),
read_token(S, Users, _),
read_token(S, _, _),
read_token(S, ',', _),
read_token(S, load, _),
read_token(S, Load1, _),
read_token(S, ',', _),
read_token(S, Load2, _),
read_token(S, ',', _),
read_token(S, Load3, _)
;
read_time(S, _),
Time = 0
).
% Parse the up/down time and if the machine is down, return 0
read_time(S, Time) :-
read_token(S, T1, _),
(read_token(S, +, _) ->
Days = T1,
read_token(S, Hours, _),
read_token(S, :, _)
;
Days = 0,
Hours = T1
),
read_token(S, Mins, _),
Time is ((24 * Days) + Hours) * 60 + Mins.
and here is a script of the session: