diff options
Diffstat (limited to 'deps/rexi/src/rexi_monitor.erl')
-rw-r--r-- | deps/rexi/src/rexi_monitor.erl | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/deps/rexi/src/rexi_monitor.erl b/deps/rexi/src/rexi_monitor.erl new file mode 100644 index 00000000..ab33fb87 --- /dev/null +++ b/deps/rexi/src/rexi_monitor.erl @@ -0,0 +1,66 @@ +% Copyright 2010 Cloudant +% +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(rexi_monitor). +-export([start/1, stop/1]). + +-include_lib("eunit/include/eunit.hrl"). + +%% @doc spawn_links a process which monitors the supplied list of items and +%% returns the process ID. If a monitored process exits, the caller will +%% receive a {rexi_DOWN, MonitoringPid, DeadPid, Reason} message. +-spec start([pid() | atom() | {atom(),node()}]) -> pid(). +start(Procs) -> + Parent = self(), + Nodes = [node() | nodes()], + {Mon, Skip} = lists:partition(fun(P) -> should_monitor(P, Nodes) end, + Procs), + spawn_link(fun() -> + [notify_parent(Parent, P, noconnect) || P <- Skip], + [erlang:monitor(process, P) || P <- Mon], + wait_monitors(Parent) + end). + +%% @doc Cleanly shut down the monitoring process and flush all rexi_DOWN +%% messages from our mailbox. +-spec stop(pid()) -> ok. +stop(MonitoringPid) -> + MonitoringPid ! {self(), shutdown}, + flush_down_messages(). + +%% internal functions %% + +notify_parent(Parent, Pid, Reason) -> + erlang:send(Parent, {rexi_DOWN, self(), Pid, Reason}). + +should_monitor(Pid, Nodes) when is_pid(Pid) -> + lists:member(node(Pid), Nodes); +should_monitor({_, Node}, Nodes) -> + lists:member(Node, Nodes). + +wait_monitors(Parent) -> + receive + {'DOWN', _, process, Pid, Reason} -> + notify_parent(Parent, Pid, Reason), + wait_monitors(Parent); + {Parent, shutdown} -> + ok + end. + +flush_down_messages() -> + receive {rexi_DOWN, _, _, _} -> + flush_down_messages() + after 0 -> + ok + end. |