summaryrefslogtreecommitdiff
path: root/eventserv.erl
blob: 85ee34d56895a70e17ddc4d68e50766ede90a429 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
%%%-------------------------------------------------------------------
%%% @author Joe Zhao
%%% @copyright (C) 2014, <COMPANY>
%%% @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}.