Skip to main content

AppLock

Struct AppLock 

Source
pub struct AppLock { /* private fields */ }
Expand description

An advisory lock on a file, held by the running process for as long as this value lives.

The lock is the operating system’s, not the file’s existence: the kernel releases it when the process ends, so a crash or a power cut never leaves a lock behind. Dropping the value releases it too.

The file itself holds the process id of the holder as text, and that is only ever material for a message to the user: a process id is reused, so nothing may be decided from it. The decision is AppLock::acquire’s answer and nothing else.

let dir = data_dir("qfocus").expect("a home directory");
std::fs::create_dir_all(&dir)?;
match AppLock::acquire(&dir.join("lock"))? {
    Some(_lock) => { /* this instance may write; the lock lives as long as `_lock` */ }
    None => { /* another instance is running */ }
}

Implementations§

Source§

impl AppLock

Source

pub fn acquire(path: &Path) -> Result<Option<Self>>

Takes the lock on path, creating the file when it is not there, or answers None because another process holds it.

The parent directory has to exist. On success the process id of this process is written into the file, for a message that names the holder; see holder_pid.

On Unix systems this is flock(LOCK_EX | LOCK_NB), which the kernel releases when the process dies. Locks of this kind are per open file, not per process, so a second acquire on the same path inside one process answers None as well.

A child process started between the moment the lock is taken and the moment it is released keeps it for a few milliseconds longer: between fork and exec the child holds a copy of every open file, this file among them, and the kernel counts the lock as held until that copy is closed. So a released lock is free in a moment, not in the same instant, and a program that starts children may need to wait briefly before it can take its own lock again.

On every other platform, Windows among them, this framework has no advisory lock yet: acquire returns an error of kind io::ErrorKind::Unsupported and never Ok, so an application is told it has no lock instead of quietly running without one. Windows would need LockFileEx, which is not reachable without unsafe, and this framework forbids unsafe.

§Errors

Returns the I/O error when the file cannot be opened or written, and io::ErrorKind::Unsupported on a platform without an advisory lock. A lock another process holds is Ok(None), not an error.

Trait Implementations§

Source§

impl Debug for AppLock

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.