-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathport_wrapper.erl
More file actions
65 lines (57 loc) · 2.1 KB
/
port_wrapper.erl
File metadata and controls
65 lines (57 loc) · 2.1 KB
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
-module(port_wrapper).
-export([wrap/1, wrap/2, wrap_link/1, wrap_link/2, send/2, shutdown/1, close/1, rpc/2]).
wrap(Command) ->
spawn(fun() -> process_flag(trap_exit, true), Port = create_port(Command), loop(Port, infinity, Command) end).
wrap(Command, Timeout) ->
spawn(fun() -> process_flag(trap_exit, true), Port = create_port(Command), loop(Port, Timeout, Command) end).
wrap_link(Command) ->
spawn_link(fun() -> process_flag(trap_exit, true), Port = create_port(Command), link(Port), loop(Port, infinity, Command) end).
wrap_link(Command, Timeout) ->
spawn_link(fun() -> process_flag(trap_exit, true), Port = create_port(Command), link(Port), loop(Port, Timeout, Command) end).
rpc(WrappedPort, Message) ->
send(WrappedPort, Message),
receive
{WrappedPort, Result} -> {ok, Result}
end.
send(WrappedPort, Message) ->
WrappedPort ! {self(), {command, Message}},
WrappedPort.
shutdown(WrappedPort) ->
WrappedPort ! shutdown,
true.
close(WrappedPort) ->
WrappedPort ! noose,
true.
create_port(Command) ->
open_port({spawn, Command}, [{packet, 4}, nouse_stdio, exit_status, binary]).
loop(Port, Timeout, Command) ->
receive
noose ->
port_close(Port),
noose;
shutdown ->
port_close(Port),
exit(shutdown);
{Source, {command, Message}} ->
Port ! {self(), {command, Message}},
receive
{Port, {data, Result}} ->
Source ! {self(), Result}
after Timeout ->
error_logger:error_msg("Port Wrapper ~p timed out in mid operation (~p)!~n", [self(),Message]),
% We timed out, which means we need to close and then restart the port
port_close(Port), % Should SIGPIPE the child.
exit(timed_out)
end,
loop(Port,Timeout,Command);
{Port, {exit_status, _Code}} ->
% Hard and Unanticipated Crash
error_logger:error_msg( "Port closed! ~p~n", [Port] ),
exit({error, _Code});
{'EXIT',_Pid,shutdown} ->
port_close(Port),
exit(shutdown);
Any ->
error_logger:warning_msg("PortWrapper ~p got unexpected message: ~p~n", [self(), Any]),
loop(Port, Timeout, Command)
end.