Pārlūkot izejas kodu

[eval] allow multiple locks from same thread for sys.thread.Mutex (fixes #10249)

Aleksandr Kuzmenko 4 gadi atpakaļ
vecāks
revīzija
43860db98f

+ 1 - 0
extra/CHANGES.txt

@@ -13,6 +13,7 @@
 	js : fixed extending extern classes for es5 (#10192)
 	js : fixed checking `this` before `super` for es6 (#10193)
 	eval : fixed null pointer exception in `eval.NativeString.fromString(null)`
+	eval : fixed multiple locks of `sys.thread.Mutex` from the same thread (#10249)
 
 2021-02-26 4.2.1:
 

+ 1 - 1
src/macro/eval/evalDebugSocket.ml

@@ -316,7 +316,7 @@ let output_inner_vars v env =
 				(s,v) :: acc
 			) h []
 		| VInstance {ikind = IMutex mutex} ->
-			["owner",match mutex.mowner with None -> vnull | Some id -> vint id]
+			["owner",match mutex.mowner with None -> vnull | Some (id,_) -> vint id]
 		| VInstance {ikind = IThread thread} ->
 			["id",vint (Thread.id thread.tthread)]
 		| VInstance vi ->

+ 30 - 8
src/macro/eval/evalStdLib.ml

@@ -1741,25 +1741,47 @@ module StdMutex = struct
 
 	let acquire = vifun0 (fun vthis ->
 		let mutex = this vthis in
-		Mutex.lock mutex.mmutex;
-		mutex.mowner <- Some (Thread.id (Thread.self()));
+		let thread_id = Thread.id (Thread.self()) in
+		(match mutex.mowner with
+		| None ->
+			Mutex.lock mutex.mmutex;
+			mutex.mowner <- Some (thread_id,1)
+		| Some (id,n) ->
+			if id = thread_id then
+				mutex.mowner <- Some (thread_id,n + 1)
+			else begin
+				Mutex.lock mutex.mmutex;
+				mutex.mowner <- Some (thread_id,1)
+			end
+		);
 		vnull
 	)
 
 	let release = vifun0 (fun vthis ->
 		let mutex = this vthis in
-		mutex.mowner <- None;
-		Mutex.unlock mutex.mmutex;
+		(match mutex.mowner with
+		| Some (id,n) when n > 1 ->
+			mutex.mowner <- Some (id,n - 1)
+		| _ ->
+			mutex.mowner <- None;
+			Mutex.unlock mutex.mmutex;
+		);
 		vnull
 	)
 
 	let tryAcquire = vifun0 (fun vthis ->
 		let mutex = this vthis in
-		if Mutex.try_lock mutex.mmutex then begin
-			mutex.mowner <- Some (Thread.id (Thread.self()));
+		let thread_id = Thread.id (Thread.self()) in
+		match mutex.mowner with
+		| Some (id,n) when id = thread_id ->
+			mutex.mowner <- Some (thread_id,n + 1);
 			vtrue
-		end else
-			vfalse
+		| _ ->
+			if Mutex.try_lock mutex.mmutex then begin
+				mutex.mowner <- Some (thread_id,1);
+				vtrue
+			end else
+				vfalse
 	)
 end
 

+ 1 - 1
src/macro/eval/evalValue.ml

@@ -252,7 +252,7 @@ and vdeque = {
 
 and vmutex = {
 	mmutex : Mutex.t;
-	mutable mowner : int option; (* thread ID *)
+	mutable mowner : (int * int) option; (* thread ID * same thread lock count *)
 }
 
 and vlock = {

+ 15 - 0
tests/threads/src/cases/TestMutex.hx

@@ -0,0 +1,15 @@
+package cases;
+
+import sys.thread.Mutex;
+
+class TestMutex extends utest.Test {
+	function testIssue10249() {
+		var m = new Mutex();
+		m.acquire();
+		m.acquire();
+		isTrue(m.tryAcquire());
+		m.release();
+		m.release();
+		m.release();
+	}
+}