netlib.narod.ru | < Назад | Оглавление | Далее > |
Семафор — это способ управления доступом к ресурсу. Обычно принято рассматривать семафор как сигнальный флажок (отсюда его название), но автор считает, что лучше его описывать как ключ. Это не целочисленные ключи, о которых мы говорили ранее, а, в этой аналогии, ключи от входной двери.
В простейшем случае семафор — это единственный ключ, который висит на гвозде рядом с запертой дверью. Чтобы пройти через дверь, нужно снять ключ с гвоздя; вы также обязаны снова повесить ключ на гвоздь, выйдя из комнаты. Если ключа не будет на месте, когда вы подойдете к двери, вам придется ждать до тех пор, пока тот, кто его взял, не повесит его на место, при условии, что вы твердо решили пройти через эту дверь. Иначе, вы можете сразу же уйти, если ключа нет на месте.
Это описание относится к ресурсу, которым может одновременно пользоваться только одна сущность; в том случае, когда имеется только один ключ, семафор называют двоичным. Семафоры для ресурсов, которые могут использоваться одновременно несколькими сущностями, называют счетными. Они действуют по такому же принципу, как описано выше, только на гвозде висят несколько ключей. Если ресурс может поддерживать четырех пользователей одновременно (или если доступно четыре эквивалентных ресурса, что по сути означает одно и то же), то имеется четыре ключа. Это естественное обобщение.
Процессы применяют семафоры для координации своей деятельности. Например, предположим, что вы написали программу и хотите исключить возможность выполнения более одного экземпляра программы на конкретном компьютере одновременно. Хорошим примером является программа воспроизведения звуковых файлов: вряд ли кому-то захочется воспроизводить несколько файлов одновременно, поскольку результатом будет неприятная какофония. В качестве другого примера можно привести сервер X Window. Иногда трудно предотвратить запуск более одного X-сервера на одном и том же компьютере одновременно, поэтому имеет смысл предусмотреть, чтобы X-сервер этого не допускал, по крайней мере, по умолчанию.
Семафоры предоставляют способ решения этой проблемы. Программа воспроизведения звука, или X-сервер, или любой другой процесс может определить семафор, проверять, находится ли он в использовании, и продолжать свою работу, если семафор свободен. Если семафор уже занят, это значит, что работает еще один экземпляр этой программы, и тогда программа должна ожидать освобождения семафора (что можно предусмотреть в программе воспроизведения звука), просто отказаться от дальнейших попыток и выйти (что можно предусмотреть в X-сервере), или продолжить работу и пока заниматься чем-то иным, время от времени повторяя попытку обратиться к семафору. Кстати, такой способ применения семафоров часто называют взаимоисключающим, по очевидным причинам; в исходном коде ядра можно встретить общепринятое сокращение соответствующего английского выражения mutual exclusion — mutex.
Для достижения такого же эффекта, как и при использовании двоичных семафоров, чаще применяются файлы блокировки, по крайней мере, при определенных обстоятельствах. Файлы блокировки несколько проще в использовании и некоторые реализации файлов блокировки могут применяться в сети, а семафоры — не могут. С другой стороны, файлы блокировки не применимы для более общего подхода, выходящего за пределы двоичного случая. Как бы то ни было, файлы блокировки не входят в тематику данной книги.
Программные реализации семафора и очереди сообщений настолько подобны, что нет нужды описывать функции sem_init (строка 20695), findkey (строка 20706), sys_semget (строка 20770), newary (строка 20722) и freeary (строка 20978), поскольку они почти полностью повторяют свои аналоги в реализации очереди сообщений.
16983: Объект struct sem представляет отдельный семафор. Он имеет два члена:
16927: Объект struct semid_ds представляет собой аналог объекта struct msqid_ds: он отслеживает всю информацию об отдельном семафоре и очереди операций, которые должны быть выполнены над ним. Ниже перечислены члены этого объекта, которые имеют интересные отличия от соответствующих членов объекта struct msqid_ds:
16989: Объект struct sem_queue представляет собой узел в очереди ожидающих операций в отдельном объекте struct semid_ds. Он имеет следующие члены:
16939: Объект struct sembuf представляет отдельную операцию, которая должна быть выполнена над семафором. Он имеет следующие члены:
На рис. 9.2 показаны взаимосвязи между этими структурами данных.
Рис. 9.2. Структуры данных для семафоров
17014: Объект struct sem_undo содержит достаточный объем информации для отмены отдельной операции над семафором. Если процесс выполняет операцию над семафором с установленным флажком SEM_UNDO, создается объект struct sem_undo, позволяющий отменить эту операцию. Все операции отмены, регламентируемые списком объектов struct sem_undo процесса, выполняются после выхода процесса. Читатели, знакомые с шаблонами проектирования, могут узнать в этом экземпляр шаблона Command.
Это средство позволяет процессу гарантировать автоматическую очистку ресурсов после себя, независимо от того, как произойдет его выход; таким образом, процесс не сможет случайно оставить другие процессы в состоянии бесконечного ожидания освобождения семафора, которое не сможет никогда произойти. (Может также возникнуть ситуация, что процесс приобретет семафор, а затем войдет в бесконечный цикл, но в задачу ядра не входит защита от такой ситуации; в этом случае реализовано намерение предоставить процессам возможность действовать правильно, а не вынуждать их действовать именно так.) Объект struct sem_undo имеет следующие члены:
21244: Функция sys_semop реализует системный вызов semop. Функция sys_semop не имеет прямого эквивалента в программной реализации очереди сообщений, и является аналогом функции sys_msgsnd, sys_msgrcv, или их обеих, в зависимости от того, под каким углом она рассматривается. Как бы то ни было, ее назначение состоит в выполнении одной или нескольких операций над одним или несколькими семафорами. Она пытается выполнять все операции атомарно (то есть без прерывания). Если она не может выполнить их все, она не будет выполнять ни одной из них.
21254: Во многом аналогично функциям очереди сообщений, по-видимому, блокировка ядра выполняется немного раньше, чем в этом действительно возникает необходимость. Безусловно, блокировку можно было бы отложить примерно до строки 21265.
21255: Проверка допустимости параметров. Отметим, в частности, что значение nsops ограничено SEMOPM, максимальным числом операций над семафорами, которые можно попытаться выполнить за один раз. Это значение установлено равным 32 директивой #define в строке 16970.
21261: Копирует описание затребованных операций из пространства пользователя во временный буфер, sops.
21265: Проверка наличия входа в указанной позиции массива. Можно видеть, что эквивалентом массива msgque в программной реализации очереди сообщений является semary (строка 20688). Отметим также, что индекс массива и порядковый номер упакованы в параметре semid таким же способом, который применялся в программной реализации очереди сообщений. Здесь, безусловно, применяется немного другая константа, SEMMNI, значение которой установлено равным 128 (и случайно совпадает со значением MSGMNI) директивой #define в строке 16967.
21272: Начинается цикл по всем указанным операциям. В нем вначале выполняется проверка того, не находится ли номер семафора, заданный в этой операции, вне диапазона, и если это так, он отбрасывается. Любопытно, что при неудачном завершении здесь возвращается ошибка EFBIG (которая означает, что «файл слишком велик»), а не ошибка EINVAL («недопустимый параметр»). Однако это соответствует документации.
21275: Подсчет числа операций, для которых установлен флажок SEM_UNDO. Однако переменная undos просто применяется в качестве флажка: важно только знать, отличается ли она от 0, поэтому присвоение ей 1 (или любого другого ненулевого значения), если выполнено это условие, будет иметь одинаковый эффект. Тем не менее, версия ядра немного быстрее. А поскольку внешний цикл повторяется не более SEMOPM раз, значения undos не могут наращиваться так много раз, чтобы эта целочисленная переменная переполнилась и снова установилась в 0.
21277: Следующие несколько проверок обновляют два локальных флажка: decrease и alter. Они отслеживают, соответственно, будет ли какая-либо операция в наборе уменьшать значение семафора и будет ли какая-либо операция изменять значение семафора. Флажок alter вычисляется не полностью до выхода из цикла в строке 21282, поскольку внутри цикла он только следит за тем, увеличивает ли какая-либо операция значение семафора; затем это значение объединяется с информацией в флажке decrease для получения сведений о том, будут ли происходить какие-либо изменения.
Отметим, что в этом коде не предпринимается попытка обнаружить, не влекут ли за собой какие-либо сочетания операций их взаимной отмены, например, когда одна операция предусматривает уменьшение значения какого-то семафора на 1, а другая операция предусматривает увеличение его значения на 1. Поэтому, если бы встречались только такие операции, то значения флажков decrease и alter могли бы в определенном смысле вводить в заблуждение. В коде ядра можно предусмотреть попытку оптимизации этого алгоритма (и предусмотреть более сложные версии таких же действий), но это может не оправдать затраты времени и усилий. Приложение, которое настолько примитивно, что способно предусматривать выполнение таких взаимоисключающих операций, получает то, что заслуживает, и не следует наказывать более интеллектуальные приложения за его глупость.
21285: Проверка того, что процесс имеет разрешение на выполнение указанных операций с семафорами. Если переменная alter имеет истинное значение, то процесс изменяет семафоры и поэтому должен иметь разрешение на запись; в ином случае, он только ожидает, пока значения одного или нескольких семафоров не установятся в 0, поэтому он просто нуждается в разрешении на чтение.
21291: Набор операций включает некоторые операции отмены. Если текущий процесс уже имеет набор операций отмены, которые должны быть выполнены над данным набором семафоров во время выхода, то данные из нового набора операций отмены необходимо слить с этими данными. В цикле происходит поиск существующего набора операций отмены, и если он существует, в переменной un устанавливается указатель на этот набор, а если нет, в ней устанавливается значение NULL.
21295: Процесс еще не имеет набора операций отмены для данного набора семафоров, поэтому распределяется новый набор. В соответствии с принятой практикой, которую мы уже рассматривали на примере программной реализации очереди сообщений, пространство для корректировок отмены (массив semadj) распределяется непосредственно за самим объектом struct sem_undo в составе того же распределения памяти. После этого происходит заполнение объекта struct sem_undo.
21311: В рассматриваемом наборе операций нет операций отмены, поэтому переменная un просто устанавливается в NULL.
21313: Вызов функции try_atomic_semop (строка 20838, рассматривается ниже) для осуществления попытки выполнить все операции за один раз. Если существуют какие-либо операции, изменяющие состояние, переменная un отлична от NULL; в случае отказа, она будет использоваться для отмены любых частично выполненных операций перед возвратом из функции.
21315: Функция try_atomic_semop возвращает 0 в случае успеха и отрицательное значение — при возникновении ошибки. В любом из этих случаев управление переходит вперед на строку 21359.
21321: В ином случае, функция try_atomic_semop возвращает положительное значение. Оно указывает, что операции нельзя было выполнить прямо сейчас, но процесс собирается ждать, а затем предпринять еще оцну попытку. Для начала заполняется локальный объект struct sem_queue.
21328: Узлы, представляющие операции, которые изменят значения семафоров, размещены в конце очереди; все узлы, представляющие операции, которые ожидают достижения нуля значениями семафоров, размещаются в начале. Почему так происходит, мы покажем при описании функции update_queue (строка 20900) далее в этой главе.
Отметим, что это равносильно размещению локальной переменной в очереди ждущих операций, что очень необычно; такие структуры данных обычно имеют узлы, распределенные в куче. В данном случае это безопасно, поскольку узел будет удален из очереди перед возвратом из функции; переключение контекстов позаботится об остальном. Иным образом, вначале может потребоваться выйти из процесса и в этом случае очистку выполнит функция sem_exit (строка 21379).
21333: Начало цикла, который повторно пытается выполнить эти операции, и прекращает свою работу, только если были успешно выполнены все затребованные операции или если произошла ошибка.
21336: Переходит в состояние ожидания до тех пор, пока не возникнет прерывание от сигнала или пока появится какая-то причина для выполнения повторной попытки.
21342: Если процесс был активизирован функцией update_queue, поскольку у него теперь есть шанс добиться успеха, он повторяет операции.
21358: Удаляет этот процесс из очереди процессов, ждущих возможности изменить набор семафоров.
21360: Если этот набор операций изменил очередь, он мог создать условия, появления которых ждут какие-то другие процессы. Функция sys_semop вызывает update_queue, чтобы она нашла и активизировала такие процессы.
21013: Функция sys_semctl, которая реализует системный вызов semctl, имеет много общего с функцией sys_msgctl. Поэтому здесь мы опишем только интересные различия, в частности, те команды sys_semctl, которые не имеют аналогов в sys_msgctl.
21093: Команды GETVAL, GETPID, GETNCNT, GETZCNT и SETVAL оперируют с отдельными семафорами, а не с наборами семафоров, поэтому в этих случаях нужно вначале проверить соответствие диапазону предоставленного параметра. Если semnum находится в диапазоне, переменная curr становится указателем на соответствующий семафор.
21115: Почти такой же набор команд — GETVAL, GETPID, GETNCNT и GETZCNT — предусматривает чтение или вычисление одного фрагмента информации о семафоре. Эта работа выполняется здесь. Обратите внимание, что верхние биты члена sempid обнуляются по маске в строке 21116; позже мы покажем, для чего это нужно.
21121: Команда GETALL представляет собой запрос на получение всех значений всех семафоров в этом наборе семафоров. Как и во многих других командах, вся работа по ее выполнению не сосредоточена в одном месте; вскоре мы опишем остальное.
21126: Команда SETVAL устанавливает семафор в заданное значение, безусловно, в заданных пределах. Опять-таки, в данный момент выполняется только часть работы, в основном, проверка диапазона.
21142: Команда SETALL — это обобщение SETVAL; она устанавливает значения всех семафоров в этом наборе. Как и в SETVAL, в данный момент выполняется только работа по настройке, например, проверка диапазона.
21173: Здесь начинается остальная часть программной реализации команды GETALL.
21175: Проверка того, что процесс имеет разрешение на чтение значений семафоров. Эта проверка разрешений дублирует выполняемую в строке 21112.
21177: Копирует значения семафоров в локальный массив sem_io, а затем копирует их оттуда в пространство пользователя.
21183: Остальная часть работы по выполнению команды SETVAL начинается здесь.
21187: Поскольку семафор принимает новое значение, все зарегистрированные корректировки отмены для семафора semnum являются недействительными. В этом цикле выполняется установка их в 0, чтобы они больше не имели силы.
21189: Устанавливает значение семафора в значение, предоставленное вызывающей программой, и вызывает функцию update_queue (строка 20900) для активизации всех процессов, которые ожидают возникших в результате этого условий.
21220: Основная часть программной реализации команды SETALL начинается здесь.
21224: Все значения семафоров установлены в значения, предоставленные вызывающей программой.
21226: Все корректировки отмены, относящиеся ко всем семафорам в наборе, установлены в нуль. Здесь не происходит ничего особенного, если семафор устанавливается в значение, которое он уже имел, и не должно происходить. Если вызывающая программа хочет установить в новое значение все семафоры, кроме одного, она не может имитировать это поведение, устанавливая данный семафор в то значение, которое он уже имел. Вместо этого, она должна использовать команду SETVAL для всех семафоров в наборе, кроме того, который не должен измениться.
21379: Функция sem_exit не имеет аналога в программной реализации очереди сообщений. Она выполняет все операции отмены, установленные процессом для автоматического выполнения во время его выхода. Поэтому она вызывается во время выхода процесса (в строке 23285).
21389: Если член semsleeping процесса отличен от NULL, то является истинным одно из двух следующих утверждений: либо процесс ожидал в одной из очередей sem_queue, либо он был только что удален из очереди, но значение semsleeping еще не было обновлено. В первом случае процесс удаляется из очереди, в которой он ожидал.
21395: Начинается проход по списку объектов struct sem_undo текущего процесса. Каждый из них будет обработан в свою очередь, а их освобождение происходит в части цикла, связанной с обновлением.
21397: Если семафоры, соответствующие этой структуре отмены, были освобождены, цикл просто продолжается. Поле semid объекта struct sem_undo может быть установлено в –1 функцией freeary, которая рассматривается далее в этой главе.
21399: Аналогичным образом, если соответствующий вход semque больше не действителен, цикл продолжается.
21406: Во многом аналогично удалению сообщения из середины очереди сообщений, этот цикл проходит по списку sma объектов struct sem_undo для поиска объекта, предшествующего тому, который должен быть удален. Когда он будет найден, функция sem_exit переходит вперед на метку found в строке 21413.
21411: Если структура отмены не была найдена в списке sma, что-то происходит не так. Функция sem_exit выводит предупреждающее сообщение и останавливает внешний цикл. Эта реакция кажется немного преувеличенной, поскольку могут еще оставаться другие структуры отмены, которые можно было бы обработать и освободить. Ведь, найдя одно гнилое яблоко, мы не выбрасываем весь ящик. Тем не менее, это «невозможный» случай, один из тех, которые (могут быть вызваны только логической ошибкой в ядре. Автор предполагает, что в основе этого поведения лежит принцип, что после обнаружения подобной ошибки нельзя доверять и оставшимся данным.
21414: В списке sma была найдена структура отмены и переменная unp указывает на указатель на ее предшественника. Переменная un удалена из очереди.
21417: Все корректировки семафоров в этой структуре отмены выполнены.
21427: Как всегда, происходит вызов функции update_queue на тот случай, если операции, выполненные этой функцией, создали условия для активизации какого-то ждущего процесса.
21429: Были обработаны все объекты struct sem_undo или в строке 21412 была обнаружена ошибка и выход из цикла произошел преждевременно. Так или иначе, очередь sem_undo текущего процесса устанавливается в NULL и функция выполняет возврат.
20805: Добавление q к очереди sem_pending объекта sma. Это компактная реализация; она обычно выглядит примерно так:
q->prev = sma->last; if (sma->sem_pending) /* He пуст? */ sma->sem_pending_last->next = q; else sma->sem_pending = q; sma->sem_pending_last = q; q->next = NULL;
Истинным преимуществом реализации, применяемой в ядре, является то, что в ней удалось избежать потенциально дорогостоящего ветвления. Эта более эффективная реализация отчасти стало возможной благодаря тому, что переменная sem_pending_last стала указателем на указатель на узел очереди, а не просто указателем на узел очереди.
20812: Вставляет q перед очередью sem_pending объекта sma. Поскольку sem_pending это не указатель на указатель, эта реализация имеет, по существу, такую же форму, как и рассмотренная ранее наивная реализация.
20823: Последней примитивной операцией над очередями struct sem_queue является именно эта, в которой выполняется удаление узла из очереди.
20826: Частично удаляет q из очереди путем изменения указателя next предыдущего узла очереди.
20828: Обновляет также указатель prev следующего узла, если он есть, или sma->sem_pending_last, если это — последний узел в очереди. Обратите внимание, что нет явного кода для удаления единственного узла очереди; вам следует выделить время, чтобы разобраться в том, почему и этот случай работает, если вы еще этого не сделали.
20831: Устанавливает указатель prev удаленного узла в NULL, чтобы код в строках 21350 и 21390 позволял эффективно обнаружить, находится ли все еще в очереди этот узел.
20838: В развернутом комментарии перед этой функцией упоминается, что она проверяет, может ли быть выполнен весь данный набор операций. В этом комментарии забыли отметить, что если все операции можно выполнить, обычно так и происходит.
20846: Начинается цикл по всем переданным операциям с проверкой каждой из них по очереди.
20850: Значение sem_op, равное 0, означает, что вызывающая программа должна ждать, пока значение curr->semval не достигнет 0. Следовательно, если значение curr->semval не равно 0, вызывающая программа должна заблокироваться, а это значит, что эти операции нельзя будет выполнить атомарно, или без прерываний (поскольку, пока этот процесс заблокирован, будет выполняться другая работа).
20853: Идентификатор процесса PID вызывающей программы временно записан в нижние 16 битов объекта curr->sempid; предыдущее значение идентификатор процесса перемещается на это время в верхние 16 битов.
20854: Выполняется корректировка curr->semval в соответствии с запросом, находящемся в sem_op, опять-таки, временно. Проверка sem_op на принадлежность к диапазону не выполняется ни здесь, ни в вызывающих эту операцию программах, но выполняется проверка принадлежности результата операции к диапазону в коде, расположенном непосредственно под этим. Это может иногда приводить к неожиданным последствиям при значениях sem_op, которые либо слишком велики, либо слишком малы, и поэтому вызывают переполнение semval с потерей первых значащих цифр.
20855: Если установлен флажок SEM_UNDO этой операции, указывающий, что операция должна быть автоматически отменена после выхода процесса, то обновляется соответствующая структура undo. Обратите внимание, что это подразумевает, что значение un отлично от NULL; за проверку того, что это действительно так, отвечает вызывающая программа.
20858: Проверка принадлежности к диапазону нового значения semval.
20864: Цикл полностью выполнен, поэтому все операции можно считать успешными. Если вызывающей программе нужно только проверить, будут ли операции успешными, но не нужно их сейчас выполнять, все операции будут немедленно отменены. В ином случае, операции уже выполнены и функция try_atomic_semop переходит к коду, который возвращает результат, свидетельствующий об успешном выполнении.
20874: Метка out_of_range достигается, если операция слишком увеличила бы значение semval. Код под этой меткой просто подготавливает к возврату ошибку ERANGE, а затем переходит вперед к коду отмены.
20878: Метка would_block достигается, если процессу пришлось бы ждать семафор либо потому, что ему пришлось бы ждать достижения семафором значения 0, либо потому, что операция не смогла приобрести семафор немедленно. Если вызывающая программа не намеревается ждать в этом случае, возвращается ошибка EAGAIN. В ином случае, функция возвращает 1 в качестве указания, что вызывающей программе нужно перейти в состояние ожидания.
20884: Код, расположенный за этой меткой undo, отменяет всю работу, которая была выполнена до сих пор, в цикле for, начинающемся в строке 20846.
20888: Очевидная часть этой строки говорит о том, что в ней восстанавливаются нижние 16 битов значения curr->sempid из значения, которое было временно отложено в строке 20853. Неочевидная часть состоит в том, что верхние 16 битов (здесь предполагается наличие 32-разрядной платформы) не обязательно заполняются нулями: в стандарте С преднамеренно оставлено на усмотрение компилятора право выбора — заполнять ли освободившиеся биты нулями или копией знакового бита. На практике компилятор применяет здесь самую быструю команду основополагающего компьютера и это иногда приводит к выбору одного из этих способов, а иногда — другого. (Именно поэтому в стандарте С не отдано предпочтение ни одному из них.) В результате, все верхние биты могут быть установлены в 0 или 1, и поэтому все биты, кроме нижних 16, заполняются по маске нулями в строке 21116.
20900: Функция update_queue вызывается при изменении значения семафора. Она завершает все ждущие операции, которые могут теперь быть выполнены успешно (или окончиться неудачей), и удаляет процесс из очереди ожидания.
20907: Если флажок состояния этого узла был уже поднят в предыдущем вызове функции update_queue, процесс, связанный с этим узлом, еще не имел шанса удалить себя из этой очереди. Функция выполняет возврат, чтобы дать другому процессу шанс выполнить свои ожидающие операции и отключить себя от очереди.
20910: Проверка того, может ли теперь быть выполнен текущий набор ожидающих операций. В качестве последнего параметра передается q->alter, чтобы изменяющиеся операции были автоматически отменены в случае их успешного выполнения. Это связано с тем, что процесс сам будет предпринимать попытки выполнения операций, а они не должны быть выполнены дважды.
20914: В случае ошибки или успеха (а не необходимости продолжать ждать) этот узел удаляется из очереди и активизируется связанный с ним процесс. В ином случае, узел остается в очереди, чтобы стать объектом повторных попыток в какой-то момент в будущем.
20917: Если набор операций включает некоторые изменяющиеся операции, поднимается флажок q->status, чтобы процесс мог определить, что он активизирован в связи с тем, что он теперь может быть успешно выполнен; он попытается выполнить операции и удалить себя из очереди. Проверка флажка выполняется в строке 21342, как было описано выше.
20920: Функция сейчас выполняет возврат с тем, чтобы несколько изменяющихся процессов не пыталось одновременно провести свои изменения, которые могут оказаться несовместимыми. Помните, что неизменяющиеся операции хранятся в начале очереди, а изменяющиеся операции хранятся в конце. В результате, все неизменяющиеся процессы (которые не будут мешать друг другу) активизируются в первую очередь, а после этого активизируется, самое большее, один изменяющийся процесс.
20922: В ином случае, возникла ошибка. Код ошибки сохраняется в переменной q->status и этот узел очереди удаляется.
20938: Функция count_semncnt вызывается из строки 21117 для реализации команды GETNCNT в функции sys_semctl. Ее задача состоит в подсчете числа задач, которые заблокированы и ждут приобретения семафора.
20949: Этот цикл выполняется для каждой ожидающей операции в каждой задаче, ожидающей в очереди ожидания объекта sma. Цикл наращивает значение semncnt каждый раз, когда находит подходящую операцию — ту, которая пытается занять указанный семафор и у которой не установлен флажок IPC_NOWAIT.
20957: Функция count_semzcnt вызывается из строки 21119 для реализации команды GETZCNT в функции sys_semctl. Она почти полностью аналогична функции count_semncnt, за исключением того, что она подсчитывает задачи, ожидающие достижения данным семафором значения 0 (то есть количество задач, ждущих, когда данный семафор станет доступным). Поэтому единственным отличием является строка 20970, где выполняется проверка равенства значения переменной нулю вместо проверки того, что это значение меньше нуля.
netlib.narod.ru | < Назад | Оглавление | Далее > |