Справочник Ada 2012
9.5.3 Вызовы процедур
Вызов entry_call_statement (вызов процедуры) может встречаться в различных контекстах. Простой вызов процедуры — это самостоятельное оператор, представляющий собой безусловный вызов процедуры объекта-цели или защищенного объекта. Вызовы процедур также могут встречаться в рамках select_statement (см. 9.7).
Синтаксис
Правила разрешения имен
Процедура_имя, указанное в entry_call_statement, должно быть именем процедуры. Правила сопоставления параметров такие же, как при вызове подпрограмм (см. 6.4 и 6.4.1).
Статическая семантика
Процедура_имя оператора entry_call_statement указывает (явно или неявно) целевой объект вызова, процедуру или семейство процедур, а также индекс процедуры, если таковой имеется (см. 9.5).
Динамическая семантика
В определенных обстоятельствах (подробно описанных ниже), процедура задачи или защищенного объекта проверяется на то, открыта она или закрыта:
- Процедура задачи открыта, если задача заблокирована на accept_statement, соответствующей процедуре (см. 9.5.2), или на selective_accept (см. 9.7.1) с открытым accept_alternative, соответствующим процедуре; в противном случае она закрыта.
- Процедура защищенного объекта открыта, если условие условия entry_barrier соответствующего entry_body истинно; в противном случае она закрыта. Если оценка условия генерирует исключение, исключение Program_Error передается всем текущим вызывающим процедурам всех процедур защищенного объекта.
При выполнении оператора entry_call_statement оценка имени и ассоциации параметров производится как при вызове подпрограммы (см. 6.4). Затем вызов процедуры выполняется: при вызове процедуры защищенного объекта запускается новое защищенное действие для объекта (см. 9.5.1). Проверяется, открыта ли названная процедура; если она открыта, вызов процедуры считается выбранным немедленно, и выполнение вызова продолжается следующим образом:
- При вызове открытой процедуры задачи принимающая задача становится готовой и продолжает выполнение соответствующего оператора accept_statement (см. 9.5.2).
- При вызове открытой процедуры защищенного объекта соответствующий entry_body выполняется (см. 9.5.2) как часть защищенного действия.
Если оператор accept_statement или entry_body завершается не с помощью переупорядочивания (см. 9.5.4), возврат выполняется вызывающей стороне (после обработки очередей — см. ниже); при необходимости происходит присвоение формальных параметров фактическим, как при вызове подпрограммы (см. 6.4.1); такие присвоения происходят вне любого защищенного действия.
Если названная процедура закрыта, вызов процедуры добавляется в очередь процедур (в рамках защищенного действия, при вызове защищенной процедуры) и остается в очереди до тех пор, пока не будет выбран или отменен; для каждой процедуры заданной задачи или защищенного объекта (включая каждую процедуру семейства процедур) существует отдельная (логическая) очередь процедур.
Когда выбранный вызов выбирается, он удаляется из своей очереди процедур. Выбор вызова из конкретной очереди процедур называется обработкой очереди процедур. Процедура с очередями вызовов может обрабатываться в следующих обстоятельствах:
- Когда связанная задача достигает соответствующего оператора accept_statement или selective_accept с соответствующей открытой accept_alternative;
- Если после выполнения в рамках защищенного действия для связанного защищенного объекта исключительной защищенной операции объект проверяется и оказывается открытым.
Если существует хотя бы один вызов в очереди, соответствующий открытой процедуре, один такой вызов выбирается в соответствии с действующей политикой очереди процедур (см. ниже), и соответствующий оператор accept_statement или entry_body выполняется, как описано выше, для вызова процедуры, выбранного немедленно.
Политика очереди процедур управляет выбором между вызовами в очереди как для очередей задач, так и для очередей защищенных процедур. По умолчанию политика очереди процедур подразумевает выбор вызовов в очереди процедур в порядке их поступления. Если вызовы из двух или более очередей одновременно подходят для выбора, политика очереди процедур по умолчанию не определяет, какая очередь обрабатывается первой. Другие политики очереди процедур могут быть определены с помощью pragma (см. D.4).
Для защищенного объекта вышеупомянутая обработка очередей процедур продолжается до тех пор, пока не останется открытых процедур с очередями вызовов, после чего защищенное действие завершается.
Для вызова процедуры, добавленного в очередь и не являющегося triggering_statement asynchronous_select (см. 9.7.4), вызывающая задача блокируется до отмены вызова или выбора вызова и завершения соответствующего оператора accept_statement или entry_body без переупорядочивания. Кроме того, вызывающая задача блокируется во время согласования.
Можно попытаться отменить вызов процедуры при прерывании (см. 9.8) и в рамках определенных форм select_statement (см. 9.7.2, 9.7.3 и 9.7.4). Отмена не происходит до тех пор, пока вызов не окажется в очереди процедур и не будет защищен от отмены в рамках переупорядочивания (см. 9.5.4); в такой момент вызов удаляется из очереди процедур и завершается из-за отмены. Отмена вызова процедуры защищенного объекта — это защищенное действие, и как таковое не может произойти, пока происходит любое другое защищенное действие над защищенным объектом. Как и любое защищенное действие, оно включает обработку очередей процедур (в случае, если какой-либо барьер процедуры зависит от атрибута Count).
Вызов процедуры задачи, уже завершившей свое выполнение, вызывает исключение Tasking_Error в момент вызова; аналогично, это исключение возникает в момент вызова, если вызываемая задача завершает свое выполнение или становится ненормальной до принятия вызова или завершения согласования (см. 9.8). Это относится как к простому вызову процедуры, так и к вызову процедуры в рамках select_statement.
Разрешения реализации
Реализация может выполнять последовательность шагов защищенного действия, используя любой поток управления; он не должен быть потоком управления задачи, которая инициировала защищенное действие. Если entry_body завершается без переупорядочивания, соответствующая вызывающая задача может быть подготовлена к выполнению, не дожидаясь завершения всего защищенного действия.
При проверке процедуры защищенного объекта на открытость реализация не обязана повторно оценивать условие соответствующего entry_barrier, если ни одна переменная или атрибут, на которые ссылается условие (непосредственно или косвенно), не была изменена выполнением (или отмененным) вызовом исключительной защищенной операции объекта с момента последней оценки условия.
Реализация может оценивать условия всех entry_barrier заданного защищенного объекта в любое время, когда любая процедура объекта проверяется на открытость.
При попытке отмены вызова входа, реализация не обязана предпринимать попытку с помощью потока управления задачи (или прерывания), инициировавшего отмену; в частности, она может использовать поток управления вызывающего процесса для попытки отмены, даже если это может привести к тому, что вызов входа будет выбран в промежутке.
ПРИМЕЧАНИЯ
28 Если во время выполнения entry_body возникает исключение, оно передается соответствующему вызывающему объекту (см. 11.4).
29 Для вызова защищенного входа проверка, открыт ли вход, выполняется до помещения вызова в очередь и снова после этого, если к атрибуту Count (см. 9.9) входа обращаются в какой-либо барьере входов.
30 Помимо простых вызовов входов, язык допускает временные, условные и асинхронные вызовы входов (см. 9.7.2, 9.7.3 и 9.7.4).
31 Реализация может оценивать условие барьера входов чаще, чем строго необходимо, даже если оценка может иметь побочные эффекты. С другой стороны, реализация не обязана повторно оценивать условие, если ничего из того, к чему оно обращается, не было обновлено промежуточной защищённой операцией над защищённым объектом, даже если условие ссылается на какую-то глобальную переменную, которая могла быть обновлена операцией, выполненной вне защищённой операции.
Примеры
Примеры вызовов входов:
Agent.Shut_Down; -- см. 9.1
Parser.Next_Lexeme(E); -- см. 9.1
Pool(5).Read(Next_Char); -- см. 9.1
Controller.Request(Low)(Some_Item); -- см. 9.1
Flags(3).Seize; -- см. 9.4
Parser.Next_Lexeme(E); -- см. 9.1
Pool(5).Read(Next_Char); -- см. 9.1
Controller.Request(Low)(Some_Item); -- см. 9.1
Flags(3).Seize; -- см. 9.4