Section IO_safety.
Context `{Config : ThreadsConfigurationOps}.
Variable (prog : Clight.program).
Definition ext_link := ext_link_prog prog.
Definition sys_getc_wrap_spec (abd : RData) : option (RData * val * trace) :=
match sys_getc_spec abd with
| Some abd' => Some (abd', get_sys_ret abd', trace_of_ostrace (strip_common_prefix IOEvent_eq abd.(io_log) abd'.(io_log)))
| None => None
end.
Definition sys_putc_wrap_spec (cv : val) (abd : RData) : option (RData * val * trace) :=
(* Make sure argument is set *)
match cv, get_sys_arg1 abd with
| Vint c, Vint c' =>
if eq_dec.eq_dec c c' then
match sys_putc_spec abd with
| Some abd' => Some (abd', get_sys_ret abd', trace_of_ostrace (strip_common_prefix IOEvent_eq abd.(io_log) abd'.(io_log)))
| None => None
end
else None
| _, _ => None
end.
Definition IO_ext_sem e (args : list val) s :=
if oi_eq_dec (Some (ext_link "putchar"%string, funsig2signature ([(1%positive, tint)], tint) cc_default))
(ef_id_sig ext_link e) then
match args with
| c :: nil =>
match sys_putc_wrap_spec c s with
| Some (s', ret, t') => Some (s', Some ret, t')
| None => None
end
| _ => None end else
if oi_eq_dec  (Some (ext_link "getchar"%string, funsig2signature ([], tint) cc_default))
(ef_id_sig ext_link e) then
match sys_getc_wrap_spec s with
| Some (s', ret, t') => Some (s', Some ret, t')
| None => None
end
else Some (s, None, TEnd).
Variable (R_mem : block -> Z).
(* Because putchar and getchar don't use memory, these functions don't either. *)
Definition IO_inj_mem (e : external_function) (args : list val) (m : mem) t s :=
valid_trace s /\ t = trace_of_ostrace s.(io_log).
Definition OS_mem (e : external_function) (args : list val) m (s : RData) : mem := m.
(* In general, this could look like: if oi_eq_dec (Some (ext_link "putchars"%string, ...) (ef_id_sig ext_link e) then match args with | (Vptr b ofs) :: len :: nil => flatmem_to_mem R_mem s.(HP) m b ofs (ofs + len) | _ => m end else ... *)
Instance IO_Espec : OracleKind := IO_Espec ext_link.

Theorem IO_OS_soundness:
forall {CS: compspecs} (initial_oracle: OK_ty) V G m,
semax_prog prog initial_oracle V G ->
Genv.init_mem prog = Some m ->
exists b, exists q, exists m',
Genv.find_symbol (Genv.globalenv prog) (prog_main prog) = Some b /\
initial_core (Clight_core.cl_core_sem (globalenv prog))
0 m q m' (Vptr b Ptrofs.zero) nil /\
forall n, exists traces, ext_safeN_trace(J := OK_spec) prog IO_ext_sem IO_inj_mem OS_mem valid_trace n TEnd traces initial_oracle q m' /\
forall t, In _ traces t -> exists z', consume_trace initial_oracle z' t.