4
%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
6
%% The contents of this file are subject to the Erlang Public License,
7
%% Version 1.1, (the "License"); you may not use this file except in
8
%% compliance with the License. You should have received a copy of the
9
%% Erlang Public License along with this software. If not, it can be
10
%% retrieved online at http://www.erlang.org/.
12
%% Software distributed under the License is distributed on an "AS IS"
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
%% the License for the specific language governing rights and limitations
20
%%% @doc Common Test Framework test execution control module.
22
%%% <p>This module is a proxy for calling and handling locks in
23
%%% common test hooks.</p>
25
-module(ct_hooks_lock).
27
-behaviour(gen_server).
30
-export([start/1, stop/1, request/0, release/0]).
32
%% gen_server callbacks
33
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
34
terminate/2, code_change/3]).
36
-define(SERVER, ?MODULE).
38
-record(state, { id, locked = false, requests = [] }).
40
%%%===================================================================
42
%%%===================================================================
44
%% @doc Starts the server
46
case gen_server:start({local, ?SERVER}, ?MODULE, Id, []) of
47
{error,{already_started, Pid}} ->
55
gen_server:call(?SERVER, {stop,Id})
56
catch exit:{noproc,_} ->
62
gen_server:call(?SERVER,{request,self()},infinity)
63
catch exit:{noproc,_} ->
69
gen_server:call(?SERVER,{release,self()})
70
catch exit:{noproc,_} ->
74
%%%===================================================================
75
%%% gen_server callbacks
76
%%%===================================================================
78
%% @doc Initiates the server
80
{ok, #state{ id = Id }}.
82
%% @doc Handling call messages
83
handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) ->
84
[gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs],
85
{stop, normal, stopped, State};
86
handle_call({stop,_Id}, _From, State) ->
87
{reply, stopped, State};
88
handle_call({request, Pid}, _From, #state{ locked = false,
89
requests = [] } = State) ->
90
Ref = monitor(process, Pid),
91
{reply, locked, State#state{ locked = {true, Pid, Ref}} };
92
handle_call({request, Pid}, From, #state{ requests = Reqs } = State) ->
93
{noreply, State#state{ requests = Reqs ++ [{From,Pid}] }};
94
handle_call({release, Pid}, _From, #state{ locked = {true, Pid, Ref},
95
requests = []} = State) ->
96
demonitor(Ref,[flush]),
97
{reply, unlocked, State#state{ locked = false }};
98
handle_call({release, Pid}, _From,
99
#state{ locked = {true, Pid, Ref},
100
requests = [{NextFrom,NextPid}|Rest]} = State) ->
101
demonitor(Ref,[flush]),
102
gen_server:reply(NextFrom,locked),
103
NextRef = monitor(process, NextPid),
104
{reply,unlocked,State#state{ locked = {true, NextPid, NextRef},
106
handle_call({release, _Pid}, _From, State) ->
107
{reply, not_locked, State}.
109
%% @doc Handling cast messages
110
handle_cast(_Msg, State) ->
113
%% @doc Handling all non call/cast messages
114
handle_info({'DOWN',Ref,process,Pid,_},
115
#state{ locked = {true, Pid, Ref},
116
requests = [{NextFrom,NextPid}|Rest] } = State) ->
117
gen_server:reply(NextFrom, locked),
118
NextRef = monitor(process, NextPid),
119
{noreply,State#state{ locked = {true, NextPid, NextRef},
122
%% @doc This function is called by a gen_server when it is about to terminate.
123
terminate(_Reason, _State) ->
126
%% @doc Convert process state when code is changed
127
code_change(_OldVsn, State, _Extra) ->
130
%% -------------------------------------------------------------------------
131
%% Internal Functions
132
%% -------------------------------------------------------------------------