1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(ct_hooks_lock). 22 23-behaviour(gen_server). 24 25%% API 26-export([start/1, stop/1, request/0, release/0]). 27 28%% gen_server callbacks 29-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 30 terminate/2, code_change/3]). 31 32-define(SERVER, ?MODULE). 33 34-record(state, { id, locked = false, requests = [] }). 35 36%%%=================================================================== 37%%% API 38%%%=================================================================== 39 40start(Id) -> 41 case gen_server:start({local, ?SERVER}, ?MODULE, Id, []) of 42 {error,{already_started, Pid}} -> 43 {ok,Pid}; 44 Else -> 45 Else 46 end. 47 48stop(Id) -> 49 try 50 gen_server:call(?SERVER, {stop,Id}) 51 catch exit:{noproc,_} -> 52 stopped 53 end. 54 55request() -> 56 try 57 gen_server:call(?SERVER,{request,self()},infinity) 58 catch exit:{noproc,_} -> 59 locked 60 end. 61 62release() -> 63 try 64 gen_server:call(?SERVER,{release,self()}) 65 catch exit:{noproc,_} -> 66 unlocked 67 end. 68 69%%%=================================================================== 70%%% gen_server callbacks 71%%%=================================================================== 72 73init(Id) -> 74 ct_util:mark_process(), 75 {ok, #state{ id = Id }}. 76 77handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) -> 78 _ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs], 79 {stop, normal, stopped, State}; 80handle_call({stop,_Id}, _From, State) -> 81 {reply, stopped, State}; 82handle_call({request, Pid}, _From, #state{ locked = false, 83 requests = [] } = State) -> 84 Ref = monitor(process, Pid), 85 {reply, locked, State#state{ locked = {true, Pid, Ref}} }; 86handle_call({request, Pid}, From, #state{ requests = Reqs } = State) -> 87 {noreply, State#state{ requests = Reqs ++ [{From,Pid}] }}; 88handle_call({release, Pid}, _From, #state{ locked = {true, Pid, Ref}, 89 requests = []} = State) -> 90 demonitor(Ref,[flush]), 91 {reply, unlocked, State#state{ locked = false }}; 92handle_call({release, Pid}, _From, 93 #state{ locked = {true, Pid, Ref}, 94 requests = [{NextFrom,NextPid}|Rest]} = State) -> 95 demonitor(Ref,[flush]), 96 gen_server:reply(NextFrom,locked), 97 NextRef = monitor(process, NextPid), 98 {reply,unlocked,State#state{ locked = {true, NextPid, NextRef}, 99 requests = Rest } }; 100handle_call({release, _Pid}, _From, State) -> 101 {reply, not_locked, State}. 102 103handle_cast(_Msg, State) -> 104 {noreply, State}. 105 106handle_info({'DOWN',Ref,process,Pid,_}, 107 #state{ locked = {true, Pid, Ref}, 108 requests = [{NextFrom,NextPid}|Rest] } = State) -> 109 gen_server:reply(NextFrom, locked), 110 NextRef = monitor(process, NextPid), 111 {noreply,State#state{ locked = {true, NextPid, NextRef}, 112 requests = Rest } }. 113 114terminate(_Reason, _State) -> 115 ok. 116 117code_change(_OldVsn, State, _Extra) -> 118 {ok, State}. 119 120%% ------------------------------------------------------------------------- 121%% Internal Functions 122%% ------------------------------------------------------------------------- 123