:- module stm_bug.

:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is cc_multi.

:- implementation.

:- import_module bool, int, require, thread, stm_builtin.

:- type lock == stm_var(bool).

:- pred new_lock(lock::out, io::di, io::uo) is det.
new_lock(Lock, !IO) :- new_stm_var(no, Lock, !IO).

:- pred lock(lock::in, io::di, io::uo) is det.
lock(Lock, !IO) :-
	atomic [outer(!IO), inner(!STM)] (
		read_stm_var(Lock, Locked, !STM),
		(
			Locked = no, write_stm_var(Lock, yes, !STM)
		;
			Locked = yes, retry(!.STM)
		)
	).

:- pred unlock(lock::in, io::di, io::uo) is det.
unlock(Lock, !IO) :-
	atomic [outer(!IO), inner(!STM)] (
		read_stm_var(Lock, Locked, !STM),
		(
			Locked = yes, write_stm_var(Lock, no, !STM)
		;
			Locked = no, error("not locked!")
		)
	).

:- pred thread(lock::in, io::di, io::uo) is cc_multi.
thread(Lock, !IO) :-
	lock(Lock, !IO), unlock(Lock, !IO), thread(Lock, !IO).

main(!IO) :-
	new_lock(Lock, !IO),
	spawn(thread(Lock), !IO), spawn(thread(Lock), !IO).
