Skip to content

Commit 38c5a60

Browse files
Enhance soft lock
1 parent 0ca3f09 commit 38c5a60

File tree

2 files changed

+83
-21
lines changed

2 files changed

+83
-21
lines changed

jls/lang/Lock-.lua

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,73 @@
11
local class = require('jls.lang.class')
2+
local system = require('jls.lang.system')
3+
4+
local function read(file, offset)
5+
file:seek('set', offset)
6+
local s = file:read(1)
7+
if s then
8+
return (string.byte(s))
9+
end
10+
return 0
11+
end
12+
13+
local function write(file, offset, value)
14+
file:seek('set', offset)
15+
file:write(string.char(value))
16+
file:flush()
17+
end
18+
19+
local MAX_ID = 2
20+
21+
local function getId(self)
22+
return self.initialized and 0 or 1
23+
end
24+
25+
local function softUnlock(file, id)
26+
write(file, MAX_ID + id, 0)
27+
end
28+
29+
-- From Lamport's bakery algorithm
30+
local function softLock(file, id, try)
31+
local max = 0
32+
write(file, id, 1)
33+
for j = MAX_ID, MAX_ID * 2 - 1 do
34+
max = math.max(max, read(file, j))
35+
end
36+
local tic = 1 + max;
37+
write(file, MAX_ID + id, tic)
38+
write(file, id, 0)
39+
--print(string.format("mutex_soft_init(%s, %s) max: %d", id, try, max));
40+
if try and max ~= 0 then
41+
softUnlock(file, id)
42+
return false
43+
end
44+
for i = 0, MAX_ID - 1 do
45+
if i ~= id then
46+
while read(file, i) == 1 do
47+
system.sleep(0)
48+
end
49+
local j = MAX_ID + i
50+
while true do
51+
local cur = read(file, j)
52+
if cur ~= 0 and (cur < tic or (cur == tic and i < id)) then
53+
system.sleep(0)
54+
else
55+
break
56+
end
57+
end
58+
end
59+
end
60+
return true
61+
end
262

363
return class.create(function(lock)
464

565
function lock:initialize()
666
self.name = string.format('.%s-%p.tmp', 'jls.lang.Lock', self)
767
self.file = io.open(self.name, 'w+')
868
self.initialized = true
69+
self.file:write(string.rep('\0', MAX_ID * 2))
70+
self.file:flush()
971
end
1072

1173
function lock:finalize()
@@ -17,33 +79,15 @@ return class.create(function(lock)
1779
end
1880

1981
function lock:lock()
20-
local b
21-
repeat
22-
self.file:seek('set')
23-
b = self.file:read(1)
24-
-- we may want to sleep in case of multiple failures
25-
until b ~= 'l'
26-
self.file:seek('set')
27-
self.file:write('l')
28-
self.file:flush()
82+
softLock(self.file, getId(self), false)
2983
end
3084

3185
function lock:unlock()
32-
self.file:seek('set')
33-
self.file:write(' ')
34-
self.file:flush()
86+
softUnlock(self.file, getId(self))
3587
end
3688

3789
function lock:tryLock()
38-
self.file:seek('set')
39-
local b = self.file:read(1)
40-
if b == 'l' then
41-
return false
42-
end
43-
self.file:seek('set')
44-
self.file:write('l')
45-
self.file:flush()
46-
return true
90+
return softLock(self.file, getId(self), true)
4791
end
4892

4993
function lock:toReference()

jls/lang/Lock-buffer.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1+
--- Provides mutual exclusion for the threads in the current process.
2+
-- @module jls.lang.Lock
3+
-- @pragma nostrip
4+
15
local class = require('jls.lang.class')
26

37
local bufferLib = require('buffer')
8+
assert(type(bufferLib.initmutex) == 'function', 'bad buffer lib version '..tostring(bufferLib._VERSION))
49

10+
--- The Lock class.
11+
-- @type Lock
512
return class.create(function(lock)
613

14+
--- Creates a new Lock.
15+
-- @function Lock:new
716
function lock:initialize()
817
self.mutex = bufferLib.newmutex()
918
bufferLib.initmutex(self.mutex)
@@ -18,24 +27,33 @@ return class.create(function(lock)
1827
end
1928
end
2029

30+
--- Acquires the lock, blocking if necessary.
2131
function lock:lock()
2232
bufferLib.lock(self.mutex)
2333
end
2434

35+
--- Releases the lock.
2536
function lock:unlock()
2637
bufferLib.unlock(self.mutex)
2738
end
2839

40+
--- Returns true if the lock has been acquired without blocking.
41+
-- @treturn boolean true if the lock has been acquired
2942
function lock:tryLock()
3043
return bufferLib.trylock(self.mutex)
3144
end
3245

46+
--- Returns a reference for this lock.
47+
-- @treturn string a reference for this lock
3348
function lock:toReference()
3449
return bufferLib.toreference(self.mutex, nil, 'jls.lang.Lock')
3550
end
3651

3752
end, function(Lock)
3853

54+
--- Returns a lock shared by the specified reference.
55+
-- @tparam string reference the reference
56+
-- @return The shared lock
3957
function Lock.fromReference(reference)
4058
local m = bufferLib.fromreference(reference, nil, 'jls.lang.Lock')
4159
if type(m) ~= 'userdata' then

0 commit comments

Comments
 (0)