Files
bare-operating-system/packages/bare-os-booter/lib/posix/bare-os-fcntl-cooperative-lock.js
T
2026-08-18 18:11:28 -04:00

78 lines
2.4 KiB
JavaScript

/**
* Cooperative advisory **`fcntl`** lock slot + **`F_SETLKW`** waiter drain (**FIFO** per path).
* Used by **`packages/bare-os-booter/index.js`** **`bareOsSyscall('fcntl')`**.
*/
/**
* @param {{ readers: Set<string>; writer: string | null }} slot
* @param {string} owner
* @param {boolean} wantWrite
*/
export function bareOsTryAcquireCooperativeLock(slot, owner, wantWrite) {
if (wantWrite) {
if (slot.writer && slot.writer !== owner) return false
if (
slot.readers.size > 0 &&
[...slot.readers].some((sid) => sid !== owner)
) {
return false
}
slot.readers.clear()
slot.writer = owner
return true
}
if (slot.writer && slot.writer !== owner) return false
slot.readers.add(owner)
return true
}
/**
* @param {Record<string, unknown>} c
* @param {string} lockPath
* @param {{ resolve: (v: unknown) => void, timer: ReturnType<typeof setTimeout> | null, owner: string, wantWrite: boolean }} entry
*/
export function bareOsRemoveFcntlWaiter(c, lockPath, entry) {
const m = /** @type {Record<string, unknown>} */ (c)
const qm = m.bareOsFcntlLockWaitQueues
if (!qm || typeof qm !== 'object') return
const q = /** @type {unknown[]} */ (qm[lockPath])
if (!Array.isArray(q)) return
const i = q.indexOf(entry)
if (i >= 0) q.splice(i, 1)
if (q.length === 0) delete qm[lockPath]
}
/**
* @param {Record<string, unknown>} c
* @param {string} lockPath
*/
export function bareOsDrainFcntlLockWaiters(c, lockPath) {
const locks = /** @type {Record<string, { readers: Set<string>; writer: string | null }>} */ (
c.bareOsCooperativeLocks
)
const slot = locks?.[lockPath]
if (!slot) return
const m = /** @type {Record<string, unknown>} */ (c)
const qm = m.bareOsFcntlLockWaitQueues
const q = qm?.[lockPath]
if (!Array.isArray(q) || q.length === 0) return
while (q.length > 0) {
const w = /** @type {{ resolve: (v: unknown) => void, timer: ReturnType<typeof setTimeout> | null, owner: string, wantWrite: boolean }} */ (
q[0]
)
if (!bareOsTryAcquireCooperativeLock(slot, w.owner, w.wantWrite)) break
q.shift()
if (w.timer) clearTimeout(w.timer)
w.resolve({
ok: true,
op: 'fcntl',
cmd: 'F_SETLKW',
path: lockPath,
cooperative: true,
locked: w.wantWrite ? 'write' : 'read',
blockedWait: true
})
}
if (q.length === 0 && qm && typeof qm === 'object') delete qm[lockPath]
}