Внутреннее устройство ядра Linux 2.4

Атомарные (неделимые) операции


Имеется два типа атомарных операций: операции над битовыми полями и над переменными типа atomic_t. Битовые поля очень удобны, когда необходимо "устанавливать" или "сбрасывать" отдельные биты в больших коллекциях битов (битовых картах), в которых каждый бит идентифицируется некоторым порядковым номером, Они (битовые операции), так же, могут широко использоваться для выполнения простой блокировки, например для предоставлении исключительного доступа к открытому устройству. Пример можно найти в arch/i386/kernel/microcode.c:

/* * Bits in microcode_status. (31 bits of room for future expansion) */ #define MICROCODE_IS_OPEN 0 /* set if device is in use */

static unsigned long microcode_status;

Очищать microcode_status нет необходимости, поскольку BSS обнуляется в Linux явно

/* * We enforce only one user at a time here with open/close. */ static int microcode_open(struct inode *inode, struct file *file) { if (!capable(CAP_SYS_RAWIO)) return -EPERM;

/* one at a time, please */ if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status)) return -EBUSY;

MOD_INC_USE_COUNT; return 0; }

Битовые операции:

  • void set_bit(int nr, volatile void *addr): устанавливает бит nr в карте, адресуемой параметром addr.
  • void clear_bit(int nr, volatile void *addr): сбрасывает бит nr в карте, адресуемой параметром addr.
  • void change_bit(int nr, volatile void *addr): изменяет состояние бита nr

    (если бит установлен, то он сбрасывается, если сброшен - устанавливается) в карте, адресуемой addr.

  • int test_and_set_bit(int nr, volatile void *addr): устанавливается бит nr и возвращается его предыдущее состояние.


  • int test_and_clear_bit(int nr, volatile void *addr): сбрасывается бит nr и возвращается его предыдущее состояние.
  • int test_and_change_bit(int nr, volatile void *addr): изменяется состояние бита nr и возвращается его предыдущее состояние.
  • Эти операции используют макрос LOCK_PREFIX, который для SMP ядра представляет из себя префиксную инструкцию "lock" и пустой для UP ядра (include/asm/bitops.h). Он гарантирует неделимость доступа на мультипроцессорной платформе.


    В некоторых ситуациях требуется выполнение атомарных арифметических операций - сложение, вычитание, инкремент, декремент. Типичный пример - счетчики ссылок. Такого рода действия предоставляются следующими операциями над типом atomic_t:

  • atomic_read(&v): возвращает значение atomic_t переменной v.


  • atomic_set(&v, i): записывает в atomic_t переменную v целое число i.


  • void atomic_add(int i, volatile atomic_t *v): складывает целое i и значение переменной v, результат помещается в переменную.


  • void atomic_sub(int i, volatile atomic_t *v): из переменной v вычитается целое i, результат помещается в переменную.


  • int atomic_sub_and_test(int i, volatile atomic_t *v): из переменной v вычитается целое i; возвращается 1 если новое значение переменной == 0, и 0 - в противном случае.


  • void atomic_inc(volatile atomic_t *v): увеличивает значение переменной на 1.


  • void atomic_dec(volatile atomic_t *v): уменьшает значение переменной на 1.


  • int atomic_dec_and_test(volatile atomic_t *v): уменьшает значение переменной на 1. Возвращает 1, если новое значение переменной == 0, 0 - в противном случае.


  • int atomic_inc_and_test(volatile atomic_t *v): увеличивает значение переменной на 1. Возвращает 1, если новое значение переменной == 0, 0 - в противном случае.


  • int atomic_add_negative(int i, volatile atomic_t *v): к переменной v прибавляется целое i, если результат меньше 0 - возвращается 1. Если результат больше либо равен 0 - возвращается 0. Эта операция используется в реализации семафоров.



  • Содержание раздела