-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathRLock.hx
160 lines (131 loc) · 4.64 KB
/
RLock.hx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
* SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com) and contributors
* SPDX-FileContributor: Sebastian Thomschke, Vegard IT GmbH
* SPDX-License-Identifier: Apache-2.0
*/
package hx.concurrent.lock;
import hx.concurrent.lock.Acquirable.AbstractAcquirable;
import hx.concurrent.internal.Dates;
import hx.concurrent.thread.Threads;
/**
* A re-entrant lock that can only be released by the same thread that acquired it.
*
* https://stackoverflow.com/questions/2332765/lock-mutex-semaphore-whats-the-difference
*/
class RLock extends AbstractAcquirable {
/**
* Indicates if this class will have any effect on the current target.
* Currently: CPP, CS, Flash, HashLink, Java, Neko, Python.
*/
public static inline final isSupported = #if (threads || flash) true #else false #end;
#if (cpp || cs || (threads && eval) || java || neko || hl)
final _rlock = new sys.thread.Mutex();
#elseif flash
// flash.concurrent.Mutex requries swf-version >= 11.4
// flash.concurrent.Condition requries swf-version >= 11.5
final _cond = new flash.concurrent.Condition(new flash.concurrent.Mutex());
#elseif python
final _rlock = new python.lib.threading.RLock();
#end
var _holder:Null<Dynamic> = null;
var _holderEntranceCount = 0;
function get_availablePermits():Int
return isAcquiredByAnyThread ? 0 : 1;
/**
* Indicates if the lock is acquired by any thread
*/
public var isAcquiredByAnyThread(get, never):Bool;
inline function get_isAcquiredByAnyThread():Bool
return _holder != null;
/**
* Indicates if the lock is acquired by the current thread
*/
public var isAcquiredByCurrentThread(get, never):Bool;
inline function get_isAcquiredByCurrentThread():Bool
return _holder == Threads.current;
/**
* Indicates if the lock is acquired by any other thread
*/
public var isAcquiredByOtherThread(get, never):Bool;
inline function get_isAcquiredByOtherThread():Bool
return isAcquiredByAnyThread && !isAcquiredByCurrentThread;
inline //
public function new() {
}
/**
* Blocks until lock can be acquired.
*/
public function acquire():Void {
#if (cpp || cs || (threads && eval) || java || neko || hl || python)
_rlock.acquire();
#elseif flash
_cond.mutex.lock();
#else
// single-threaded targets: js,lua,php
#end
_holder = Threads.current;
_holderEntranceCount++;
}
/**
* By default this call is non-blocking, meaning if the lock cannot be acquired `false` is returned immediately.
*
* If <code>timeoutMS</code> is set to value > 0, results in blocking for the given time to aqcuire the lock.
* If <code>timeoutMS</code> is set to value lower than -0, results in an exception.
*
* @return `false` if lock could not be acquired
*/
public function tryAcquire(timeoutMS = 0):Bool {
if (timeoutMS < 0) throw "[timeoutMS] must be >= 0";
if (tryAcquireInternal(timeoutMS)) {
_holder = Threads.current;
_holderEntranceCount++;
return true;
}
return false;
}
#if !flash inline #end
private function tryAcquireInternal(timeoutMS = 0):Bool {
#if (cpp || cs || (threads && eval) || java || neko || hl)
return Threads.await(() -> _rlock.tryAcquire(), timeoutMS);
#elseif python
return Threads.await(() -> _rlock.acquire(false), timeoutMS);
#elseif flash
final startAt = Dates.now();
while (true) {
if (_cond.mutex.tryLock())
return true;
final elapsedMS = Dates.now() - startAt;
if (elapsedMS >= timeoutMS)
return false;
// wait for mutex to be released by other thread
_cond.wait(timeoutMS - elapsedMS);
}
#else
// single-threaded targets: js,lua,php
return _holder == null || _holder == Threads.current;
#end
}
/**
* Releases the lock.
*
* @throws an exception if the lock was not acquired by the current thread
*/
public function release():Void {
if (isAcquiredByCurrentThread) {
_holderEntranceCount--;
if (_holderEntranceCount == 0)
_holder = null;
} else if (isAcquiredByOtherThread) {
throw "Lock was aquired by another thread!";
} else
throw "Lock was not aquired by any thread!";
#if (cpp || cs || (threads && eval) || java || neko || hl || python)
_rlock.release();
#elseif flash
_cond.notify();
_cond.mutex.unlock();
#else
// single-threaded targets: js,lua,php
#end
}
}