https://bitbucket.org/adelard/simple-concurrency
Tip revision: cd7dfa9b13e79137daa54446067371af0a68515d authored by Dan Sheridan on 27 February 2015, 15:32:58 UTC
Change -accesses-for to report accesses from the "main" entry point even if it is not explicitly listed in -threads; this better matches the behaviour of -var-overlap.
Change -accesses-for to report accesses from the "main" entry point even if it is not explicitly listed in -threads; this better matches the behaviour of -var-overlap.
Tip revision: cd7dfa9
concur_gui.ml
(**************************************************************************)
(* *)
(* This file is part of the Concurrency Plugin for Frama-C *)
(* *)
(* Copyright (C) 2013 *)
(* Adelard LLP *)
(* CINIF (Control and Instrumentation Nuclear Industry Forum) *)
(* *)
(* You can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 3. *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version v3 *)
(* for more details (enclosed in the file ./LGPLv3). *)
(* *)
(**************************************************************************)
(**
* This is the main entry for the Concurrency plugin gui.
*)
(*GUIs*)
open Gtk_helper
open Pretty_source
(*Plugin modules*)
open Concurrency_main
open Cil_datatype
open Cil_types
open Visitor
(*open Option - was not been able to link this library ExtLib*)
open Concurguiglobs
open Vappgui
open Accessesgui
open Epsgui
let show_column = ref (fun _ -> ());; (*the 'Concurrency' column in filetree*)
(** Computes an intersection of the variable sets used by the main thread
* and the selected thread*)
let update_var_overlap () =
if (List.length (SelectedThreads.get ())) > 0 && ((SelectedMain.get) () != init_fundec)
then
(
let main_vars = variables_used (get_option !cg) (SelectedMain.get ()) in
let intersect_vars st f2 =
if f2 != (SelectedMain.get ()) then
Varinfo.Set.inter st (variables_used (get_option !cg) f2)
else
st
in
let out_set = List.fold_left intersect_vars main_vars (SelectedThreads.get ()) in
VarOverlapSet_ref.set out_set;
)
else
() ;;
(** Updates the R/W access locations for a particular variable and thread
* and converts this data to the local data holder type*)
let update_acc() =
if (List.length (SelectedThreads.get ())) > 0
&& (SelectedMain.get ()) != init_fundec
&& (LockedVar.get ()) != init_varinfo
then
begin
(*obtains the locs for the current entry point*)
let get_locs_for_v_from_ep v ep =
let vis = new varAccess v in
let visfun _ f =
let _ = visitFramacFunction (vis:>frama_c_visitor) f in ()
in
cg_dfs_fundecs (get_option !cg) visfun ep;
vis#locs
in
(*converts locs to the AccessForList type*)
let to_access_for ep (a, b, c) =
(ep, a, b, c)
in
let main_locs = get_locs_for_v_from_ep (LockedVar.get ()) (SelectedMain.get ()) in
AccessForList.set [];
AccessForList.set (List.append (AccessForList.get ()) (List.map (to_access_for (SelectedMain.get ())) main_locs));
let apply_to_all_eps ep =
let ep_locs = get_locs_for_v_from_ep (LockedVar.get ()) ep in
AccessForList.set (List.append (AccessForList.get ()) (List.map (to_access_for ep) ep_locs))
in
List.iter apply_to_all_eps (SelectedThreads.get ())
end ;;
(** Updates the pretty source viewer part of the Frama-C GUI
* to highlight the critical regions in the code.
*)
let concur_highlighter buffer loc ~start ~stop =
if (List.length (AccessForList.get ())) > 0 then
begin
let highlight clr =
(*make_tag apply_tag are frama-c functions*)
let tag = make_tag buffer "concurrency" [`BACKGROUND clr ] in
apply_tag buffer tag start stop
in
match loc with
| PLval (_, ki, (lh,_)) ->
let same_lval ki lh (_,k,_,_) =
(Kinstr.equal ki k) &&
match lh with
| Var(vi) -> (Varinfo.equal vi (LockedVar.get ()))
| _ -> false
in
if List.exists (same_lval ki lh) (AccessForList.get ()) then
highlight "yellow";
| PTermLval (_,ki,(lh,_)) ->
let same_tlval ki lh (_,k,_,_) =
(Kinstr.equal ki k) &&
match lh with
| TVar(tv) ->
begin
match tv.lv_origin with
| Some(vi) -> (Varinfo.equal vi (LockedVar.get ()))
| None -> false
end
| _ -> false
in
if List.exists (same_tlval ki lh) (AccessForList.get ()) then
highlight "yellow"
| PVDecl(_, vi') when Varinfo.equal (LockedVar.get ()) vi' ->
highlight "yellow"
| PVDecl _ | PStmt _ | PGlobal _ | PIP _ -> ()
end;;
(** Configures the concurrency plugin side panel and loads the additional forms.
*)
let concurrency_panel main_ui =
let eps_display = new vEpsWindow in (*entry points form*)
let var_overlap_display = new vAppWindow in (*intersected variables form*)
let access_display = new vAccWindow main_ui in (*access form*)
(*setup the side panel*)
let v_box = GPack.vbox () in
let h0_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Filter:"
~width:100
~packing:(h0_box#pack ~expand:false) ()
in
let open_ep_filter = GButton.button ~label:"Entry Points" ~packing:h0_box#pack () in
ignore (open_ep_filter#connect#pressed (fun () -> eps_display#show_eps ()));
(*Create Main combo and label*)
let h2_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current main: "
~width:100
~packing:(h2_box#pack ~expand:false) ()
in
let main_combo = GEdit.combo_box_text ~strings:[]
~has_frame:true ~packing:h2_box#pack ()
in
(*Populates the main entry point combo box with
selection of available entry points*)
let populate_main () =
let add_eps_to_combo ep =
let ep_name = (Kernel_function.get_name ep) in
GEdit.text_combo_add main_combo ep_name
in
let (_,(a,_)) = main_combo in
a#clear ();
List.iter add_eps_to_combo (FilteredEntryPoints.get ())
in
let (a,_) = main_combo in
ignore(a#connect#changed (fun () ->
let mn = match GEdit.text_combo_get_active main_combo with
| Some(a) -> Globals.Functions.find_by_name a
| None -> init_fundec
in
if mn != init_fundec then
begin
SelectedMain.set mn;
LockedVar.set init_varinfo;
AccessForList.set [];
SelectedThreads.set [];
VarOverlapSet_ref.set Varinfo.Set.empty;
refresh := (false,true,true,true,false) (*update gui*)
end));
(*Create E.P. combo and label*)
let h3_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current E.P.: "
~width:100
~packing:(h3_box#pack ~expand:false) ()
in
let eps_combo = GEdit.combo_box_text ~strings:[] ~has_frame:true ~packing:h3_box#pack () in
(* Populates the Entry Points combo with the
available entry points except what was selected as a main entry point*)
let populate_eps () =
let current_main = match GEdit.text_combo_get_active main_combo with
| Some(a) -> a
| None -> ""
in
let add_eps_to_combo ep =
let ep_name = (Kernel_function.get_name ep) in
if not (ep_name = current_main) then
GEdit.text_combo_add eps_combo ep_name
in
let (_,(a,_)) = eps_combo in
a#clear ();
List.iter add_eps_to_combo (FilteredEntryPoints.get ())
in
let (a,_) = eps_combo in
ignore(a#connect#changed (
fun () ->
let ep = match GEdit.text_combo_get_active eps_combo with
| Some(a) -> Globals.Functions.find_by_name a
| None -> init_fundec
in
if ep != init_fundec then
begin
SelectedThreads.set [ep];
LockedVar.set init_varinfo;
VarOverlapSet_ref.set Varinfo.Set.empty;
AccessForList.set [];
refresh := (false,false,true,true,false) (*update gui*)
end));
(*Create the currently selected variable combo box*)
let h1_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current variable:"
~width:100
~packing:(h1_box#pack ~expand:false) ()
in
let var_combo = GEdit.combo_box_text ~strings:[] ~has_frame:true ~packing:h1_box#pack () in
(*Populates the combo box with the current
variables shared between main and EP thread.*)
let populate_var () =
let (a,(b,_)) = var_combo in
let add_vars_to_combo vi c =
if not (Cil.isFunctionType vi.vtype) then begin
GEdit.text_combo_add var_combo vi.vname;
(*the purpose of this is to activate the currently selected variable*)
if vi.vname == (LockedVar.get ()).vname then
a#set_active c; (*how to get the number of elements added*)
c+1
end
else c
in
b#clear ();
ignore(Varinfo.Set.fold add_vars_to_combo (VarOverlapSet_ref.get ()) 0);
in
let (a,_) = var_combo in
ignore(a#connect#changed (fun () ->
let vi = match GEdit.text_combo_get_active var_combo with
| Some(a) ->
(try Globals.Vars.find_from_astinfo a VGlobal
with Not_found -> init_varinfo)
| None -> init_varinfo
in
if vi != init_varinfo then
LockedVar.set vi;
AccessForList.set [];
refresh := (false, false, false, true, false) (*update gui*)
));
(*create buttons*)
let show_vapp = GButton.button ~label:"Details" ~packing:h1_box#pack () in
ignore (show_vapp#connect#pressed (fun () -> var_overlap_display#show_vapp ()));
let h4_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Compute:"
~width:100
~packing:(h4_box#pack ~expand:false) ()
in
let button_access_details = GButton.button ~label:"Show Details" ~packing:h4_box#pack () in
ignore (button_access_details#connect#pressed(fun () -> update_acc (); access_display#show_acc ()));
(* Drives the GUI statemachine updating the Concurrency section of the GUI*)
let refresh = fun () ->
begin
(*We could replace this by some sort of signal*)
let (m,e,v,g,_) = !refresh in
if m then
populate_main ();
(*main has changed*)
if e then
populate_eps ();
(*main or eps have changed*)
if v then
begin
update_var_overlap ();
populate_var ();
!show_column `Visibility
end;
(*main or eps or var have changed*)
if g then
begin
populate_var ();
update_acc ();
!show_column `Visibility
end;
if m || e || v || g then
(
var_overlap_display#refresh ();
access_display#refresh ();
main_ui#rehighlight ();
);
refresh := (false,false, false, false, false)
end
in
"Concurrency", v_box#coerce, Some refresh
;;
(** Decorates the file tree Concurrency colum to show the
* functions where a particular variable is used.
*)
let file_tree_decorate (file_tree:Filetree.t) =
show_column :=
file_tree#append_pixbuf_column
~title:"Concurrency"
(fun globs ->
if List.length (AccessForList.get ()) > 0 then
begin
let in_globals (_,ki,_,_) =
match ki with
| Kglobal -> false
| Kstmt stmt ->
let kf = Kernel_function.find_englobing_kf stmt in
let {vid=v0} = Kernel_function.get_vi kf in
List.exists
(fun glob -> match glob with
| GFun ({svar ={vid=v1}},_ ) -> v1=v0
| _ -> false)
globs
in
if (List.exists in_globals (AccessForList.get ())) then [`STOCK_ID "gtk-apply"]
else [`STOCK_ID ""]
end
else
[`STOCK_ID ""])
(fun () -> not (Varinfo.equal (LockedVar.get ()) init_varinfo));
!show_column `Visibility ;;
let concur_gui_f main_ui=
(*init*)
start_concurrency ();
Self.result "Starting concur plugin";
(*menu accessible from right clicking on the source viewer*)
(*main_ui#register_source_selector concur_menu_item;*)
(*highlights in main code display when necessary parameters of the plugin
are set*)
main_ui#register_source_highlighter concur_highlighter;
main_ui#register_panel concurrency_panel;
file_tree_decorate main_ui#file_tree;
;;
(*Register the main_gui function as enty point for Concur GUI*)
let () = Design.register_extension concur_gui_f ;;