l0.DependencyControl.Lock¶
Lock ¶
Cooperative, named lock with per-resource granularity. Each distinct (scope, namespace, resource) maps to its own OS lock, so unrelated resources lock independently. A lock is mutually exclusive across every Lock instance -- and, for Global scope, across every process -- that targets the same tuple.
Scope (see Lock.Scope) selects the primitive and reach of exclusion: Process: a named semaphore whose name embeds the pid; only Lua states within this process contend. Global: an OS advisory file lock (FileLock) shared by every process in the session -- use for resources shared between Aegisub instances (e.g. a config file). The kernel releases it if the holder crashes, so it never stays stuck; it cannot, however, be taken from a holder that is alive but hung.
While held, the holder's identity and lease are recorded in a per-resource side file for diagnostics. Long operations should call renew! periodically to extend the recorded lease so waiters don't mistake a busy holder for a crashed one.
Constructor ¶
Creates a lock for the given resource.
| param | type | description |
|---|---|---|
| args | LockArgs |
Instance methods¶
getActiveHolder ¶
Returns the holder currently believed to hold this lock, or nil if it appears free. Reads the side file lock-free, so the result is advisory: a holder whose lease has lapsed (likely crashed) is reported as free, and a brand-new holder may not be visible yet. Reports this instance too when it holds the lock. Requires holder recording.
Returns:
recordtable? — The holder record (holderName, pid, namespace, resource, ...).
lock ¶
Attempts to acquire the lock, waiting up to timeout milliseconds.
| param | type | description |
|---|---|---|
| timeout? | number |
Maximum time to wait in milliseconds (default math.huge). |
| lockWaitInterval? | number |
Poll interval in milliseconds while waiting (default 250). |
Returns:
stateLockState — Held on success, Unavailable on timeout.timePassednumber— Milliseconds spent waiting.
tryLock ¶
Attempts to acquire the lock without waiting.
Returns:
stateLockState — Held if the lock was acquired, Unavailable if it's held elsewhere.timePassednumber— Milliseconds spent waiting (always 0).
release ¶
Releases the lock held by this instance.
Returns:
releasedboolean? — True on success, nil if the lock wasn't held by this instance.statusOrErrLockState|string— Available on success, or an error message when the lock wasn't held.
renew ¶
Refreshes the held lock's lease when it is close to expiring, re-stamping its recorded expiry to @expiresAfter from now. This only affects the metadata on this Lock instance and the side file, so waiters don't mistake a busy holder for a crashed one. The underlying OS lock remains held until explicitly released. To avoid unnecessary writes, the side file is only updated when the remaining lease is approaching expiry.
| param | type | description |
|---|---|---|
| expiryThreshold? | number |
Renew only if the remaining lease is <= this many milliseconds; -1 forces an unconditional refresh. Defaults to the larger of half the lease or the safety margin, capped at the full lease. |
Returns:
renewedboolean? — True if refreshed, false if still fresh, nil if the lock isn't held.errstring? — Set (with nil renewed) only when the lock isn't held.
Class methods¶
guard ¶
Acquires a lock for the given args and runs the provided body function. Releases the lock when the body completes or throws. The held Lock is passed to the body so it can call renew on it if needed.
| param | type | description |
|---|---|---|
| args | GuardArgs | Lock constructor args plus optional timeout/lockWaitInterval for the acquire. |
| body | fun(lock: Lock): ... |
Called with the held Lock; its return values are passed through. |
Returns:
...any— The body's return values on success, or nil + err if the lock couldn't be acquired.
Fields¶
| field | type | description |
|---|---|---|
| state | LockState | Held when this instance holds the lock, otherwise Unknown (a foreign holder's state can't be told without acquiring). Read-only. |
Enums¶
LockState ¶
| member | value | description |
|---|---|---|
| Unknown | -1 |
the state can't be determined without trying to acquire (e.g. a foreign holder) |
| Unavailable | 0 |
the lock is held elsewhere and couldn't be acquired |
| Available | 1 |
the lock is free to acquire |
| Held | 2 |
this instance holds the lock |
LockScope ¶
| member | value | description |
|---|---|---|
| Process | "process" |
only Lua states within this process contend |
| Global | "global" |
every process in the session contends via an advisory file lock |
Types¶
LockArgs ¶
| field | type | description |
|---|---|---|
| namespace? | string |
Logical namespace component of the locked resource (default ""). |
| resource? | string |
Resource component within the namespace (default ""). |
| holderName? | string |
Human-readable holder name recorded for diagnostics (default "unknown"). |
| logger? | Logger | |
| expiresAfter? | number |
Lease duration in seconds before a holder is considered stale (default 300). |
| scope? | LockScope | Scope selecting the primitive and reach of exclusion (default "process"). |
| recordHolder? | boolean |
Write a holder side file while held (default true). |
| overrideExpiry? | boolean |
Judge foreign holders against this instance's expiresAfter rather than their recorded lease (default false). |
GuardArgs ¶
| field | type | description |
|---|---|---|
| timeout? | number |
Acquire timeout in milliseconds (default math.huge). |
| lockWaitInterval? | number |
Poll interval in milliseconds while waiting (default 250). |