[][src]Module sunrise_kernel::sync

Synchronization primitives used by the kernel

In Sunrise kernel we provide different families of locks, that differ on their strategy when the lock cannot be obtained immediately, and how they deal with IRQs when the lock is held.

spin locks

SpinLock, SpinRwLock, and Once are just dumb busy-loop locks. When calling lock, they will check if the lock is available and return, and otherwise busy-loop until it is available.

These are just the types provided by the spin crate, renamed to reduce ambiguities.

Because they are blocking and non-preemptive, they can't be used for long exclusive tasks without badly hurting performance for waiters. However they fit really well for really short tasks, where preempting would cause too much overhead, and because they're so dumb, they can be used pretty much everywhere, especially where preempting is not possible, as in the scheduler itself, or during early boot.

Deadlock avoidance

Those lock are guaranteed to never deadlock, as long you don't:

  1. Preempt while holding the lock. E.g.: On a single core, kernel thread A takes the lock, preempts to thread B, tries to take the lock again: that's a deadlock.
  2. Try to use the lock both in regular context and interrupt context. E.g.: On a single core, kernel thread A takes the lock, is interrupted, IRQ handler tries to take the lock: that's a deadlock.

Note that you can in theory use SpinLocks in interrupt context, as long as you don't try to access it in regular context. This would be useful on multi-core systems to arbitrate access to a resource when two IRQs are run concurrently. But we highly discourage it, as we see no use case for a resource that would be accessed only in interrupt context. So, our implementation panics when locked in interrupt context.

SpinLockIRQ

SpinLockIRQ is a variation of SpinLock, which lifts the restriction on interrupt context access.

It still is basically is busy-loop in its essence, but also disables all interrupts on the current core when the lock is held.

It fits the same use cases as SpinLock, but because it cannot be interrupted while the lock is held, it can be used to access a resource both in regular and interrupt context.

Deadlock avoidance

Similar to SpinLock, this lock is guaranteed to never deadlock, as long you don't:

  1. Preempt while holding the lock. E.g.: On a single core, kernel thread A takes the lock, preempts to thread B, tries to take the lock again: that's a deadlock.

As a interrupt disabler

A side-effect of SpinLockIRQs, is that it disables all IRQs for as long as it is held. They often are used in the kernel for this sole purpose.

If you create a SpinLockIRQ and wrap no type, i.e. SpinLockIRQ<()>, you can control whether interrupts are enabled/disabled simply by locking it and unlocking it.

Mutex

Mutex is a lock that preempts when it cannot be obtained. Those are the locks you are expected to use when you have to do some long exclusive tasks.

However since it uses the scheduler, it cannot be used in early boot.

Deadlock avoidance

Those locks are illegal for interrupt context.

However, for every other use case they a lot less constrained compared to SpinLocks. But since they aren't recursive, you still can't lock one while holding it.

You can preempt while holding such a lock, as long as the scheduler's code doesn't also use it for itself, but this would seem like a bad idea.

Re-exports

pub use self::spin_lock_irq::SpinLockIRQ;
pub use self::spin_lock_irq::SpinLockIRQGuard;
pub use self::spin_lock::SpinLock;
pub use self::mutex::Mutex;
pub use self::mutex::MutexGuard;

Modules

mutex

Preemptive Mutex

spin_lock

Lock that panics when used in a IRQ context

spin_lock_irq

Lock disabling IRQs while held

Structs

Once

A synchronization primitive which can be used to run a one-time global initialization. Unlike its std equivalent, this is generalized so that the closure returns a value and it is stored. Once therefore acts something like a future, too.

SpinLockGuard

A guard to which the protected data can be accessed

SpinRwLock

A reader-writer lock

SpinRwLockReadGuard

A guard from which the protected data can be read

SpinRwLockWriteGuard

A guard to which the protected data can be written

Statics

INTERRUPT_DISARM

Boolean to spin_lock_irq::permanently_disable_interrupts.

Traits

Lock

Abstraction around various kind of locks.