49 thus "distinct q" by auto |
49 thus "distinct q" by auto |
50 qed |
50 qed |
51 qed |
51 qed |
52 qed |
52 qed |
53 |
53 |
54 lemma step_back_vt: "vt (e#s) \<Longrightarrow> vt s" |
54 text {* |
55 by(ind_cases "vt (e#s)", simp) |
55 The following lemma shows that only the @{text "P"} |
56 |
56 operation can add new thread into waiting queues. |
57 lemma step_back_step: "vt (e#s) \<Longrightarrow> step s e" |
57 Such kind of lemmas are very obvious, but need to be checked formally. |
58 by(ind_cases "vt (e#s)", simp) |
58 This is a kind of confirmation that our modelling is correct. |
|
59 *} |
59 |
60 |
60 lemma block_pre: |
61 lemma block_pre: |
61 fixes thread cs s |
62 fixes thread cs s |
62 assumes vt_e: "vt (e#s)" |
63 assumes vt_e: "vt (e#s)" |
63 and s_ni: "thread \<notin> set (wq s cs)" |
64 and s_ni: "thread \<notin> set (wq s cs)" |
108 qed |
109 qed |
109 ultimately show "False" by auto |
110 ultimately show "False" by auto |
110 qed |
111 qed |
111 qed |
112 qed |
112 qed |
113 qed |
|
114 |
|
115 text {* |
|
116 The following lemmas is also obvious and shallow. It says |
|
117 that only running thread can request for a critical resource |
|
118 and that the requested resource must be one which is |
|
119 not current held by the thread. |
|
120 *} |
113 |
121 |
114 lemma p_pre: "\<lbrakk>vt ((P thread cs)#s)\<rbrakk> \<Longrightarrow> |
122 lemma p_pre: "\<lbrakk>vt ((P thread cs)#s)\<rbrakk> \<Longrightarrow> |
115 thread \<in> runing s \<and> (Cs cs, Th thread) \<notin> (RAG s)^+" |
123 thread \<in> runing s \<and> (Cs cs, Th thread) \<notin> (RAG s)^+" |
116 apply (ind_cases "vt ((P thread cs)#s)") |
124 apply (ind_cases "vt ((P thread cs)#s)") |
117 apply (ind_cases "step s (P thread cs)") |
125 apply (ind_cases "step s (P thread cs)") |
199 qed |
207 qed |
200 |
208 |
201 (* Wrong: |
209 (* Wrong: |
202 lemma \<lbrakk>thread \<in> set (wq_fun cs1 s); thread \<in> set (wq_fun cs2 s)\<rbrakk> \<Longrightarrow> cs1 = cs2" |
210 lemma \<lbrakk>thread \<in> set (wq_fun cs1 s); thread \<in> set (wq_fun cs2 s)\<rbrakk> \<Longrightarrow> cs1 = cs2" |
203 *) |
211 *) |
|
212 |
|
213 text {* (* ??? *) |
|
214 The nature of the work is like this: since it starts from a very simple and basic |
|
215 model, even intuitively very `basic` and `obvious` properties need to derived from scratch. |
|
216 For instance, the fact |
|
217 that one thread can not be blocked by two critical resources at the same time |
|
218 is obvious, because only running threads can make new requests, if one is waiting for |
|
219 a critical resource and get blocked, it can not make another resource request and get |
|
220 blocked the second time (because it is not running). |
|
221 |
|
222 To derive this fact, one needs to prove by contraction and |
|
223 reason about time (or @{text "moement"}). The reasoning is based on a generic theorem |
|
224 named @{text "p_split"}, which is about status changing along the time axis. It says if |
|
225 a condition @{text "Q"} is @{text "True"} at a state @{text "s"}, |
|
226 but it was @{text "False"} at the very beginning, then there must exits a moment @{text "t"} |
|
227 in the history of @{text "s"} (notice that @{text "s"} itself is essentially the history |
|
228 of events leading to it), such that @{text "Q"} switched |
|
229 from being @{text "False"} to @{text "True"} and kept being @{text "True"} |
|
230 till the last moment of @{text "s"}. |
|
231 |
|
232 Suppose a thread @{text "th"} is blocked |
|
233 on @{text "cs1"} and @{text "cs2"} in some state @{text "s"}, |
|
234 since no thread is blocked at the very beginning, by applying |
|
235 @{text "p_split"} to these two blocking facts, there exist |
|
236 two moments @{text "t1"} and @{text "t2"} in @{text "s"}, such that |
|
237 @{text "th"} got blocked on @{text "cs1"} and @{text "cs2"} |
|
238 and kept on blocked on them respectively ever since. |
|
239 |
|
240 Without lose of generality, we assume @{text "t1"} is earlier than @{text "t2"}. |
|
241 However, since @{text "th"} was blocked ever since memonent @{text "t1"}, so it was still |
|
242 in blocked state at moment @{text "t2"} and could not |
|
243 make any request and get blocked the second time: Contradiction. |
|
244 *} |
204 |
245 |
205 lemma waiting_unique_pre: |
246 lemma waiting_unique_pre: |
206 fixes cs1 cs2 s thread |
247 fixes cs1 cs2 s thread |
207 assumes vt: "vt s" |
248 assumes vt: "vt s" |
208 and h11: "thread \<in> set (wq s cs1)" |
249 and h11: "thread \<in> set (wq s cs1)" |
405 from preced_unique [OF _ th_in1 th_in2] and neq_12 |
456 from preced_unique [OF _ th_in1 th_in2] and neq_12 |
406 have "preced th1 s \<noteq> preced th2 s" by auto |
457 have "preced th1 s \<noteq> preced th2 s" by auto |
407 thus ?thesis by auto |
458 thus ?thesis by auto |
408 qed |
459 qed |
409 |
460 |
|
461 (* An aux lemma used later *) |
410 lemma unique_minus: |
462 lemma unique_minus: |
411 fixes x y z r |
463 fixes x y z r |
412 assumes unique: "\<And> a b c. \<lbrakk>(a, b) \<in> r; (a, c) \<in> r\<rbrakk> \<Longrightarrow> b = c" |
464 assumes unique: "\<And> a b c. \<lbrakk>(a, b) \<in> r; (a, c) \<in> r\<rbrakk> \<Longrightarrow> b = c" |
413 and xy: "(x, y) \<in> r" |
465 and xy: "(x, y) \<in> r" |
414 and xz: "(x, z) \<in> r^+" |
466 and xz: "(x, z) \<in> r^+" |
512 lemma RAG_exit_unchanged: "(RAG (Exit th # s)) = RAG s" |
570 lemma RAG_exit_unchanged: "(RAG (Exit th # s)) = RAG s" |
513 apply (unfold s_RAG_def s_waiting_def wq_def) |
571 apply (unfold s_RAG_def s_waiting_def wq_def) |
514 by (simp add:Let_def) |
572 by (simp add:Let_def) |
515 |
573 |
516 |
574 |
517 |
575 text {* |
|
576 The following lemmas are used in the proof of |
|
577 lemma @{text "step_RAG_v"}, which characterizes how the @{text "RAG"} is changed |
|
578 by @{text "V"}-events. |
|
579 However, since our model is very concise, such seemingly obvious lemmas need to be derived from scratch, |
|
580 starting from the model definitions. |
|
581 *} |
518 lemma step_v_hold_inv[elim_format]: |
582 lemma step_v_hold_inv[elim_format]: |
519 "\<And>c t. \<lbrakk>vt (V th cs # s); |
583 "\<And>c t. \<lbrakk>vt (V th cs # s); |
520 \<not> holding (wq s) t c; holding (wq (V th cs # s)) t c\<rbrakk> \<Longrightarrow> next_th s th cs t \<and> c = cs" |
584 \<not> holding (wq s) t c; holding (wq (V th cs # s)) t c\<rbrakk> \<Longrightarrow> |
|
585 next_th s th cs t \<and> c = cs" |
521 proof - |
586 proof - |
522 fix c t |
587 fix c t |
523 assume vt: "vt (V th cs # s)" |
588 assume vt: "vt (V th cs # s)" |
524 and nhd: "\<not> holding (wq s) t c" |
589 and nhd: "\<not> holding (wq s) t c" |
525 and hd: "holding (wq (V th cs # s)) t c" |
590 and hd: "holding (wq (V th cs # s)) t c" |
562 qed |
627 qed |
563 with True show ?thesis by auto |
628 with True show ?thesis by auto |
564 qed |
629 qed |
565 qed |
630 qed |
566 |
631 |
|
632 text {* |
|
633 The following @{text "step_v_wait_inv"} is also an obvious lemma, which, however, needs to be |
|
634 derived from scratch, which confirms the correctness of the definition of @{text "next_th"}. |
|
635 *} |
567 lemma step_v_wait_inv[elim_format]: |
636 lemma step_v_wait_inv[elim_format]: |
568 "\<And>t c. \<lbrakk>vt (V th cs # s); \<not> waiting (wq (V th cs # s)) t c; waiting (wq s) t c |
637 "\<And>t c. \<lbrakk>vt (V th cs # s); \<not> waiting (wq (V th cs # s)) t c; waiting (wq s) t c |
569 \<rbrakk> |
638 \<rbrakk> |
570 \<Longrightarrow> (next_th s th cs t \<and> cs = c)" |
639 \<Longrightarrow> (next_th s th cs t \<and> cs = c)" |
571 proof - |
640 proof - |
788 step_v_release step_v_wait_inv |
861 step_v_release step_v_wait_inv |
789 step_v_get_hold step_v_release_inv) |
862 step_v_get_hold step_v_release_inv) |
790 apply (erule_tac step_v_not_wait, auto) |
863 apply (erule_tac step_v_not_wait, auto) |
791 done |
864 done |
792 |
865 |
|
866 text {* |
|
867 The following @{text "step_RAG_p"} lemma charaterizes how @{text "RAG"} is changed |
|
868 with the happening of @{text "P"}-events: |
|
869 *} |
793 lemma step_RAG_p: |
870 lemma step_RAG_p: |
794 "vt (P th cs#s) \<Longrightarrow> |
871 "vt (P th cs#s) \<Longrightarrow> |
795 RAG (P th cs # s) = (if (wq s cs = []) then RAG s \<union> {(Cs cs, Th th)} |
872 RAG (P th cs # s) = (if (wq s cs = []) then RAG s \<union> {(Cs cs, Th th)} |
796 else RAG s \<union> {(Th th, Cs cs)})" |
873 else RAG s \<union> {(Th th, Cs cs)})" |
797 apply(simp only: s_RAG_def wq_def) |
874 apply(simp only: s_RAG_def wq_def) |
806 |
883 |
807 |
884 |
808 lemma RAG_target_th: "(Th th, x) \<in> RAG (s::state) \<Longrightarrow> \<exists> cs. x = Cs cs" |
885 lemma RAG_target_th: "(Th th, x) \<in> RAG (s::state) \<Longrightarrow> \<exists> cs. x = Cs cs" |
809 by (unfold s_RAG_def, auto) |
886 by (unfold s_RAG_def, auto) |
810 |
887 |
|
888 text {* |
|
889 The following lemma shows that @{text "RAG"} is acyclic. |
|
890 The overall structure is by induction on the formation of @{text "vt s"} |
|
891 and then case analysis on event @{text "e"}, where the non-trivial cases |
|
892 for those for @{text "V"} and @{text "P"} events. |
|
893 *} |
811 lemma acyclic_RAG: |
894 lemma acyclic_RAG: |
812 fixes s |
895 fixes s |
813 assumes vt: "vt s" |
896 assumes vt: "vt s" |
814 shows "acyclic (RAG s)" |
897 shows "acyclic (RAG s)" |
815 using assms |
898 using assms |
1216 qed |
1299 qed |
1217 with th_nin th_in show False by auto |
1300 with th_nin th_in show False by auto |
1218 qed |
1301 qed |
1219 qed |
1302 qed |
1220 |
1303 |
|
1304 text {* \noindent |
|
1305 The following lemmas shows that: starting from any node in @{text "RAG"}, |
|
1306 by chasing out-going edges, it is always possible to reach a node representing a ready |
|
1307 thread. In this lemma, it is the @{text "th'"}. |
|
1308 *} |
|
1309 |
1221 lemma chain_building: |
1310 lemma chain_building: |
1222 assumes vt: "vt s" |
1311 assumes vt: "vt s" |
1223 shows "node \<in> Domain (RAG s) \<longrightarrow> (\<exists> th'. th' \<in> readys s \<and> (node, Th th') \<in> (RAG s)^+)" |
1312 shows "node \<in> Domain (RAG s) \<longrightarrow> (\<exists> th'. th' \<in> readys s \<and> (node, Th th') \<in> (RAG s)^+)" |
1224 proof - |
1313 proof - |
1225 from wf_dep_converse [OF vt] |
1314 from wf_dep_converse [OF vt] |
2358 lemma cnp_cnv_eq: |
2453 lemma cnp_cnv_eq: |
2359 fixes th s |
2454 fixes th s |
2360 assumes "vt s" |
2455 assumes "vt s" |
2361 and "th \<notin> threads s" |
2456 and "th \<notin> threads s" |
2362 shows "cntP s th = cntV s th" |
2457 shows "cntP s th = cntV s th" |
2363 proof - |
2458 by (simp add: assms(1) assms(2) cnp_cnv_cncs not_thread_cncs) |
2364 from assms show ?thesis |
|
2365 proof(induct) |
|
2366 case (vt_cons s e) |
|
2367 have ih: "th \<notin> threads s \<Longrightarrow> cntP s th = cntV s th" by fact |
|
2368 have not_in: "th \<notin> threads (e # s)" by fact |
|
2369 have "step s e" by fact |
|
2370 thus ?case proof(cases) |
|
2371 case (thread_create thread prio) |
|
2372 assume eq_e: "e = Create thread prio" |
|
2373 hence "thread \<in> threads (e#s)" by simp |
|
2374 with not_in and eq_e have "th \<notin> threads s" by auto |
|
2375 from ih [OF this] show ?thesis using eq_e |
|
2376 by (auto simp:cntP_def cntV_def count_def) |
|
2377 next |
|
2378 case (thread_exit thread) |
|
2379 assume eq_e: "e = Exit thread" |
|
2380 and not_holding: "holdents s thread = {}" |
|
2381 have vt_s: "vt s" by fact |
|
2382 from finite_holding[OF vt_s] have "finite (holdents s thread)" . |
|
2383 with not_holding have "cntCS s thread = 0" by (unfold cntCS_def, auto) |
|
2384 moreover have "thread \<in> readys s" using thread_exit by (auto simp:runing_def) |
|
2385 moreover note cnp_cnv_cncs[OF vt_s, of thread] |
|
2386 ultimately have eq_thread: "cntP s thread = cntV s thread" by auto |
|
2387 show ?thesis |
|
2388 proof(cases "th = thread") |
|
2389 case True |
|
2390 with eq_thread eq_e show ?thesis |
|
2391 by (auto simp:cntP_def cntV_def count_def) |
|
2392 next |
|
2393 case False |
|
2394 with not_in and eq_e have "th \<notin> threads s" by simp |
|
2395 from ih[OF this] and eq_e show ?thesis |
|
2396 by (auto simp:cntP_def cntV_def count_def) |
|
2397 qed |
|
2398 next |
|
2399 case (thread_P thread cs) |
|
2400 assume eq_e: "e = P thread cs" |
|
2401 have "thread \<in> runing s" by fact |
|
2402 with not_in eq_e have neq_th: "thread \<noteq> th" |
|
2403 by (auto simp:runing_def readys_def) |
|
2404 from not_in eq_e have "th \<notin> threads s" by simp |
|
2405 from ih[OF this] and neq_th and eq_e show ?thesis |
|
2406 by (auto simp:cntP_def cntV_def count_def) |
|
2407 next |
|
2408 case (thread_V thread cs) |
|
2409 assume eq_e: "e = V thread cs" |
|
2410 have "thread \<in> runing s" by fact |
|
2411 with not_in eq_e have neq_th: "thread \<noteq> th" |
|
2412 by (auto simp:runing_def readys_def) |
|
2413 from not_in eq_e have "th \<notin> threads s" by simp |
|
2414 from ih[OF this] and neq_th and eq_e show ?thesis |
|
2415 by (auto simp:cntP_def cntV_def count_def) |
|
2416 next |
|
2417 case (thread_set thread prio) |
|
2418 assume eq_e: "e = Set thread prio" |
|
2419 and "thread \<in> runing s" |
|
2420 hence "thread \<in> threads (e#s)" |
|
2421 by (simp add:runing_def readys_def) |
|
2422 with not_in and eq_e have "th \<notin> threads s" by auto |
|
2423 from ih [OF this] show ?thesis using eq_e |
|
2424 by (auto simp:cntP_def cntV_def count_def) |
|
2425 qed |
|
2426 next |
|
2427 case vt_nil |
|
2428 show ?case by (auto simp:cntP_def cntV_def count_def) |
|
2429 qed |
|
2430 qed |
|
2431 |
2459 |
2432 lemma eq_RAG: |
2460 lemma eq_RAG: |
2433 "RAG (wq s) = RAG s" |
2461 "RAG (wq s) = RAG s" |
2434 by (unfold cs_RAG_def s_RAG_def, auto) |
2462 by (unfold cs_RAG_def s_RAG_def, auto) |
2435 |
2463 |