Ядро Linux в комментариях

       

Try_atomic_semop


В развернутом комментарии перед этой функцией упоминается, что она проверяет, может ли быть выполнен весь данный набор операций. В этом комментарии забыли отметить, что если все операции можно выполнить, обычно так и происходит.

Начинается цикл по всем переданным операциям с проверкой каждой из них по очереди.

Значение sem_op, равное 0, означает, что вызывающая программа должна ждать, пока значение curr->semval не достигнет 0. Следовательно, если значение curr->semval не равно 0, вызывающая программа должна заблокироваться, а это значит, что эти операции нельзя будет выполнить атомарно, или без прерываний (поскольку, пока этот процесс заблокирован, будет выполняться другая работа).

Идентификатор процесса PID вызывающей программы временно записан в нижние 16 битов объекта curr->sempid; предыдущее значение идентификатор процесса перемещается на это время в верхние 16 битов.

Выполняется корректировка curr->semval в соответствии с запросом, находящемся в sem_op, опять-таки, временно. Проверка sem_op на принадлежность к диапазону не выполняется ни здесь, ни в вызывающих эту операцию программах, но выполняется проверка принадлежности результата операции к диапазону в коде, расположенном непосредственно под этим. Это может иногда приводить к неожиданным последствиям при значениях sem_op, которые либо слишком велики, либо слишком малы, и поэтому вызывают переполнение semval с потерей первых значащих цифр.

Если установлен флажок SEM_UNDO этой операции, указывающий, что операция должна быть автоматически отменена после выхода процесса, то обновляется соответствующая структура undo. Обратите внимание, что это подразумевает, что значение un отлично от NULL; за проверку того, что это действительно так, отвечает вызывающая программа.

Проверка принадлежности к диапазону нового значения semval.

Цикл полностью выполнен, поэтому все операции можно считать успешными. Если вызывающей программе нужно только проверить, будут ли операции успешными, но не нужно их сейчас выполнять, все операции будут немедленно отменены. В ином случае, операции уже выполнены и функция try_atomic_semop переходит к коду, который возвращает результат, свидетельствующий об успешном выполнении.


Метка out_of_range достигается, если операция слишком увеличила бы значение semval. Код под этой меткой просто подготавливает к возврату ошибку ERANGE, а затем переходит вперед к коду отмены.

Метка would_block достигается, если процессу пришлось бы ждать семафор либо потому, что ему пришлось бы ждать достижения семафором значения 0, либо потому, что операция не смогла приобрести семафор немедленно. Если вызывающая программа не намеревается ждать в этом случае, возвращается ошибка EAGAIN. В ином случае, функция возвращает 1 в качестве указания, что вызывающей программе нужно перейти в состояние ожидания.

Код, расположенный за этой меткой undo, отменяет всю работу, которая была выполнена до сих пор, в цикле for, начинающемся в строке .

Очевидная часть этой строки говорит о том, что в ней восстанавливаются нижние 16 битов значения curr->sempid из значения, которое было временно отложено в строке . Неочевидная часть состоит в том, что верхние 16 битов (здесь предполагается наличие 32-разрядной платформы) не обязательно заполняются нулями: в стандарте С преднамеренно оставлено на усмотрение компилятора право выбора — заполнять ли освободившиеся биты нулями или копией знакового бита. На практике компилятор применяет здесь самую быструю команду основополагающего компьютера и это иногда приводит к выбору одного из этих способов, а иногда — другого. (Именно поэтому в стандарте С не отдано предпочтение ни одному из них.) В результате, все верхние биты могут быть установлены в 0 или 1, и поэтому все биты, кроме нижних 16, заполняются по маске нулями в строке .


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