1 % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(eventhandling, [register_event_listener/3,announce_event/1, store_virtual_event/1]).
6
7 :- meta_predicate register_event_listener(+,0,+).
8 :- meta_predicate call_for_event(-,0).
9
10 :- use_module(module_information,[module_info/2]).
11 :- module_info(group,infrastructure).
12 :- module_info(description,'The eventhandling module is used to register predicates that are called when certain events (like loading a specification) occurr.').
13
14 :- use_module(library(lists)).
15
16 :- use_module(error_manager,[add_internal_error/2]).
17 :- use_module(tools_strings,[ajoin/2]).
18
19 :- dynamic registered_listener/3.
20
21 % This predicate is called when starting up; the other modules may not be initialised
22 % Do not use other modules yet
23 register_event_listener(Event,Pred,Description) :- %print(register(Event,Module)),nl,
24 ( known_events(Event,_) ->
25 register_event_listener2(Event,Pred,Description)
26 ;
27 print(unknown(Event)),nl,
28 format('~n!!! Unknown event ~w (from ~w) : ~w~n~n',[Event,Pred,Description])
29 %add_internal_error('Unknown event',register_event_listener(Event,Pred,Description))
30 ).
31 register_event_listener2(Event,Pred,Description) :-
32 (registered_listener(Event,Pred,Description) -> true
33 ; assertz(registered_listener(Event,Pred,Description))).
34
35 known_events(compile_prob,'ProB is being compiled').
36 known_events(startup_prob,'ProB is starting up').
37 known_events(stop_prob,'ProB is stopping').
38 known_events(clear_specification,'After we have finished with a specification').
39 known_events(reset_specification,'Resetting animator, without changing specification').
40 known_events(start_initialising_specification,'We start loading a (new) specification').
41 known_events(specification_initialised,'Directly after the specificiation has been loaded and precompiled').
42 known_events(reset_prob,'Resetting probcli (preferences, ... back to defaults), requires clear_specification before').
43
44 known_events(change_of_animation_mode,'Changing Animation Mode (e.g., adding CSP guide)').
45 known_events(start_solving,'Begin solving a new predicate').
46 known_events(end_solving,'End of solving a predicate').
47 known_events(play_counterexample,'Getting counterexample from cache').
48 known_events(start_unit_tests,'Starting ProB Unit Tests').
49 known_events(stop_unit_tests,'Stop ProB Unit Tests').
50
51 % not announced, just stored for lifecycle; TO DO: try and get rid of this (used for self-check)
52 store_virtual_event(Event) :-
53 ( known_events(Event,_) ->
54 check_lifecycle(Event)
55 ;
56 add_internal_error('Unknown event',announce_event(Event))).
57
58 announce_event(Event) :- %print(announce(Event)),nl,
59 ( known_events(Event,_) ->
60 announce_event2(Event)
61 ;
62 add_internal_error('Unknown event',announce_event(Event))).
63
64 announce_event2(Event) :-
65 check_lifecycle(Event),
66 findall(Predicate, registered_listener(Event,Predicate,_Desc), Calls),
67 maplist(call_for_event(Event), Calls)
68 . %, format('Finished processing ~w~n',[Event]).
69
70
71 call_for_event(Event,Predicate) :-
72 % format('Event ~w --triggered--> ~w~n',[Event,Predicate]),
73 statistics(walltime, [Start|_]),
74 ( call(Predicate)
75 -> statistics(walltime, [End|_]), Tot is End-Start,
76 (Tot > 1000
77 -> format('** ~w ms long lifecycle event ~w : predicate : ~w~n',[Tot,Event,Predicate])
78 ; true)
79 ;
80 ajoin(['Call for event ',Event,' failed.'],Msg),
81 add_internal_error(Msg,Predicate)).
82
83
84 % life-cycle management & monitoring
85 % at the moment very simple: as all events are specification related
86
87 :- dynamic last_event/1.
88 last_event(none).
89
90 check_lifecycle(Event) :- last_event(X), %nl,print(event(Event,last(X))),nl,
91 !,
92 (missing_transition(X,Event) -> true ; true),
93 retractall(last_event(_)),
94 assertz(last_event(Event)).
95 check_lifecycle(Event) :- add_internal_error('No last event for ',check_lifecycle(Event)),
96 assertz(last_event(Event)).
97
98 :- use_module(error_manager,[add_warning/3, add_warning/2]).
99 %missing_transition(PreviousEvent, NewEvent)
100 missing_transition(specification_initialised,start_initialising_specification) :-
101 add_warning(event_handling,'Missing event after specification_initialised: ',clear_specification).
102 %announce_event(clear_specification). % here we can remedy this
103 missing_transition(clear_specification,specification_initialised) :-
104 add_warning(event_handling,'Missing event after clear_specification: ',start_initialising_specification).
105 missing_transition(specification_initialised,specification_initialised) :-
106 add_warning(event_handling,'Previous specification not cleared').
107 missing_transition(start_initialising_specification,start_initialising_specification) :-
108 add_warning(event_handling,'Double Start of Specification Initialisation').
109 missing_transition(Prev,reset_prob) :- Prev \= clear_specification,
110 add_warning(event_handling,'Missing event before reset_prob: ',clear_specification).
111 %missing_transition(start_initialising_specification,clear_specification). % we do not need to announce spec initialised