!standard D.16.1(0) 11-06-06 AI05-0167-1/12 !standard C.3.2(2) !standard C.3.2(10) !standard C.3.2(22/1) !standard J.15.10(0) !class Amendment 09-10-22 !status Amendment 2012 11-03-15 !status ARG Approved 8-0-0 11-03-17 !status ARG Approved 7-0-1 11-02-19 !status work item 09-10-22 !status received 09-10-22 !priority Medium !difficulty Medium !subject Managing affinities for programs executing on multiprocessors !summary Facilities are provided to allow a multiprocessor platform to be partitioned into a number of non-overlapping dispatching domains (DDs). Every task is scheduled within a DD. A task may also be assigned to execute on just one CPU from within its DD. !problem An increasing number of embedded applications are now executed on multiprocessor and multicore platforms. For non-real-time programs it is usually acceptable for the mapping of tasks to CPUs to be implementation defined and hidden from the program. For real-time programs it may not be acceptable for the mapping of tasks to CPUs to be hidden from the program. This mapping is often known as the "affinity" of the task. The control of affinities is as important as the control of priorities. The ability to control the affinity of a task is needed in Ada. !proposal The following collection of additions to the language are concerned with supporting the execution of multi-tasking Ada programs on SMPs - identical multiprocessors. The following issues are addressed - representing CPUs (now covered in AI05-171) - controlling task affinities - identifying interrupt affinities - Implementation advice and documentation requirements The following package (and pragma CPU) is defined in AI05-171: package System.Multiprocessors is pragma Preelaborate(Multiprocessors); type CPU_Range is range 0 .. ; Not_A_Specific_CPU : constant CPU_Range := 0; subtype CPU is CPU_Range range 1 .. CPU_Range'Last; function Number_Of_CPUs return CPU; end System.Multiprocessors; The details of the proposal are contained in !wording. The following points should be emphasized. All dispatching domains have the same range of priorities System.Any_Priority. There is a default dispatching domain that initially contains all the processors and on which the environment task executes. If no tasks are explicitly assigned to other domains, then all tasks will execute on this default domain. A task executing in the default domain can be assigned to another dispatching domain. By default, a task will execute in the dispatching domain of its activating task. For protected objects there is no need for affinities; it is the tasks that have domains and possibly an assigned CPU. PO code will run on the task's CPU. There is however a need to know on what CPU interrupt code will execute; this will allow an associated task to be assigned the same CPU. !wording Add a new clause: D.16.1 Multiprocessor Dispatching Domains This clause allows implementations on multiprocessor platforms to be partitioned into distinct dispatching domains during program startup. Static Semantics The following language-defined library package exists: with Ada.Real_Time; package System.Multiprocessors.Dispatching_Domains is pragma Preelaborate(Dispatching_Domains); Dispatching_Domain_Error : exception; type Dispatching_Domain (<>) is limited private; System_Dispatching_Domain : constant Dispatching_Domain; function Create(First, Last : CPU) return Dispatching_Domain; function Get_First_CPU(Domain : Dispatching_Domain) return CPU; function Get_Last_CPU(Domain : Dispatching_Domain) return CPU; function Get_Dispatching_Domain(T : Task_Id := Current_Task) return Dispatching_Domain; procedure Assign_Task(Domain : in out Dispatching_Domain; CPU : in CPU_Range := Not_A_Specific_CPU; T : in Task_Id := Current_Task); procedure Set_CPU(CPU : in CPU_Range; T : in Task_Id := Current_Task); function Get_CPU(T : in Task_Id := Current_Task) return CPU_Range; procedure Delay_Until_And_Set_CPU( Delay_Until_Time : in Ada.Real_Time.Time; CPU : in CPU_Range); private ... -- not specified by the language end System.Multiprocessors.Dispatching_Domains; The type Dispatching_Domain represents a series of processors on which a task may execute. Each processor is contained within exactly one Dispatching_Domain. System_Dispatching_Domain contains the processor or processors on which the environment task executes. At program start-up all processors are contained within System_Dispatching_Domain. For a task type (including the anonymous type of a single_task_declaration), the following language-defined representation aspect may be specified: Dispatching_Domain The value of aspect Dispatching_Domain is an expression, which shall be of type Dispatching_Domains.Dispatching_Domain. This aspect is the domain to which the task (or all objects of the task type) are assigned. Legality Rules The Dispatching_Domain aspect shall not be specified for a task interface. Dynamic Semantics The expression specifed for the Dispatching_Domain aspect of a task is evaluated for each task object (see 9.1). The Dispatching_Domain value is then associated with the task object whose task declaration specifies the aspect. If a task is not explicitly assigned to any domain, it is assigned to that of the activating task. A task always executes on some CPU in its domain. If both Dispatching_Domain and CPU are specified for a task, and the CPU value is not contained within the range of processors for the domain (and is not Not_A_Specific_CPU), the activation of the task is defined to have failed, and it becomes a completed task (see 9.2). The function Create creates and returns a Dispatching_Domain containing all the processors in the range First .. Last. These processors are removed from System_Dispatching_Domain. A call of Create will raise Dispatching_Domain_Error if any designated processor is not currently in System_Dispatching_Domain, or if the system cannot support a distinct domain over the processors identified, or if a processor has a task assigned to it, or if the allocation would leave System_Dispatching_Domain empty. A call of Create will raise Dispatching_Domain_Error if the calling task is not the environment task, or if Create is called after the call to the main subprogram. The function Get_First_CPU returns the first CPU in Domain; Get_Last_CPU returns the last one. The function Get_Dispatching_Domain returns the Dispatching_Domain on which the task is assigned. A call of the procedure Assign_Task assigns task T to the CPU within Dispatching_Domain Domain. Task T can now execute only on CPU unless CPU designates Not_A_Specific_CPU, in which case it can execute on any processor within Domain. The exception Dispatching_Domain_Error is propagated if T is already assigned to a Dispatching_Domain other than System_Dispatching_Domain, or if CPU is not one of the processors of Domain (and is not Not_A_Specific_CPU). A call of Assign_Task is a task dispatching point for task T. If T is the Current_Task the effect is immediate, otherwise the effect is as soon as practical. Assigning a task to System_Dispatching_Domain that is already assigned to that domain has no effect. A call of procedure Set_CPU assigns task T to the CPU. Task T can now execute only on CPU, unless CPU designates Not_A_Specific_CPU, in which case it can execute on any processor within its Dispatching_Domain. The exception Dispatching_Domain_Error is propagated if CPU is not one of the processors of the Dispatching_Domain on which T is assigned (and is not Not_A_Specific_CPU). A call of Set_CPU is a task dispatching point for task T. If T is the Current_Task the effect is immediate, otherwise the effect is as soon as practical. The function Get_CPU returns the processor assigned to task T, or Not_A_Specific_CPU if the task is not assigned to a processor. A call of Delay_Until_And_Set_CPU delays the calling task for the designated time and then assigns the task to the specified processor when the delay expires. The exception Dispatching_Domain_Error is propagated if P is not one of the processors of the calling task's Dispatching_Domain (and is not Not_A_Specific_CPU). Implementation Requirements The implementation shall perform the operations Assign_Task, Set_CPU, Get_CPU and Delay_Until_And_Set_CPU atomically with respect to any of these operations on the same dispatching_domain, processor or task. Implementation Advice Each dispatching domain should have separate and disjoint ready queues. Documentation Requirement The implementation shall document the processor(s) on which the clock interrupt is handled and hence where delay queue and ready queue manipulations occur. For any Interrupt_Id whose handler can execute on more than one processor the implementation shall also document this set of processors. Implementation Permissions An implementation may limit the number of dispatching domains that can be created and raise Dispatching_Domain_Error if an attempt is made to exceed this number. -- Add to Ada.Interrupts (C.3.2): with System.Multiprocessors; function Get_CPU(Interrupt: Interrupt_Id) return System.Multiprocessors.CPU_Range; The function Get_CPU returns the processor on which the handler for Interrupt is executed. If the handler can execute on more than one processor the value System.Multiprocessors.Not_A_Specific_CPU is returned. Add to Annex J.15: J.15.xx pragma Dispatching_Domain AARM Discussion: This pragma is born obsolescent; it is defined to provide consistency with existing real-time pragmas. Syntax The form of a pragma Dispatching_Domain as follows: pragma Dispatching_Domain(expression); Name Resolution Rules The expected type for the expression is System.Multiprocessors.Dispatching_Domains.Dispatching_Domain. Legality Rules A Dispatching_Domain pragma is allowed only immediately within a task_definition. Static Semantics Pragma Dispatching_Domain specifies that the Dispatching_Domain aspect (see D.16.1) of the containing task has the value given by expression. !discussion An increasing number of embedded applications are now executed on multiprocessor and multicore platforms. For non-real-time programs it is usually acceptable for the mapping of tasks to CPUs to be implementation defined and hidden from the program. For real-time programs this is not the case. The control of affinities is as important as the control of priorities. In the literature on multiprocessor scheduling there are two main approaches to affinity: global scheduling where the tasks can run on any CPU (and potentially migrate at runtime); and partitioned scheduling where tasks are anchored to a single CPU. From these schemes, two further variants are commonly discussed: for global scheduling tasks are restricted to a subset of the available CPUs, and for partitioned scheduling the program can explicitly change a task's affinity and hence cause it to be moved at run-time. Restricting the set of CPUs on which a task can be globally scheduled supports scalability - as platforms move to contain hundreds of CPUs, the overheads of allowing full task migration become excessive and outweighs any advantage that might accrue from global scheduling. Controlled changing of a task's affinity has been shown to lead to improved schedulability for certain types of application. These four schemes can be used with any form of dispatching, for example fixed priority or EDF. For multiprocessors, EDF is no longer optimal and is not always better than fixed priority. Also global scheduling is usually better than partitioning, but not always. New dispatching algorithms will be defined in the future (it is an active research area), the provisions defined above will allow many of these algorithms to be programmed using the controls provided. However, a fully flexible model with, for example, overlapping dispatching domains, is not supported by the workshop (IRTAW). It was felt better to remove a constraint later rather than attempt to add one. Protected objects require a real lock on a multiprocessor platform unless all user tasks are assigned the same CPU. Spin locking (where tasks spin at their current active priority) is an adequate scheme. Programmer control over ceilings allows protocols such as non-preemptive execution of 'shared' POs to be programmed. No further language provision is required. The provisions outlined in this AI formed the main focus of the 14th IRTAW. They are the result of considerable discussion and evaluation. The starting point were a number of papers at the workshop, including: Supporting Execution on Multiprocessor Platforms, by Burns and Wellings; Providing Additional Real-Time Capability and Flexibility for Ada 2005, by Rod White; Towards a Ravenscar Extension for Multiprocessor Systems, by Ruiz; and Realtime Paradigms Needed Post Ada 2005, by Michell et al. There were also relevant papers and discussions at the previous workshop. The notion of a dispatching domain has some similarities to the current Ada notion of a partition. However the workshop felt that the two notions were not identical and to use partitions for dispatching domains would not be effective. Partitions are more likely to have a role with non SMP (i.e. CC-NUMA) architectures. The definition of DDs is such that a simple system with just one DD will not need to consider these domains. Moreover, if global dispatching using fixed priorities is adequate then the program can be silent on all affinity issues. One possible extension, not covered in this AI, is to allow each DD to have different dispatching policies. This was deemed to be too adventurous for the current set of changes. However, a possible package for this was discussed: The following would allow dispatching (scheduling) policies to be defined. with System; use System; package Ada.Dispatching is Dispatching_Policy_Error : exception; type Dispatching_Policy is private; type Policy is (Priority_Specific_Dispatching, Non_Preemptive_FIFO_Within_Priorities, FIFO_Within_Priorities, Round_Robin_Within_Priorities, EDF_ACross_Priorities, Implementation_Specific); subtype Priority_Specific is Policy range FIFO_Within_Priorities .. EDF_ACross_Priorities; procedure Set_Policy(DP : in out Dispatching_Policy; P : Policy); procedure Set_Priority_Specific_Policy( DP : in out Dispatching_Policy; P : Priority_Specific; Low : Priority; High : Priority); -- raises Dispatching_Policy_Error if -- DP has not been set to Priority_Specific_Dispatching, or -- High is not greater than Low, or -- any priority from Low to High has already been set private -- not defined by language end Ada.Dispatching; A series of calls of the final procedure allows the program to construct the required priority-specific allocations. Note this is a non-extendible definition of dispatching policies. Although a child package could be used to provide this extension. If this package existed then when a DD was defined it would also define its disptching policy. The following is an earlier version of the package that supports the creation of dispatching domains (DDs). One DD is defined to be the 'System' DD; the environment task and any derived from that task are allocated to the 'System' DD. The collection of CPUs, represented by an integer ordering 1 .. Number_Of_CPUs, is partitioned into a finite set of non-overlapping DDs. When a DD is defined it is given a dispatching (scheduling). Tasks can be allocated to a DD and be globally scheduled within that DD. Alternatively they can be allocated to a DD and assigned to a specific CPU within that DD. Tasks cannot be allocated to more than one DD, or assigned to more than one CPU. Task cannot move between DD, but can move between CPUs within the same DD. with Ada.Real_Time; package System.Multiprocessors.Dispatching_Domains is Dispatching_Domain_Error : exception; type Dispatching_Domain is private; System_Dispatching_Domain : Dispatching_Domain; function Create(First,Last : CPU) return Dispatching_Domain; -- checks to see if the processors First, First+1, ..., Last -- are in the system dispatching domain. -- if so, remove them from system scheduling domain and add to the new domain, -- set the scheduling policy for the domain -- raise Dispatching_Domain_Error -- if the system cannot support global scheduling -- over the processors identified, or -- if processors are not in system dispatching domain, or -- if a processor has a task fixed to it, or -- if the allocation would leave the system dispatching domain -- empty, or -- if Dispatching_Domain_Policy has not been set. function Get_First_CPU(DD : Dispatching_Domain) return CPU; function Get_Last_CPU(DD : Dispatching_Domain) return CPU; -- both raise Dispatching_Domain_Error if domain not created function Get_Dispatching_Domain(T : Task_Id := Current_Task) return Dispatching_Domain; procedure Assign_Task(DD : in out Dispatching_Domain; T : in Task_Id := Current_Task); -- raises Dispatching_Domain_Error if T is already assigned -- to a dispatching domain procedure Assign_Task(DD : in out Dispatching_Domain; P : in CPU; T : in Task_Id := Current_Task); -- raises Dispatching_Domain_Error if P not in DD or if -- T is already assigned procedure Set_CPU(P : in CPU_Range; T : in Task_Id := Current_Task); -- raises Dispatching_Domain_Error if P not in current DD for T procedure Free_CPU(T : in Task_Id := Current_Task); function Get_CPU(T : in Task_Id := Current_Task) return CPU_Range; -- returns 0 if T is not set to a specific CPU procedure Delay_Until_And_Set_CPU( Delay_Until_Time : in Ada.Real_Time.Time; P : in CPU); -- raises Dispatching_Domain_Error if P not in -- current DD for calling task private -- not defined by the language end System.Multiprocessors.Dispatching_Domains; The required behaviour of each subprogram is as follows: Create -- Creates a dispatching domain. The identified CPUs are moved from the `System' dispatching domain to this new domain. A CPU cannot be moved if it has a task assigned to it. The `System' dispatching domain must not be emptied of CPUs as it always contains the environment task. Get_First_CPU -- returns the number of the first CPU in the domain. Get_Last_CPU -- returns the number of the last CPU in the domain. Get_Dispatching_Domain -- as the names imply. Assign_Task -- There are two Assign_Task procedures. One allocates the task just to a dispatching domain (for global scheduling within that domain) the other allocates it to a dispatching domain and assigns a specific CPU within that dispatching domain (for partitioned scheduling). Set_CPU -- sets the task to a specified CPU. The task will now only execute on that CPU. Free_CPU -- removes the CPU specific assignment. The task can now execute on any CPU within its dispatching domain. Get_CPU -- returns the CPU on which the designated task is runnable. (if assigned, Not_A_Specific_CPU otherwise). Delay_Until_And_Set_CPU -- delays a task and then sets the task to the specified CPU when the delay expires. This is needed for some scheduling schemes. In addition to these two packages there is a new aspect Dispatching_Domain, required to control the affinity of tasks. !example ** TBD ** !corrigendum C.3.2(2) @drepl @xcode<@b System; @b Ada.Interrupts @b @b Interrupt_Id @b @ft<@i>; @b Parameterless_Handler @b @b;> @dby @xcode<@b System; @b System.Multiprocessors; @b Ada.Interrupts @b @b Interrupt_Id @b @ft<@i>; @b Parameterless_Handler @b @b;> !corrigendum C.3.2(10) @dinsa @xcode< @b Reference (Interrupt : Interrupt_Id) @b System.Address;> @dinst @xcode< @b Get_CPU (Interrupt : Interrupt_Id) @b System.Multiprocessors.CPU_Range;> !corrigendum C.3.2(22/1) @dinsa The Reference function returns a value of type System.Address that can be used to attach a task entry via an address clause (see J.7.1) to the interrupt specified by Interrupt. This function raises Program_Error if attaching task entries to interrupts (or to this particular interrupt) is not supported. @dinst The function Get_CPU returns the processor on which the handler for Interrupt is executed. If the handler can execute on more than one processor the value System.Multiprocessors.Not_A_Specific_CPU is returned. !corrigendum D.16.1(0) @dinsc This clause allows implementations on multiprocessor platforms to be partitioned into distinct dispatching domains during program startup. @s8<@i> The following language-defined library package exists: @xcode<@b Ada.Real_Time; @b System.Multiprocessors.Dispatching_Domains @b @b Preelaborate(Dispatching_Domains); Dispatching_Domain_Error : @b; @b Dispatching_Domain (<@>) @b; System_Dispatching_Domain : @b Dispatching_Domain; @b Create (First, Last : CPU) @b Dispatching_Domain; @b Get_First_CPU (Domain : Dispatching_Domain) @b CPU; @b Get_Last_CPU (Domain : Dispatching_Domain) @b CPU; @b Get_Dispatching_Domain (T : Task_Id := Current_Task) @b Dispatching_Domain; @b Assign_Task (Domain : @b Dispatching_Domain; CPU : @b CPU_Range := Not_A_Specific_CPU; T : @b Task_Id := Current_Task); @b Set_CPU (CPU : @b CPU_Range; T : @b Task_Id := Current_Task); @b Get_CPU (T : Task_Id := Current_Task) @b CPU_Range; @b Delay_Until_And_Set_CPU ( Delay_Until_Time : @b Ada.Real_Time.Time; CPU : @b CPU_Range); @b ... -- @ft<@i> @b System.Multiprocessors.Dispatching_Domains;> The type Dispatching_Domain represents a series of processors on which a task may execute. Each processor is contained within exactly one Dispatching_Domain. System_Dispatching_Domain contains the processor or processors on which the environment task executes. At program start-up all processors are contained within System_Dispatching_Domain. For a task type (including the anonymous type of a @fa), the following language-defined representation aspect may be specified: @xhang<@xterm The value of aspect Dispatching_Domain is an @fa, which shall be of type Dispatching_Domains.Dispatching_Domain. This aspect is the domain to which the task (or all objects of the task type) are assigned.> @s8<@i> The Dispatching_Domain aspect shall not be specified for a task interface. @s8<@i> The expression specified for the Dispatching_Domain aspect of a task is evaluated for each task object (see 9.1). The Dispatching_Domain value is then associated with the task object whose task declaration specifies the aspect. If a task is not explicitly assigned to any domain, it is assigned to that of the activating task. A task always executes on some CPU in its domain. If both Dispatching_Domain and CPU are specified for a task, and the CPU value is not contained within the range of processors for the domain (and is not Not_A_Specific_CPU), the activation of the task is defined to have failed, and it becomes a completed task (see 9.2). The function Create creates and returns a Dispatching_Domain containing all the processors in the range First .. Last. These processors are removed from System_Dispatching_Domain. A call of Create will raise Dispatching_Domain_Error if any designated processor is not currently in System_Dispatching_Domain, or if the system cannot support a distinct domain over the processors identified, or if a processor has a task assigned to it, or if the allocation would leave System_Dispatching_Domain empty. A call of Create will raise Dispatching_Domain_Error if the calling task is not the environment task, or if Create is called after the call to the main subprogram. The function Get_First_CPU returns the first CPU in Domain; Get_Last_CPU returns the last one. The function Get_Dispatching_Domain returns the Dispatching_Domain on which the task is assigned. A call of the procedure Assign_Task assigns task T to the CPU within Dispatching_Domain Domain. Task T can now execute only on CPU unless CPU designates Not_A_Specific_CPU, in which case it can execute on any processor within Domain. The exception Dispatching_Domain_Error is propagated if T is already assigned to a Dispatching_Domain other than System_Dispatching_Domain, or if CPU is not one of the processors of Domain (and is not Not_A_Specific_CPU). A call of Assign_Task is a task dispatching point for task T. If T is the Current_Task the effect is immediate, otherwise the effect is as soon as practical. Assigning a task to System_Dispatching_Domain that is already assigned to that domain has no effect. A call of procedure Set_CPU assigns task T to the CPU. Task T can now execute only on CPU, unless CPU designates Not_A_Specific_CPU, in which case it can execute on any processor within its Dispatching_Domain. The exception Dispatching_Domain_Error is propagated if CPU is not one of the processors of the Dispatching_Domain on which T is assigned (and is not Not_A_Specific_CPU). A call of Set_CPU is a task dispatching point for task T. If T is the Current_Task the effect is immediate, otherwise the effect is as soon as practical. The function Get_CPU returns the processor assigned to task T, or Not_A_Specific_CPU if the task is not assigned to a processor. A call of Delay_Until_And_Set_CPU delays the calling task for the designated time and then assigns the task to the specified processor when the delay expires. The exception Dispatching_Domain_Error is propagated if P is not one of the processors of the calling task's Dispatching_Domain (and is not Not_A_Specific_CPU). @s8<@i> The implementation shall perform the operations Assign_Task, Set_CPU, Get_CPU and Delay_Until_And_Set_CPU atomically with respect to any of these operations on the same dispatching_domain, processor or task. @s8<@i> Each dispatching domain should have separate and disjoint ready queues. @s8<@i> The implementation shall document the processor(s) on which the clock interrupt is handled and hence where delay queue and ready queue manipulations occur. For any Interrupt_Id whose handler can execute on more than one processor the implementation shall also document this set of processors. @s8<@i> An implementation may limit the number of dispatching domains that can be created and raise Dispatching_Domain_Error if an attempt is made to exceed this number. !corrigendum J.15.10(0) @dinsc @s8<@i> The form of a @fa Dispatching_Domain is as follows: @xcode<@ft<@b Dispatching_Domain (@fa);>> @s8<@i> The expected type for the @fa is System.Multiprocessors.Dispatching_Domains.Dispatching_Domain. @s8<@i> A Dispatching_Domain pragma is allowed only immediately within a @fa. @s8<@i> For an implementation that supports Annex D, a pragma Dispatching_Domain specifies the value of the Dispatching_Domain aspect (see D.16.1). The @fa is associated with the aspect for the task type or @fa that contains the pragma. !ACATS test Add an ACATS C-Test of this package. !appendix From: Bob Duff Sent: Sunday, January 23, 2011 5:30 PM New version of AI05-0167-1, Managing affinities for programs executing on multiprocessors. [Editor's note: This is version /05 of this AI.] I basically did what the minutes say, but: (Alan, and everybody, see "???" below.) Where does the name "system DD" come from? System_Dispatching_Domain : constant Dispatching_Domain; Seems like "default" would be a better name for it, and seems like "dispatching" is unnecessary noise. So how about: Default_Domain : constant Dispatching_Domain; ? > Tucker suggests rewording: > > ?The exception Dispatching_Domain_Error is propagated if T is already > assigned to a Dispatching_Domain other than System_Dispatching_Domain, > or if P is not one of the processors of DD (and is not > Not_A_Specific_CPU); assigning a task to the System_Dispatching_Domain > has no effect.? And drop the last sentence. I don't see how that makes sense. If a task is already assigned to some non-system domain, then attempting to assign it back to the system domain should be an error, shouldn't it? Dynamic Semantics A pragma Dispatching_Domain assigns the task to the specified domain. During activation, a task executes in the domain of the activating task; afterward, it executes in the domain to which it is assigned. If the task is not assigned to any domain, it executes in that of the activating task. ---------------- ???The above matches my understanding of the minutes, but I'm still having trouble with it. Activation is over when a task reaches its "begin" -- do we really want to insist that it move to a different domain, and therefore a different CPU, at that time? Suppose we say: Assign_Task(DD_3, CPU_7, My_Task); And suppose My_Task is then activated by the environment task, which is running in System_Dispatching_Domain, on CPU_2. So during activation, My_Task runs in System_Dispatching_Domain, but it certainly can't run on CPU_7, because that's part of DD_3. But that contradicts the semantics of Assign_Task below. To me it seems much simpler if a task is assigned to a domain once and for all (doesn't switch domains at the "begin"), and always runs on its assigned CPU (before and after "begin"), and that CPU is always part of that domain. (Except the Not_A_Specific_CPU case, of course). We can change CPU affinity, but not the domain, of a task, right? ---------------- If a task contains a CPU pragma and a Dispatching_Domain pragma, and the CPU value is not contained within the range of processors for the Dispatching_Domain value (and is not Not_A_Specific_CPU), the activation of the task is defined to have failed, and it becomes a completed task (see 9.2(1)). The function Create creates and returns a Dispatching_Domain containing all the processors in the range First .. Last. These processors are removed from System_Dispatching_Domain. A call of Create will raise Dispatching_Domain_Error if any designated processor is not currently in System_Dispatching_Domain, or if the system cannot support a distinct domain over the processors identified, or if a processor has a task assigned to it, or if the allocation would leave System_Dispatching_Domain empty. A call of Create will raise Dispatching_Domain_Error if the calling task is not the environment task, or after the call to the main subprogram. ???Is that last sentence what we want? The minutes say "Program_Error", but everything else here raises Dispatching_Domain_Error, so I used that. But more importantly: It's OK to create domains after tasks start running? And it's bad to create domains in the main procedure? **************************************************************** From: Alan Burns Sent: Monday, January 31, 2011 5:38 AM I note in the minutes of the telephone meeting that AI 167 still has a couple of issues open. As I will not be at the next full meeting I thought it would be useful to try and get closure on these by email - but note Bob is now responsible for this AI (not me). The main issue concerns a task (T) that is destine to run in one Dispatching Domain (D1) but whose activating task (A) is running in another domain (D2). Two possibilities - 1) T is activated in D2 and then moves to D1 at 'begin' 2) T is activated and executed on D2 Currently the AI favours 1) on the basis that A is blocked waiting for T to finish activating - this is a dependency between dispatching domains which should be avoided as much as possible. However, as Bob notes in the current version of the AI, it is strange to have T start in one dispatching domain (on some CPU) and then move to another domain (and hence a different CPU) at the point that it moves from activating to executing. I agree with Bob. Although it is useful to eliminate A's dependency on another Dispatching Domain, it is not the only situation in which it occurs (others are rendezvous across domains, waiting for termination). It will be much more efficient to allow T to activate and execute on the same CPU. Also the programmer can program the other situation if needed (by not using the domain pragma, and then calling Assign_Task as the first executable statement). So my view is that we change. The other question concerned the name of the exception to be raised if Create is called 'late' - I have no view on this! - but I'm sure others have!! Perhaps the current wording 'or after the call' is not quite clear? **************************************************************** From: Bob Duff Sent: Monday, January 31, 2011 7:10 AM > I note in the minutes of the telephone meeting that AI 167 still has a > couple of issues open. As I will not be at the next full meeting I > thought it would be useful to try and get closure on these by email - > but note Bob is now responsible for this AI (not me). Thanks for answering my questions, Alan. I'll update the AI. If anybody else wants to weigh in, please speak up. > Two possibilities - > > 1) T is activated in D2 and then moves to D1 at 'begin' > 2) T is activated and executed on D2 Right, but note that we should stick with RM terminology to avoid confusion: activation is part of execution. (I've never understood why activation is special -- that is, why the activator should wait for notification from the activatee(s). Strange.) **************************************************************** From: Alan Burns Sent: Monday, January 31, 2011 7:22 AM ... >> Two possibilities - >> >> 1) T is activated in D2 and then moves to D1 at 'begin' >> 2) T is activated and executed on D2 > Right, but note that we should stick with RM terminology to avoid > confusion: activation is part of execution. Agreed, I was using the terms more informally > (I've never understood why activation is special -- that is, why the > activator should wait for notification from the activatee(s). > Strange.) I always assumed this was to catch a task failing during activation. Any exception raised during activation cannot really be caught by the task itself, so it must be caught by the 'parent'. Hence the 'parent' must wait until all 'child' tasks have got past the difficult age. The alternative would be to allow tasks to fail silently - activator would then not have to wait **************************************************************** From: Tucker Taft Sent: Monday, January 31, 2011 8:27 AM I agree switching CPUs is undesirable, especially having just spent the time to initialize all of the nice local data structures of the task body on one CPU before reaching the "begin." Also, the "Activation_Done" message is a "fire and forget" kind of message. The subtask doesn't have to wait for any kind of acknowledgment from the activator -- it can just keep rolling along. **************************************************************** From: Bob Duff Sent: Monday, January 31, 2011 10:05 AM > I always assumed this was to catch a task failing during activation. Yes, that's probably the reason. But it's based on a broken aspect of the design: that exceptions in task bodies vanish by default. I would have fixed that part of the design, instead. > Any exception raised during activation cannot really be caught by the > task itself, ... Well, it CAN be caught by the task itself: just move that decl part down into a block statement. I'll bet most Ada programmers would make that transformation without even thinking about the weird activation semantics. **************************************************************** From: Randy Brukardt Sent: Sunday, January 30, 2011 11:12 PM I was filing old mail, and noticed an old suggestion that was never addressed. Back in July, Bob made a number of suggestions about AI05-0171-1. One of them was to rename the package to "Processors", since it makes just as much sense when there is only one processor. (At least to query how many processors there are.) Discussion of his other suggestions completely overwhelmed the package name, and no conclusion ever was made. I tend to agree with Bob here, in that "multi" is just noise. It makes the name longer than it needs to be. Any thoughts?? **************************************************************** From: Robert Dewar Sent: Monday, January 31, 2011 1:34 AM I aww insufficient reason to change. **************************************************************** From: John Barnes Sent: Monday, January 31, 2011 3:55 AM My first reaction was that this was a good idea. But having browsed through the draft rat, it doesn't make the program text much shorter. Moreover, the commentary talks about multiprocessors quite a lot and the required functionality arises when there are several processors and was the cause of the introduction of the package. So I vote to leave it as is. Sometimes in English we always add the prefix such as multi. If my computer has several processors then I refer to it as a multiprocessor machine and not a processor machine. However, if I am talking about trains, I refer to a passenger train not a multipassenger train. Is that becuause a train for one passenger would be unusual? Brunel often had a private train, he being the only passenger. Here is a a little story. One night, Brunel galloped into Maidenhead on his way to London. The railway was only open between Paddington and Maidenhead so this would be in about 1838. He demanded a train and one was in steam, so he dashed off into the darkness having ascertained that no other trains were on the rails that night. Meanwhile, Babbage (yes the friend of Ada), arrived at Paddington. He was a senior consultant to Brunel and had free travel rights. He demanded an engine in order to go to Maidenhead. One was available. And the driver remarked that since there was no one about that night it didn't matter which track they used. A little later, both men to their horror saw the light of another train approaching. Luckily they were on different tracks. This made them think about the need for signals. And I suppose if the worst had happened and both had been killed this would not be the ARG. **************************************************************** From: Bob Duff Sent: Monday, January 31, 2011 6:30 AM > Sometimes in English we always add the prefix such as multi. OK, I am gruntled. **************************************************************** From: Tucker Taft Sent: Monday, January 31, 2011 8:20 AM "Processors" is fine with me. **************************************************************** From: Edmond Schonberg Sent: Monday, January 31, 2011 9:25 AM I tend to agree as well. "Processors" is fine. **************************************************************** From: Robert Dewar Sent: Monday, January 31, 2011 9:34 AM The reason I prefer to keep the multi, is that this is all about multi-processing, it is not about more general features of processors such as their endianness, word length etc. So I think a name of processors is misleading. Let's look at the features: > package System.Multiprocessors is > pragma Preelaborate (Multiprocessors); > > type CPU_Range is range 0 .. 2 ** 16 - 1; > > subtype CPU is CPU_Range range 1 .. CPU_Range'Last; > > Not_A_Specific_CPU : constant CPU_Range := 0; > > function Number_Of_CPUs return CPU; > -- Number of available CPUs > > end System.Multiprocessors; All of this is about multiprocessing capability, it has nothing to do with giving specific information about processor characteristics. The child packages about locks are also all about multi-procesasing. Previously, I was sort of neutral on this, I have changed my mind, I think it is a mistake to change the name. **************************************************************** From: Bob Duff Sent: Monday, January 31, 2011 9:58 AM > Previously, I was sort of neutral on this, I have changed my mind, I > think it is a mistake to change the name. I am convinced by Robert's arguments. (Note that I'm the one who originally suggested the name change.) Another (fairly weak) argument: "multiprocessor" has some advertising value these days. **************************************************************** From: Robert Dewar Sent: Monday, January 31, 2011 10:11 AM Another (fairly weak) argument: GNAT has implemented it with the name Multiprocessor, so we would keep that name anyway, and just make the official one a renaming. **************************************************************** From: Robert Dewar Sent: Monday, January 31, 2011 10:12 AM > Another (fairly weak) argument: "multiprocessor" has some advertising > value these days. Actually that's a bit stronger than "fairly weak" for me **************************************************************** From: Randy Brukardt Sent: Monday, January 31, 2011 1:55 PM > The reason I prefer to keep the multi, is that this is all about > multi-processing, it is not about more general features of processors > such as their endianness, word length etc. So I think a name of > processors is misleading. It seems that we have no consensus for a change. (I count 4 in favor and 3 against at this point.) Given that we can argue about naming pretty much forever, in the absence of a consensus, we should simply make no change and close the discussion. I so move. **************************************************************** From: John Barnes Sent: Monday, January 31, 2011 2:41 PM Seconded. **************************************************************** From: Erhard Ploedereder Sent: Monday, January 31, 2011 2:41 PM I second. (And, just in case, count me in favor of multi.) **************************************************************** From: Brad Moore Sent: Monday, January 31, 2011 8:56 PM I originally was going to go with Processors, but Roberts arguments persuaded me as well. ****************************************************************