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