summaryrefslogtreecommitdiff
path: root/deps/rexi/src/rexi_monitor.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/rexi/src/rexi_monitor.erl')
-rw-r--r--deps/rexi/src/rexi_monitor.erl66
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.