59 lines
1.4 KiB
GDScript3
59 lines
1.4 KiB
GDScript3
|
|
extends LockBase
|
||
|
|
class_name RLock
|
||
|
|
|
||
|
|
## Re-entrant lock
|
||
|
|
##
|
||
|
|
## Lock can be aquired multiple times by the same thread
|
||
|
|
|
||
|
|
var _aquired_thread
|
||
|
|
var _counter : int
|
||
|
|
var _mutex : Mutex
|
||
|
|
|
||
|
|
func _init():
|
||
|
|
self._aquired_thread = null
|
||
|
|
self._counter = 0
|
||
|
|
self._mutex = Mutex.new()
|
||
|
|
|
||
|
|
self._saved_recursion_depth = -1
|
||
|
|
|
||
|
|
func lock():
|
||
|
|
self._mutex.lock()
|
||
|
|
self._aquired_thread = OS.get_thread_caller_id()
|
||
|
|
self._counter += 1
|
||
|
|
|
||
|
|
func unlock():
|
||
|
|
if self._counter <= 0:
|
||
|
|
LockNotAquiredError.new(
|
||
|
|
"RLock was released but nobody aquired it!").throw()
|
||
|
|
return
|
||
|
|
if self._aquired_thread != OS.get_thread_caller_id():
|
||
|
|
LockNotAquiredError.new(
|
||
|
|
"RLock was released by a thread which has not aquired it!").throw()
|
||
|
|
return
|
||
|
|
self._counter -= 1
|
||
|
|
if self._counter == 0:
|
||
|
|
self._aquired_thread = null
|
||
|
|
self._mutex.unlock()
|
||
|
|
|
||
|
|
func try_lock() -> bool:
|
||
|
|
return self._mutex.try_lock()
|
||
|
|
|
||
|
|
func is_locking_thread() -> bool:
|
||
|
|
var id = OS.get_thread_caller_id()
|
||
|
|
return self._aquired_thread == id
|
||
|
|
|
||
|
|
## Internal interface to free the lock even though it was aquired more than once
|
||
|
|
var _saved_recursion_depth : int
|
||
|
|
|
||
|
|
## Unlocks the RLock and stores recursion depth
|
||
|
|
func _unlock_and_store_recursion_depth():
|
||
|
|
self._saved_recursion_depth = self._counter
|
||
|
|
for __ in range(self._saved_recursion_depth):
|
||
|
|
self.unlock()
|
||
|
|
|
||
|
|
## Locks the RLock and restores old recursion depth
|
||
|
|
func _lock_and_restore_recursion_depth():
|
||
|
|
for __ in range(self._saved_recursion_depth):
|
||
|
|
self.lock()
|
||
|
|
self._saved_recursion_depth = -1
|