__CPU_SIMPLE_LOCK(9)

__CPU_SIMPLE_LOCK(9) | Kernel Developer's Manual | __CPU_SIMPLE_LOCK(9)

# NAME

`__cpu_simple_lock` —
simple spin locks

# SYNOPSIS

`#include <sys/lock.h>`

void
`__cpu_simple_lock_init`(__cpu_simple_lock_t *lock);

void
`__cpu_simple_lock`(__cpu_simple_lock_t *lock);

int
`__cpu_simple_lock_try`(__cpu_simple_lock *lock);

void
`__cpu_simple_unlock`(__cpu_simple_lock_t *lock);

int
`__SIMPLELOCK_LOCKED_P`(__cpu_simple_lock *lock);

`/* obsolete and for ABI compat only -- do not use */`

void
`__cpu_simple_lock_set`(__cpu_simple_Lock *lock);

void
`__cpu_simple_lock_clear`(__cpu_simple_lock *lock);

int
`__SIMPLELOCK_UNLOCKED_P`(__cpu_simple_lock *lock);

# DESCRIPTION

The `__cpu_simple_lock` functions provide a simple spin-lock facility for limited purposes that cannot be served by mutex(9), such as inside the implementation of mutex(9) itself on platforms with limited atomic read/modify/write operations.

`__cpu_simple_lock` is very limited:

- `__cpu_simple_lock` provides no debugging or diagnostic support through the `LOCKDEBUG` option.
- `__cpu_simple_lock` does not synchronize between code on a CPU and interrupt handlers running on that CPU — you must use it with spl(9) for any locks that may be taken in interrupt context; failing to do so will likely lead to hard-to-debug deadlock.
- `__cpu_simple_lock` does not block preemption, so a thread holding a lock may be preempted, potentially requiring other callers to spin for long durations until the scheduler runs the holder again.
- `__cpu_simple_lock` does no exponential backoff to reduce memory traffic during contention.

Unless you know what you are doing, you should use mutex(9) instead.

# FUNCTIONS

`__cpu_simple_lock_init`(lock)
  Initialize lock for use with the other `__cpu_simple_lock` functions.

  The caller is responsible for ensuring `__cpu_simple_lock_init`() happens before any use of the other functions. `__cpu_simple_lock_init`() implies no particular memory ordering on its own.

`__cpu_simple_lock`(lock)
  Acquire lock, waiting until it is released if currently held.

  Any memory operations preceding the previous `__cpu_simple_unlock`() call that released the lock happen before any memory operations after the next `__cpu_simple_lock`() call that acquires it.

`__cpu_simple_lock_try`(lock)
  Try to acquire lock, without waiting if it is currently held. Return 1 if successful, 0 if not.

  Any memory operations preceding the previous `__cpu_simple_unlock`() call that released the lock happen before any memory operations after the next successful `__cpu_simple_lock_try`() call that acquires it.

`__cpu_simple_unlock`(lock)
  Release lock.

  Any memory operations preceding `__cpu_simple_unlock`() happen before the next call to `__cpu_simple_lock`(), or the next successful call to `__cpu_simple_lock_try`(), that acquires lock.

`__SIMPLELOCK_LOCKED_P`(lock)
  True if lock is currently locked, by anyone.

  This is normally only used for diagnostic assertions, or for loops around `__cpu_simple_lock_try`() that also have higher-level functions like blocking interrupts and performing exponential backoff.

  No memory ordering is implied.

# OBSOLETE FUNCTIONS

The following functions abuse the __cpu_simple_lock_t type to store a boolean. They are used inside the pthread(3) library, and were included in the library ABI, so they can't be removed without breaking the pthread(3) ABI. Do not use these in new code (except `__SIMPLELOCK_LOCKED_P`()).

`__cpu_simple_lock_set`(lock)
  Set lock to true.
`__cpu_simple_lock_clear`(lock)
  Set lock to false.
`__SIMPLELOCK_LOCKED_P`(lock)
  True iff lock is true.
`__SIMPLELOCK_UNLOCKED_P`(lock)
  True iff lock is false.

# CODE REFERENCES

The `__cpu_simple_lock` functions are implemented in sys/arch/$ARCH/include/lock.h.

A machine-independent implementation, using compiler support for atomic and memory barrier builtins, is available in sys/sys/common_lock.h.

# SEE ALSO

locking(9), mutex(9)

# HISTORY

`__cpu_simple_lock` appeared a long time ago.

February 12, 2022 | NetBSD 10.1