Руководство по Ada (Ada 2022)
D.16.1 Домены диспетчеризации многопроцессорных систем
Этот подраздел позволяет реализациям на многопроцессорных платформах разделяться на отдельные домены диспетчеризации во время запуска программы.
Статическая семантика
Существует следующая определяемая языком библиотечная пакет:
with Ada.Real_Time;
with Ada.Task_Identification;
package System.Multiprocessors.Dispatching_Domains
with Nonblocking, Global => in out synchronized is
with Ada.Task_Identification;
package System.Multiprocessors.Dispatching_Domains
with Nonblocking, Global => in out synchronized is
Dispatching_Domain_Error : exception;
type Dispatching_Domain (<>) is limited private;
System_Dispatching_Domain : constant Dispatching_Domain;
function Create (First : CPU; Last : CPU_Range) return Dispatching_Domain;
function Get_First_CPU (Domain : Dispatching_Domain) return CPU;
function Get_Last_CPU (Domain : Dispatching_Domain) return CPU_Range;
type CPU_Set is array(CPU range <>) of Boolean;
function Create (Set : CPU_Set) return Dispatching_Domain;
function Get_CPU_Set (Domain : Dispatching_Domain) return CPU_Set;
function Get_Dispatching_Domain
(T : Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task)
return Dispatching_Domain;
(T : Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task)
return Dispatching_Domain;
procedure Assign_Task
(Domain : in out Dispatching_Domain;
CPU : in CPU_Range := Not_A_Specific_CPU;
T : in Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task);
(Domain : in out Dispatching_Domain;
CPU : in CPU_Range := Not_A_Specific_CPU;
T : in Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task);
procedure Set_CPU
(CPU : in CPU_Range;
T : in Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task);
(CPU : in CPU_Range;
T : in Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task);
function Get_CPU
(T : Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task)
return CPU_Range;
(T : Ada.Task_Identification.Task_Id :=
Ada.Task_Identification.Current_Task)
return CPU_Range;
procedure Delay_Until_And_Set_CPU
(Delay_Until_Time : in Ada.Real_Time.Time; CPU : in CPU_Range);
(Delay_Until_Time : in Ada.Real_Time.Time; CPU : in CPU_Range);
private
... -- не определено языком
end System.Multiprocessors.Dispatching_Domains;
... -- не определено языком
end System.Multiprocessors.Dispatching_Domains;
Домен диспетчеризации представляет собой набор процессоров, на которых может выполняться задача. Каждый процессор содержится ровно в одном домене диспетчеризации. Объект типа Dispatching_Domain идентифицирует домен диспетчеризации. System_Dispatching_Domain идентифицирует домен, содержащий процессор или процессоры, на которых выполняется задача среды. При запуске программы все процессоры содержатся в этом домене.
Для типа задачи (включая анонимный тип single_task_declaration) можно указать следующий аспект представления, определяемый языком:
Dispatching_Domain
Значение аспекта Dispatching_Domain — это выражение, которое должно быть типа Dispatching_Domains.Dispatching_Domain. Этот аспект является доменом, которому назначена задача (или все объекты типа задачи).
Правила легальности
Аспект Dispatching_Domain не должен быть указан для интерфейса задачи.
Динамическая семантика
Выражение, указанное для аспекта Dispatching_Domain типа задачи, вычисляется каждый раз при создании объекта типа задачи (см. 9.1). Если идентифицированный домен диспетчеризации пуст, то генерируется исключение Dispatching_Domain_Error; в противном случае созданной задаче назначается домен, определённый значением выражения.
Если задаче не явно назначен никакой домен, ей назначается домен активирующей задачи. Задача всегда выполняется на каком-либо процессоре в своем домене.
Если для задачи указаны и домен диспетчеризации, и процессор, а значение процессора не содержится в наборе процессоров для данного домена (и не равно Not_A_Specific_CPU), считается, что активация задачи завершилась неудачно, и она становится завершённой задачей (см. 9.2).
Функция Create с параметрами First и Last создает и возвращает домен диспетчеризации, содержащий все процессоры в диапазоне First .. Last. Функция Create с параметром Set создает и возвращает домен диспетчеризации, содержащий процессоры, для которых Set(I) равно True. Эти процессоры удаляются из System_Dispatching_Domain. Вызов Create вызовет Dispatching_Domain_Error, если какой-либо указанный процессор в данный момент не находится в System_Dispatching_Domain, или если система не может поддерживать отдельный домен над идентифицированными процессорами, или если процессору назначена задача, или если выделение приведет к опустошению System_Dispatching_Domain. Вызов Create вызовет Dispatching_Domain_Error, если вызывающая задача не является задачей среды или если Create вызывается после вызова главной подпрограммы.
Функция Get_First_CPU возвращает первый процессор в Domain, или CPU'First, если Domain пуст; Get_Last_CPU возвращает последний процессор в Domain, или CPU_Range'First, если Domain пуст. Функция Get_CPU_Set(D) возвращает массив, нижняя граница которого равна Get_First_CPU(D), верхняя граница — Get_Last_CPU(D), значения в Set равны True для процессоров, находящихся в данном домене.
Функция Get_Dispatching_Domain возвращает домен диспетчеризации, которому назначена задача.
Вызов процедуры Assign_Task назначает задаче T процессор в домене диспетчеризации Domain. Задача T теперь может выполняться только на процессоре CPU, если CPU не обозначает Not_A_Specific_CPU, в этом случае она может выполняться на любом процессоре в домене. Исключение Dispatching_Domain_Error генерируется, если Domain пуст, T уже назначена в другой домен диспетчеризации, кроме System_Dispatching_Domain, или если CPU не является одним из процессоров Domain (и не равно Not_A_Specific_CPU). Вызов Assign_Task — это точка диспетчеризации задачи T, за исключением случаев, когда T находится внутри защищенного действия, в этом случае эффект для задачи T откладывается до следующей точки диспетчеризации задачи. Если T — это Current_Task, эффект немедленный, если T не находится внутри защищенного действия, в противном случае эффект наступает как можно скорее. Назначение задачи, уже назначенной в System_Dispatching_Domain, в этот же домен не оказывает никакого эффекта.
Вызов процедуры Set_CPU назначает задаче T процессор. Задача T теперь может выполняться только на процессоре CPU, если CPU не обозначает Not_A_Specific_CPU, в этом случае она может выполняться на любом процессоре в своём домене диспетчеризации. Исключение Dispatching_Domain_Error генерируется, если CPU не является одним из процессоров домена диспетчеризации, которому назначена T (и не равно Not_A_Specific_CPU). Вызов Set_CPU — это точка диспетчеризации задачи T, за исключением случаев, когда T находится внутри защищенного действия, в этом случае эффект для задачи T откладывается до следующей точки диспетчеризации задачи. Если T — это Current_Task, эффект немедленный, если T не находится внутри защищенного действия, в противном случае эффект наступает как можно скорее.
Функция Get_CPU возвращает процессор, назначенный задаче T, или Not_A_Specific_CPU, если задаче не назначен процессор.
Вызов Delay_Until_And_Set_CPU откладывает вызывающую задачу на указанное время, а затем назначает задачу указанному процессору по истечении задержки. Исключение Dispatching_Domain_Error генерируется, если процессор P не является одним из процессоров домена диспетчеризации вызывающей задачи (и не равен Not_A_Specific_CPU).
Требования к реализации
Реализация должна выполнять операции Assign_Task, Set_CPU, Get_CPU и Delay_Until_And_Set_CPU атомарно относительно любых из этих операций в том же домене диспетчеризации, процессоре или задаче.
Любая задача, принадлежащая системному домену диспетчеризации, может выполняться на любом процессоре в пределах этого домена, если назначение задачи не указано.
Рекомендации по реализации
Каждый домен диспетчеризации должен иметь отдельные и непересекающиеся очереди готовности.
Требования к документации
Реализация должна документировать процессор(ы), на котором обрабатывается прерывание таймера, и, следовательно, где происходят манипуляции с очередью задержек и очередью готовности. Для любого Interrupt_Id, обработчик которого может выполняться на нескольких процессорах, реализация также должна документировать этот набор процессоров.
Разрешения для реализации
Реализация может ограничить количество создаваемых доменов диспетчеризации и вызывать Dispatching_Domain_Error, если будет предпринята попытка превысить это количество.
Реализация может отложить эффект операции Set_CPU или Assign_Task до тех пор, пока указанная задача не покинет текущую параллельную конструкцию.