Source file mt_mutexes.ml
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
open Cil_types
open Mt_types
open Mt_thread
open Mt_cfg_types
open Mt_mutexes_types
let mutexes_protecting_zones' accesses =
let aux (z, set) =
SetNodeIdAccess.fold
(fun (rw, node, _id) acc ->
let mutexes = node.cfgn_context.locked_mutexes in
let mut = match rw with
| Read -> { mutexes_for_write = Unaccessed;
mutexes_for_read = Mutexes mutexes }
| Write _ -> { mutexes_for_read = Unaccessed;
mutexes_for_write = Mutexes mutexes }
| ReadPos _ -> { mutexes_for_read = Mutexes mutexes;
mutexes_for_write = Unaccessed }
| WritePos _ -> { mutexes_for_read = Unaccessed;
mutexes_for_write = Mutexes mutexes }
in
MutexesByZone.add_binding ~exact:false acc z mut
) set MutexesByZone.empty
in
let r1 = List.map aux accesses in
let z = List.fold_left
(fun r r' -> MutexesByZone.join r r') MutexesByZone.empty r1
in z
let pretty_with_mutexes =
Mt_shared_vars.Precise.pretty_concurrent_accesses
~f:(fun fmt (_, node, _) ->
let mutexes = node.cfgn_context.locked_mutexes in
if MutexPresence.is_empty mutexes then
Format.fprintf fmt ",@ unprotected"
else
Format.fprintf fmt ",@ @[<hov>protected by %a@]"
MutexPresence.pretty mutexes ;
if Mt_options.PrintCallstacks.get ()
then Format.fprintf fmt ",@ // %a" Callstack.pretty node.cfgn_stack
) ();
;;
type protection = Unprotected | Priority | Protected of Mutex.Set.t
let pretty_protection fmt = function
| Unprotected -> Format.fprintf fmt "unprotected"
| Priority -> Format.fprintf fmt "protected by priorities"
| Protected set ->
Format.fprintf fmt "@[<hov 2>protected by %a@]"
(Pretty_utils.pp_iter Mutex.Set.iter Mutex.pretty) set
let pretty_protection_per_thread fmt (th_read, th_write, protection) =
Format.fprintf fmt "@[<hov 2>Read by %a,@ Write by %a:@ %a@]"
Thread.pretty th_read Thread.pretty th_write
pretty_protection protection
type zone_protection =
(Locations.Zone.t * (Thread.t * Thread.t * protection) list) list
let pretty_zone_protection fmt (z, l) =
Format.fprintf fmt "@[<hv 2>@[%a@]:@ %a@]"
Locations.Zone.pretty z
(Pretty_utils.pp_list ~pre:"" ~suf:"" pretty_protection_per_thread) l
let check_protection analysis (l: Mt_shared_vars.Precise.list_accesses) : zone_protection =
let aux (z, s) =
let m_read = ref Thread.Map.empty in
let m_write = ref Thread.Map.empty in
let add th node map =
let mutexes' = MutexPresence.only_present node.cfgn_context.locked_mutexes in
try
let mutexes = Thread.Map.find th map in
let inter = Mutex.Set.inter mutexes mutexes' in
Thread.Map.add th inter map
with Not_found -> Thread.Map.add th mutexes' map
in
let aux_nodes (op, n, th) =
match op with
| Read -> m_read := add th n !m_read
| Write _ -> m_write := add th n !m_write
| ReadPos _ -> m_read := add th n !m_read
| WritePos _ -> m_write := add th n !m_write
in
SetNodeIdAccess.iter aux_nodes s;
let classify_access th_read read th_write write classified =
if not (Thread.equal th_read th_write) then begin
let th_read_state = Mt_thread.thread_state analysis th_read in
let th_write_state = Mt_thread.thread_state analysis th_write in
let protection =
match th_read_state.th_priority, th_write_state.th_priority with
| PPriority p1, PPriority p2 when p1 > p2 ->
Priority
| _ ->
let both_mutexes = Mutex.Set.inter read write in
if Mutex.Set.is_empty both_mutexes
then Unprotected
else Protected both_mutexes
in
(th_read, th_write, protection) :: classified
end
else classified
in
let protections =
Thread.Map.fold (fun th_read read acc ->
Thread.Map.fold (fun th_write write acc ->
classify_access th_read read th_write write acc
) !m_write acc
) !m_read []
in
(z, protections)
in
List.map aux l
let pretty_protections fmt l =
Pretty_utils.pp_list
~pre:"@[<v>" ~suf:"@]" ~sep:"@ " pretty_zone_protection fmt l
let ill_protected (accesses: Mt_shared_vars.Precise.list_accesses) (protections: zone_protection) =
let res = Cil_datatype.Stmt.Hashtbl.create 16 in
let aux (z, nodes) (z', protections) =
assert (z == z');
let aux (th_read, _th_write, protect) =
if protect = Unprotected then
let aux (op, node, th) =
if Thread.equal th th_read && op = Read then begin
let stmts = CfgNode.node_stmt node in
let aux stmt =
let prev =
try Cil_datatype.Stmt.Hashtbl.find res stmt
with Not_found -> Locations.Zone.bottom
in
let z = Locations.Zone.join prev z in
Cil_datatype.Stmt.Hashtbl.replace res stmt z
in
List.iter aux stmts
end
in
SetNodeIdAccess.iter aux nodes
in
List.iter aux protections
in
List.iter2 aux accesses protections;
res
let need_sync stmtsh =
let aux stmt z acc =
match stmt.preds with
| [stmt] when Mt_cil.is_call_to_sync stmt -> acc
| _ -> (stmt, z) :: acc
in
Cil_datatype.Stmt.Hashtbl.fold aux stmtsh []