summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-27 20:25:26 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit5d9a56d47a9cd5eefc4c8bf03709f2e96febb212 (patch)
tree3471e580d122efbaa881b338ad3542d864c65f65 /test
parent7dc3891ed574d6e96548f592b09b0f8abc87ae2a (diff)
downloadpardes-5d9a56d47a9cd5eefc4c8bf03709f2e96febb212.tar.gz
pardes-5d9a56d47a9cd5eefc4c8bf03709f2e96febb212.zip
A pane's ctl takes acme's lock and unlock
A client doing an edit of several writes to addr and data had no way to keep another client's from landing in between. acme's window ctl takes lock and unlock for this (editors/acme/xfid.c:603-611): a qlock that blocks a second locker, owned by the fid that wrote it and given up when that fid is clunked, binding only clients that ask. pardes does the same: the open's record holds it, a second lock parks until unlock, close or the pane closing, and no other write is refused for it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test')
-rw-r--r--test/fs.py19
1 files changed, 18 insertions, 1 deletions
diff --git a/test/fs.py b/test/fs.py
index b4b0315b..fe7e4c13 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -217,6 +217,23 @@ def discovery(binary, embedded=False):
client.write('/exec', b'Msg woken\n')
reader.join(5)
assert woke and woke[0].endswith(b' woken\n'), woke
+ # A pane's ctl takes acme's lock: a second open's lock waits until
+ # the holder unlocks, and nothing else waits on it meanwhile.
+ with Client(address) as other:
+ mine = client.open(f'/pane/{first}/ctl', 2)
+ client.rpc(118, struct.pack('<IQI', mine, 0, 5) + b'lock\n')
+ theirs = other.open(f'/pane/{first}/ctl', 1)
+ locked = []
+ locker = threading.Thread(target=lambda: locked.append(other.rpc(118, struct.pack('<IQI', theirs, 0, 5) + b'lock\n')), daemon=True)
+ locker.start()
+ time.sleep(.2)
+ assert not locked
+ client.write(f'/pane/{first}/addr', b'#0')
+ client.rpc(118, struct.pack('<IQI', mine, 0, 7) + b'unlock\n')
+ locker.join(5)
+ assert locked, 'a lock waiting on another open goes once it unlocks'
+ client.close(mine)
+ other.close(theirs)
assert set(client.list('/pane')) == {'new', str(fixture), str(first), str(second)}
client.write(f'/pane/{first}/body', b'first pane', truncate=True)
assert client.read(f'/pane/{first}/body') == b'first pane'
@@ -287,7 +304,7 @@ def discovery(binary, embedded=False):
assert client.read('/src/pardes.zig').startswith(b'const std')
assert client.stat('/src/pardes.zig')['mode'] == 0o444
assert b'pub const Pardes' in client.read(f'/pane/{look(client, "/virtual/src/pardes.zig")}/body')
- print('9P discovery: listing/stat/find are inert; new, remove, look, exec, name, sel and log behave')
+ print('9P discovery: listing/stat/find are inert; new, remove, look, exec, name, sel, log and ctl lock behave')
def run_file(binary):