%%%------------------------------------------------------------------- %%% @author Joe Zhao %%% @copyright (C) 2014, %%% @doc %%% This module serves the purpose of registering and monitoring different events %%% Whether they are periodic or oneshot. %%% Events are happening in a sense that none should be depending on those that happend before. %%% Spawning one with mutable state is thus not recommended and not supported in such modules. %%% Thus, the events are defined so that none of them would have states change during different invocations. %%% @end %%% Created : 27. 四月 2014 19:11 %%%------------------------------------------------------------------- -module(eventserv). -author("Joe Zhao"). -include("eventserv.hrl"). -compile([debug_info,export_all]). %% API %%-export([]). event(Pid,S) -> receive {_PPid,shutdown} -> io:format("I, ~p, am killed.\n",[S#event.name]) after S#event.period -> Pid ! {self(),run,S}, if S#event.spawn -> spawn(S#event.call,[self()]); true -> (S#event.call)(self()) end, case S#event.type of oneshot -> ok; periodic -> event(Pid,S); _Else -> ok end end. recloop(Events) -> receive {Pid,shutdown} -> [ Proc ! {self(),shutdown} || Proc<- orddict:fetch_keys(Events)]; {PPid,reg,S} -> Pid = spawn(?MODULE,event,[self(),S]), link(Pid), recloop(orddict:store(Pid,S,Events)); {Pid,run,S} -> io:format("Event run, type ~p: ~p\n",[S#event.type,S#event.name]), recloop(Events); {'EXIT',Pid,Cond} when Cond==normal;Cond==shutdown -> io:format("Event died naturally, pid: ~p\n.",[Pid]), recloop(orddict:erase(Pid,Events)); {'EXIT',Pid,Cause} -> S=orddict:fetch(Pid,Events), io:format("Event died abruptly(~p), pid: ~p ; name: ~p\n.",[Cause,Pid,S#event.name]), if S#event.type == periodic -> io:format("Event(periodic) will restart, name: ~p\n.",[S#event.name]), self() ! {self(),reg,S} end, recloop(orddict:erase(Pid,Events)) end. evemon(Events) -> process_flag(trap_exit,true), register(?MODULE,self()), recloop(Events). start() -> spawn(?MODULE,evemon,[orddict:new()]). reg_future(Name,Call,T) -> eventserv ! {self(),reg,#event{name=Name,server=eventserv, call=Call,period=T,type=oneshot}}. reg_future(Call,T) -> eventserv ! {self(),reg,#event{name="Unamed",server=eventserv, call=Call,period=T,type=oneshot}}. reg_periodic(Name,Call,T) -> eventserv ! {self(),reg,#event{name=Name,server=eventserv, call=Call,period=T}}. reg_periodic(Call,T) -> eventserv ! {self(),reg,#event{name="Unamed",server=eventserv, call=Call,period=T}}. regevent(Pid,S) -> Pid ! {self(),reg,S}. test() -> Pid=start(), Pid ! {self(),reg,#event{name="test1",server=Pid, call=fun (PPid) -> io:format("HAHA im here!!!!\n") end,period=1000}}, timer:sleep(500), Pid ! {self(),reg,#event{name="test2",server=Pid, call=fun (PPid) -> io:format("HAHA im away and buggy!!!!\n"),exit("I just love to die") end,period=1000}}, timer:sleep(10000), Pid ! {self(),shutdown}.